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
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -16,9 +16,9 @@ type
|
||||||
TAnalysisResult* = enum
|
TAnalysisResult* = enum
|
||||||
arNo, arMaybe, arYes
|
arNo, arMaybe, arYes
|
||||||
|
|
||||||
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult
|
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult
|
||||||
|
|
||||||
proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
|
proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
|
||||||
result = arNo
|
result = arNo
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkRecList:
|
of nkRecList:
|
||||||
|
|
@ -39,7 +39,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult =
|
||||||
result = isPartOfAux(n.sym.typ, b, marker)
|
result = isPartOfAux(n.sym.typ, b, marker)
|
||||||
else: internalError(n.info, "isPartOfAux()")
|
else: internalError(n.info, "isPartOfAux()")
|
||||||
|
|
||||||
proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult =
|
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
|
||||||
result = arNo
|
result = arNo
|
||||||
if a == nil or b == nil: return
|
if a == nil or b == nil: return
|
||||||
if containsOrIncl(marker, a.id): return
|
if containsOrIncl(marker, a.id): return
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,7 @@ type
|
||||||
nkConstDef, # a const definition
|
nkConstDef, # a const definition
|
||||||
nkTypeDef, # a type definition
|
nkTypeDef, # a type definition
|
||||||
nkYieldStmt, # the yield statement as a tree
|
nkYieldStmt, # the yield statement as a tree
|
||||||
|
nkDefer, # the 'defer' statement
|
||||||
nkTryStmt, # a try statement
|
nkTryStmt, # a try statement
|
||||||
nkFinally, # a finally section
|
nkFinally, # a finally section
|
||||||
nkRaiseStmt, # a raise statement
|
nkRaiseStmt, # a raise statement
|
||||||
|
|
@ -293,6 +294,7 @@ const
|
||||||
# require RC ops
|
# require RC ops
|
||||||
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
sfCompileToCpp* = sfInfixCall # compile the module as C++ code
|
||||||
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code
|
||||||
|
sfExperimental* = sfOverriden # module uses the .experimental switch
|
||||||
|
|
||||||
const
|
const
|
||||||
# getting ready for the future expr/stmt merge
|
# getting ready for the future expr/stmt merge
|
||||||
|
|
@ -566,8 +568,8 @@ type
|
||||||
mBool, mChar, mString, mCstring,
|
mBool, mChar, mString, mCstring,
|
||||||
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
|
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
|
||||||
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy,
|
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy,
|
||||||
mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor,
|
mIsMainModule, mCompileDate, mCompileTime, mProcCall,
|
||||||
mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, mAppType,
|
mCpuEndian, mHostOS, mHostCPU, mAppType,
|
||||||
mNaN, mInf, mNegInf,
|
mNaN, mInf, mNegInf,
|
||||||
mCompileOption, mCompileOptionArg,
|
mCompileOption, mCompileOptionArg,
|
||||||
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
|
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
|
||||||
|
|
@ -610,7 +612,7 @@ const
|
||||||
# thus cannot be overloaded (also documented in the spec!):
|
# thus cannot be overloaded (also documented in the spec!):
|
||||||
SpecialSemMagics* = {
|
SpecialSemMagics* = {
|
||||||
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
|
||||||
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn}
|
mEcho, mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}
|
||||||
|
|
||||||
type
|
type
|
||||||
PNode* = ref TNode
|
PNode* = ref TNode
|
||||||
|
|
@ -681,7 +683,6 @@ type
|
||||||
heapRoot*: PRope # keeps track of the enclosing heap object that
|
heapRoot*: PRope # keeps track of the enclosing heap object that
|
||||||
# owns this location (required by GC algorithms
|
# owns this location (required by GC algorithms
|
||||||
# employing heap snapshots or sliding views)
|
# employing heap snapshots or sliding views)
|
||||||
a*: int
|
|
||||||
|
|
||||||
# ---------------- end of backend information ------------------------------
|
# ---------------- end of backend information ------------------------------
|
||||||
|
|
||||||
|
|
@ -734,7 +735,7 @@ type
|
||||||
# check for the owner when touching 'usedGenerics'.
|
# check for the owner when touching 'usedGenerics'.
|
||||||
usedGenerics*: seq[PInstantiation]
|
usedGenerics*: seq[PInstantiation]
|
||||||
tab*: TStrTable # interface table for modules
|
tab*: TStrTable # interface table for modules
|
||||||
of skLet, skVar, skField:
|
of skLet, skVar, skField, skForVar:
|
||||||
guard*: PSym
|
guard*: PSym
|
||||||
else: nil
|
else: nil
|
||||||
magic*: TMagic
|
magic*: TMagic
|
||||||
|
|
@ -772,6 +773,7 @@ type
|
||||||
# it won't cause problems
|
# it won't cause problems
|
||||||
|
|
||||||
TTypeSeq* = seq[PType]
|
TTypeSeq* = seq[PType]
|
||||||
|
TLockLevel* = distinct int16
|
||||||
TType* {.acyclic.} = object of TIdObj # \
|
TType* {.acyclic.} = object of TIdObj # \
|
||||||
# types are identical iff they have the
|
# types are identical iff they have the
|
||||||
# same id; there may be multiple copies of a type
|
# same id; there may be multiple copies of a type
|
||||||
|
|
@ -798,11 +800,12 @@ type
|
||||||
deepCopy*: PSym # overriden 'deepCopy' operation
|
deepCopy*: PSym # overriden 'deepCopy' operation
|
||||||
size*: BiggestInt # the size of the type in bytes
|
size*: BiggestInt # the size of the type in bytes
|
||||||
# -1 means that the size is unkwown
|
# -1 means that the size is unkwown
|
||||||
align*: int # the type's alignment requirements
|
align*: int16 # the type's alignment requirements
|
||||||
|
lockLevel*: TLockLevel # lock level as required for deadlock checking
|
||||||
loc*: TLoc
|
loc*: TLoc
|
||||||
|
|
||||||
TPair*{.final.} = object
|
TPair*{.final.} = object
|
||||||
key*, val*: PObject
|
key*, val*: RootRef
|
||||||
|
|
||||||
TPairSeq* = seq[TPair]
|
TPairSeq* = seq[TPair]
|
||||||
TTable*{.final.} = object # the same as table[PObject] of PObject
|
TTable*{.final.} = object # the same as table[PObject] of PObject
|
||||||
|
|
@ -811,7 +814,7 @@ type
|
||||||
|
|
||||||
TIdPair*{.final.} = object
|
TIdPair*{.final.} = object
|
||||||
key*: PIdObj
|
key*: PIdObj
|
||||||
val*: PObject
|
val*: RootRef
|
||||||
|
|
||||||
TIdPairSeq* = seq[TIdPair]
|
TIdPairSeq* = seq[TIdPair]
|
||||||
TIdTable*{.final.} = object # the same as table[PIdent] of PObject
|
TIdTable*{.final.} = object # the same as table[PIdent] of PObject
|
||||||
|
|
@ -838,7 +841,7 @@ type
|
||||||
counter*: int
|
counter*: int
|
||||||
data*: TNodePairSeq
|
data*: TNodePairSeq
|
||||||
|
|
||||||
TObjectSeq* = seq[PObject]
|
TObjectSeq* = seq[RootRef]
|
||||||
TObjectSet*{.final.} = object
|
TObjectSet*{.final.} = object
|
||||||
counter*: int
|
counter*: int
|
||||||
data*: TObjectSeq
|
data*: TObjectSeq
|
||||||
|
|
@ -1054,7 +1057,7 @@ proc discardSons(father: PNode) =
|
||||||
father.sons = nil
|
father.sons = nil
|
||||||
|
|
||||||
when defined(useNodeIds):
|
when defined(useNodeIds):
|
||||||
const nodeIdToDebug* = 310841 # 612794
|
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||||
#612840 # 612905 # 614635 # 614637 # 614641
|
#612840 # 612905 # 614635 # 614637 # 614641
|
||||||
# 423408
|
# 423408
|
||||||
#429107 # 430443 # 441048 # 441090 # 441153
|
#429107 # 430443 # 441048 # 441090 # 441153
|
||||||
|
|
@ -1166,6 +1169,16 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode,
|
||||||
result.sons = @[name, pattern, genericParams, params,
|
result.sons = @[name, pattern, genericParams, params,
|
||||||
pragmas, exceptions, body]
|
pragmas, exceptions, body]
|
||||||
|
|
||||||
|
const
|
||||||
|
UnspecifiedLockLevel* = TLockLevel(-1'i16)
|
||||||
|
MaxLockLevel* = 1000'i16
|
||||||
|
UnknownLockLevel* = TLockLevel(1001'i16)
|
||||||
|
|
||||||
|
proc `$`*(x: TLockLevel): string =
|
||||||
|
if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>"
|
||||||
|
elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
|
||||||
|
else: result = $int16(x)
|
||||||
|
|
||||||
proc newType(kind: TTypeKind, owner: PSym): PType =
|
proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||||
new(result)
|
new(result)
|
||||||
result.kind = kind
|
result.kind = kind
|
||||||
|
|
@ -1173,6 +1186,7 @@ proc newType(kind: TTypeKind, owner: PSym): PType =
|
||||||
result.size = - 1
|
result.size = - 1
|
||||||
result.align = 2 # default alignment
|
result.align = 2 # default alignment
|
||||||
result.id = getID()
|
result.id = getID()
|
||||||
|
result.lockLevel = UnspecifiedLockLevel
|
||||||
when debugIds:
|
when debugIds:
|
||||||
registerId(result)
|
registerId(result)
|
||||||
#if result.id < 2000:
|
#if result.id < 2000:
|
||||||
|
|
@ -1184,7 +1198,7 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||||
a.flags = a.flags + b.flags
|
a.flags = a.flags + b.flags
|
||||||
if a.t == nil: a.t = b.t
|
if a.t == nil: a.t = b.t
|
||||||
if a.r == nil: a.r = b.r
|
if a.r == nil: a.r = b.r
|
||||||
if a.a == 0: a.a = b.a
|
#if a.a == 0: a.a = b.a
|
||||||
|
|
||||||
proc assignType(dest, src: PType) =
|
proc assignType(dest, src: PType) =
|
||||||
dest.kind = src.kind
|
dest.kind = src.kind
|
||||||
|
|
@ -1195,6 +1209,7 @@ proc assignType(dest, src: PType) =
|
||||||
dest.align = src.align
|
dest.align = src.align
|
||||||
dest.destructor = src.destructor
|
dest.destructor = src.destructor
|
||||||
dest.deepCopy = src.deepCopy
|
dest.deepCopy = src.deepCopy
|
||||||
|
dest.lockLevel = src.lockLevel
|
||||||
# this fixes 'type TLock = TSysLock':
|
# this fixes 'type TLock = TSysLock':
|
||||||
if src.sym != nil:
|
if src.sym != nil:
|
||||||
if dest.sym != nil:
|
if dest.sym != nil:
|
||||||
|
|
@ -1545,3 +1560,9 @@ proc isEmptyType*(t: PType): bool {.inline.} =
|
||||||
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
|
## 'void' and 'stmt' types are often equivalent to 'nil' these days:
|
||||||
result = t == nil or t.kind in {tyEmpty, tyStmt}
|
result = t == nil or t.kind in {tyEmpty, tyStmt}
|
||||||
|
|
||||||
|
proc makeStmtList*(n: PNode): PNode =
|
||||||
|
if n.kind == nkStmtList:
|
||||||
|
result = n
|
||||||
|
else:
|
||||||
|
result = newNodeI(nkStmtList, n.info)
|
||||||
|
result.add n
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
import
|
import
|
||||||
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
|
ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils
|
||||||
|
|
||||||
proc hashNode*(p: PObject): THash
|
proc hashNode*(p: RootRef): THash
|
||||||
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
|
proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope
|
||||||
# Convert a tree into its YAML representation; this is used by the
|
# Convert a tree into its YAML representation; this is used by the
|
||||||
# YAML code generator and it is invaluable for debugging purposes.
|
# YAML code generator and it is invaluable for debugging purposes.
|
||||||
|
|
@ -24,21 +24,21 @@ proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope
|
||||||
proc lineInfoToStr*(info: TLineInfo): PRope
|
proc lineInfoToStr*(info: TLineInfo): PRope
|
||||||
|
|
||||||
# ----------------------- node sets: ---------------------------------------
|
# ----------------------- node sets: ---------------------------------------
|
||||||
proc objectSetContains*(t: TObjectSet, obj: PObject): bool
|
proc objectSetContains*(t: TObjectSet, obj: RootRef): bool
|
||||||
# returns true whether n is in t
|
# returns true whether n is in t
|
||||||
proc objectSetIncl*(t: var TObjectSet, obj: PObject)
|
proc objectSetIncl*(t: var TObjectSet, obj: RootRef)
|
||||||
# include an element n in the table t
|
# include an element n in the table t
|
||||||
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool
|
proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool
|
||||||
# more are not needed ...
|
# more are not needed ...
|
||||||
|
|
||||||
# ----------------------- (key, val)-Hashtables ----------------------------
|
# ----------------------- (key, val)-Hashtables ----------------------------
|
||||||
proc tablePut*(t: var TTable, key, val: PObject)
|
proc tablePut*(t: var TTable, key, val: RootRef)
|
||||||
proc tableGet*(t: TTable, key: PObject): PObject
|
proc tableGet*(t: TTable, key: RootRef): RootRef
|
||||||
type
|
type
|
||||||
TCmpProc* = proc (key, closure: PObject): bool {.nimcall.} # true if found
|
TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found
|
||||||
|
|
||||||
proc tableSearch*(t: TTable, key, closure: PObject,
|
proc tableSearch*(t: TTable, key, closure: RootRef,
|
||||||
comparator: TCmpProc): PObject
|
comparator: TCmpProc): RootRef
|
||||||
# return val as soon as comparator returns true; if this never happens,
|
# return val as soon as comparator returns true; if this never happens,
|
||||||
# nil is returned
|
# nil is returned
|
||||||
|
|
||||||
|
|
@ -79,9 +79,9 @@ proc debug*(n: PType) {.deprecated.}
|
||||||
proc debug*(n: PNode) {.deprecated.}
|
proc debug*(n: PNode) {.deprecated.}
|
||||||
|
|
||||||
# --------------------------- ident tables ----------------------------------
|
# --------------------------- ident tables ----------------------------------
|
||||||
proc idTableGet*(t: TIdTable, key: PIdObj): PObject
|
proc idTableGet*(t: TIdTable, key: PIdObj): RootRef
|
||||||
proc idTableGet*(t: TIdTable, key: int): PObject
|
proc idTableGet*(t: TIdTable, key: int): RootRef
|
||||||
proc idTablePut*(t: var TIdTable, key: PIdObj, val: PObject)
|
proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef)
|
||||||
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
|
proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool
|
||||||
# checks if `t` contains the `key` (compared by the pointer value, not only
|
# checks if `t` contains the `key` (compared by the pointer value, not only
|
||||||
# `key`'s id)
|
# `key`'s id)
|
||||||
|
|
@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
|
||||||
else: internalError(list.info, "getSymFromList")
|
else: internalError(list.info, "getSymFromList")
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc hashNode(p: PObject): THash =
|
proc hashNode(p: RootRef): THash =
|
||||||
result = hash(cast[pointer](p))
|
result = hash(cast[pointer](p))
|
||||||
|
|
||||||
proc mustRehash(length, counter: int): bool =
|
proc mustRehash(length, counter: int): bool =
|
||||||
|
|
@ -245,13 +245,13 @@ proc lineInfoToStr(info: TLineInfo): PRope =
|
||||||
toRope(toLinenumber(info)),
|
toRope(toLinenumber(info)),
|
||||||
toRope(toColumn(info))])
|
toRope(toColumn(info))])
|
||||||
|
|
||||||
proc treeToYamlAux(n: PNode, marker: var TIntSet,
|
proc treeToYamlAux(n: PNode, marker: var IntSet,
|
||||||
indent, maxRecDepth: int): PRope
|
indent, maxRecDepth: int): PRope
|
||||||
proc symToYamlAux(n: PSym, marker: var TIntSet,
|
proc symToYamlAux(n: PSym, marker: var IntSet,
|
||||||
indent, maxRecDepth: int): PRope
|
indent, maxRecDepth: int): PRope
|
||||||
proc typeToYamlAux(n: PType, marker: var TIntSet,
|
proc typeToYamlAux(n: PType, marker: var IntSet,
|
||||||
indent, maxRecDepth: int): PRope
|
indent, maxRecDepth: int): PRope
|
||||||
proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int,
|
proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int,
|
||||||
maxRecDepth: int): PRope =
|
maxRecDepth: int): PRope =
|
||||||
var istr = spaces(indent + 2)
|
var istr = spaces(indent + 2)
|
||||||
result = toRope("[")
|
result = toRope("[")
|
||||||
|
|
@ -277,13 +277,13 @@ proc ropeConstr(indent: int, c: openArray[PRope]): PRope =
|
||||||
inc(i, 2)
|
inc(i, 2)
|
||||||
appf(result, "$N$1}", [spaces(indent)])
|
appf(result, "$N$1}", [spaces(indent)])
|
||||||
|
|
||||||
proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
|
proc symToYamlAux(n: PSym, marker: var IntSet, indent: int,
|
||||||
maxRecDepth: int): PRope =
|
maxRecDepth: int): PRope =
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
elif containsOrIncl(marker, n.id):
|
elif containsOrIncl(marker, n.id):
|
||||||
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
|
result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope(
|
||||||
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
|
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
|
||||||
else:
|
else:
|
||||||
var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
|
var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1)
|
||||||
result = ropeConstr(indent, [toRope("kind"),
|
result = ropeConstr(indent, [toRope("kind"),
|
||||||
|
|
@ -298,13 +298,13 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int,
|
||||||
flagsToStr(n.options), toRope("position"),
|
flagsToStr(n.options), toRope("position"),
|
||||||
toRope(n.position)])
|
toRope(n.position)])
|
||||||
|
|
||||||
proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
|
proc typeToYamlAux(n: PType, marker: var IntSet, indent: int,
|
||||||
maxRecDepth: int): PRope =
|
maxRecDepth: int): PRope =
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
elif containsOrIncl(marker, n.id):
|
elif containsOrIncl(marker, n.id):
|
||||||
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
|
result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope(
|
||||||
strutils.toHex(cast[TAddress](n), sizeof(n) * 2))])
|
strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))])
|
||||||
else:
|
else:
|
||||||
if sonsLen(n) > 0:
|
if sonsLen(n) > 0:
|
||||||
result = toRope("[")
|
result = toRope("[")
|
||||||
|
|
@ -326,7 +326,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
|
||||||
toRope("align"), toRope(n.align),
|
toRope("align"), toRope(n.align),
|
||||||
toRope("sons"), result])
|
toRope("sons"), result])
|
||||||
|
|
||||||
proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
|
proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int,
|
||||||
maxRecDepth: int): PRope =
|
maxRecDepth: int): PRope =
|
||||||
if n == nil:
|
if n == nil:
|
||||||
result = toRope("null")
|
result = toRope("null")
|
||||||
|
|
@ -450,9 +450,10 @@ proc debug(n: PSym) =
|
||||||
writeln(stdout, "skUnknown")
|
writeln(stdout, "skUnknown")
|
||||||
else:
|
else:
|
||||||
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
|
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
|
||||||
writeln(stdout, ropeToStr(ropef("$1_$2: $3, $4, $5", [
|
writeln(stdout, "$1_$2: $3, $4, $5, $6" % [
|
||||||
toRope(n.name.s), toRope(n.id), flagsToStr(n.flags),
|
n.name.s, $n.id, flagsToStr(n.flags).ropeToStr,
|
||||||
flagsToStr(n.loc.flags), lineInfoToStr(n.info)])))
|
flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr,
|
||||||
|
$n.kind])
|
||||||
|
|
||||||
proc debug(n: PType) =
|
proc debug(n: PType) =
|
||||||
writeln(stdout, ropeToStr(debugType(n)))
|
writeln(stdout, ropeToStr(debugType(n)))
|
||||||
|
|
@ -469,7 +470,7 @@ proc nextTry(h, maxHash: THash): THash =
|
||||||
# generates each int in range(maxHash) exactly once (see any text on
|
# generates each int in range(maxHash) exactly once (see any text on
|
||||||
# random-number generation for proof).
|
# random-number generation for proof).
|
||||||
|
|
||||||
proc objectSetContains(t: TObjectSet, obj: PObject): bool =
|
proc objectSetContains(t: TObjectSet, obj: RootRef): bool =
|
||||||
# returns true whether n is in t
|
# returns true whether n is in t
|
||||||
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
|
var h: THash = hashNode(obj) and high(t.data) # start with real hash value
|
||||||
while t.data[h] != nil:
|
while t.data[h] != nil:
|
||||||
|
|
@ -478,7 +479,7 @@ proc objectSetContains(t: TObjectSet, obj: PObject): bool =
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
result = false
|
result = false
|
||||||
|
|
||||||
proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) =
|
proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) =
|
||||||
var h: THash = hashNode(obj) and high(data)
|
var h: THash = hashNode(obj) and high(data)
|
||||||
while data[h] != nil:
|
while data[h] != nil:
|
||||||
assert(data[h] != obj)
|
assert(data[h] != obj)
|
||||||
|
|
@ -493,12 +494,12 @@ proc objectSetEnlarge(t: var TObjectSet) =
|
||||||
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
|
if t.data[i] != nil: objectSetRawInsert(n, t.data[i])
|
||||||
swap(t.data, n)
|
swap(t.data, n)
|
||||||
|
|
||||||
proc objectSetIncl(t: var TObjectSet, obj: PObject) =
|
proc objectSetIncl(t: var TObjectSet, obj: RootRef) =
|
||||||
if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
|
if mustRehash(len(t.data), t.counter): objectSetEnlarge(t)
|
||||||
objectSetRawInsert(t.data, obj)
|
objectSetRawInsert(t.data, obj)
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
|
|
||||||
proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
|
proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool =
|
||||||
# returns true if obj is already in the string table:
|
# returns true if obj is already in the string table:
|
||||||
var h: THash = hashNode(obj) and high(t.data)
|
var h: THash = hashNode(obj) and high(t.data)
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -516,7 +517,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
result = false
|
result = false
|
||||||
|
|
||||||
proc tableRawGet(t: TTable, key: PObject): int =
|
proc tableRawGet(t: TTable, key: RootRef): int =
|
||||||
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
||||||
while t.data[h].key != nil:
|
while t.data[h].key != nil:
|
||||||
if t.data[h].key == key:
|
if t.data[h].key == key:
|
||||||
|
|
@ -524,8 +525,8 @@ proc tableRawGet(t: TTable, key: PObject): int =
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
result = -1
|
result = -1
|
||||||
|
|
||||||
proc tableSearch(t: TTable, key, closure: PObject,
|
proc tableSearch(t: TTable, key, closure: RootRef,
|
||||||
comparator: TCmpProc): PObject =
|
comparator: TCmpProc): RootRef =
|
||||||
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
var h: THash = hashNode(key) and high(t.data) # start with real hash value
|
||||||
while t.data[h].key != nil:
|
while t.data[h].key != nil:
|
||||||
if t.data[h].key == key:
|
if t.data[h].key == key:
|
||||||
|
|
@ -535,12 +536,12 @@ proc tableSearch(t: TTable, key, closure: PObject,
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc tableGet(t: TTable, key: PObject): PObject =
|
proc tableGet(t: TTable, key: RootRef): RootRef =
|
||||||
var index = tableRawGet(t, key)
|
var index = tableRawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
else: result = nil
|
else: result = nil
|
||||||
|
|
||||||
proc tableRawInsert(data: var TPairSeq, key, val: PObject) =
|
proc tableRawInsert(data: var TPairSeq, key, val: RootRef) =
|
||||||
var h: THash = hashNode(key) and high(data)
|
var h: THash = hashNode(key) and high(data)
|
||||||
while data[h].key != nil:
|
while data[h].key != nil:
|
||||||
assert(data[h].key != key)
|
assert(data[h].key != key)
|
||||||
|
|
@ -556,7 +557,7 @@ proc tableEnlarge(t: var TTable) =
|
||||||
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
|
if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val)
|
||||||
swap(t.data, n)
|
swap(t.data, n)
|
||||||
|
|
||||||
proc tablePut(t: var TTable, key, val: PObject) =
|
proc tablePut(t: var TTable, key, val: RootRef) =
|
||||||
var index = tableRawGet(t, key)
|
var index = tableRawGet(t, key)
|
||||||
if index >= 0:
|
if index >= 0:
|
||||||
t.data[index].val = val
|
t.data[index].val = val
|
||||||
|
|
@ -626,20 +627,34 @@ proc strTableAdd(t: var TStrTable, n: PSym) =
|
||||||
strTableRawInsert(t.data, n)
|
strTableRawInsert(t.data, n)
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
|
|
||||||
|
proc reallySameIdent(a, b: string): bool {.inline.} =
|
||||||
|
when defined(nimfix):
|
||||||
|
result = a[0] == b[0]
|
||||||
|
else:
|
||||||
|
result = true
|
||||||
|
|
||||||
proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} =
|
||||||
# returns true if n is already in the string table:
|
# returns true if n is already in the string table:
|
||||||
# It is essential that `n` is written nevertheless!
|
# It is essential that `n` is written nevertheless!
|
||||||
# This way the newest redefinition is picked by the semantic analyses!
|
# This way the newest redefinition is picked by the semantic analyses!
|
||||||
assert n.name != nil
|
assert n.name != nil
|
||||||
var h: THash = n.name.h and high(t.data)
|
var h: THash = n.name.h and high(t.data)
|
||||||
|
var replaceSlot = -1
|
||||||
while true:
|
while true:
|
||||||
var it = t.data[h]
|
var it = t.data[h]
|
||||||
if it == nil: break
|
if it == nil: break
|
||||||
if it.name.id == n.name.id:
|
# Semantic checking can happen multiple times thanks to templates
|
||||||
t.data[h] = n # overwrite it with newer definition!
|
# and overloading: (var x=@[]; x).mapIt(it).
|
||||||
return true # found it
|
# So it is possible the very same sym is added multiple
|
||||||
|
# times to the symbol table which we allow here with the 'it == n' check.
|
||||||
|
if it.name.id == n.name.id and reallySameIdent(it.name.s, n.name.s):
|
||||||
|
if it == n: return false
|
||||||
|
replaceSlot = h
|
||||||
h = nextTry(h, high(t.data))
|
h = nextTry(h, high(t.data))
|
||||||
if mustRehash(len(t.data), t.counter):
|
if replaceSlot >= 0:
|
||||||
|
t.data[replaceSlot] = n # overwrite it with newer definition!
|
||||||
|
return true # found it
|
||||||
|
elif mustRehash(len(t.data), t.counter):
|
||||||
strTableEnlarge(t)
|
strTableEnlarge(t)
|
||||||
strTableRawInsert(t.data, n)
|
strTableRawInsert(t.data, n)
|
||||||
else:
|
else:
|
||||||
|
|
@ -677,7 +692,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
||||||
ti.h = nextTry(h, high(tab.data))
|
ti.h = nextTry(h, high(tab.data))
|
||||||
|
|
||||||
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
||||||
excluding: TIntSet): PSym =
|
excluding: IntSet): PSym =
|
||||||
var h: THash = ti.h and high(tab.data)
|
var h: THash = ti.h and high(tab.data)
|
||||||
var start = h
|
var start = h
|
||||||
result = tab.data[h]
|
result = tab.data[h]
|
||||||
|
|
@ -693,7 +708,7 @@ proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable,
|
||||||
if result != nil and contains(excluding, result.id): result = nil
|
if result != nil and contains(excluding, result.id): result = nil
|
||||||
|
|
||||||
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
|
proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
|
||||||
excluding: TIntSet): PSym =
|
excluding: IntSet): PSym =
|
||||||
ti.h = s.h
|
ti.h = s.h
|
||||||
ti.name = s
|
ti.name = s
|
||||||
if tab.counter == 0: result = nil
|
if tab.counter == 0: result = nil
|
||||||
|
|
@ -740,22 +755,22 @@ proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool =
|
||||||
if index >= 0: result = t.data[index].key == key
|
if index >= 0: result = t.data[index].key == key
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
proc idTableGet(t: TIdTable, key: PIdObj): PObject =
|
proc idTableGet(t: TIdTable, key: PIdObj): RootRef =
|
||||||
var index = idTableRawGet(t, key.id)
|
var index = idTableRawGet(t, key.id)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
else: result = nil
|
else: result = nil
|
||||||
|
|
||||||
proc idTableGet(t: TIdTable, key: int): PObject =
|
proc idTableGet(t: TIdTable, key: int): RootRef =
|
||||||
var index = idTableRawGet(t, key)
|
var index = idTableRawGet(t, key)
|
||||||
if index >= 0: result = t.data[index].val
|
if index >= 0: result = t.data[index].val
|
||||||
else: result = nil
|
else: result = nil
|
||||||
|
|
||||||
iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] =
|
iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] =
|
||||||
for i in 0..high(t.data):
|
for i in 0..high(t.data):
|
||||||
if t.data[i].key != nil:
|
if t.data[i].key != nil:
|
||||||
yield (t.data[i].key.id, t.data[i].val)
|
yield (t.data[i].key.id, t.data[i].val)
|
||||||
|
|
||||||
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
|
proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) =
|
||||||
var h: THash
|
var h: THash
|
||||||
h = key.id and high(data)
|
h = key.id and high(data)
|
||||||
while data[h].key != nil:
|
while data[h].key != nil:
|
||||||
|
|
@ -765,7 +780,7 @@ proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) =
|
||||||
data[h].key = key
|
data[h].key = key
|
||||||
data[h].val = val
|
data[h].val = val
|
||||||
|
|
||||||
proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
|
proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) =
|
||||||
var
|
var
|
||||||
index: int
|
index: int
|
||||||
n: TIdPairSeq
|
n: TIdPairSeq
|
||||||
|
|
@ -784,7 +799,7 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) =
|
||||||
idTableRawInsert(t.data, key, val)
|
idTableRawInsert(t.data, key, val)
|
||||||
inc(t.counter)
|
inc(t.counter)
|
||||||
|
|
||||||
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] =
|
iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] =
|
||||||
for i in 0 .. high(t.data):
|
for i in 0 .. high(t.data):
|
||||||
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
|
if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# this unit handles Nimrod sets; it implements bit sets
|
# this unit handles Nim sets; it implements bit sets
|
||||||
# the code here should be reused in the Nimrod standard library
|
# the code here should be reused in the Nim standard library
|
||||||
|
|
||||||
type
|
type
|
||||||
TBitSet* = seq[int8] # we use byte here to avoid issues with
|
TBitSet* = seq[int8] # we use byte here to avoid issues with
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -370,7 +370,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||||
# the last entry of a symbol:
|
# the last entry of a symbol:
|
||||||
if s.ast != nil:
|
if s.ast != nil:
|
||||||
# we used to attempt to save space here by only storing a dummy AST if
|
# we used to attempt to save space here by only storing a dummy AST if
|
||||||
# it is not necessary, but Nimrod's heavy compile-time evaluation features
|
# it is not necessary, but Nim's heavy compile-time evaluation features
|
||||||
# make that unfeasible nowadays:
|
# make that unfeasible nowadays:
|
||||||
encodeNode(w, s.info, s.ast, result)
|
encodeNode(w, s.info, s.ast, result)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -103,9 +103,9 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
|
||||||
result = ropef("$1, $1Len0", [rdLoc(a)])
|
result = ropef("$1, $1Len0", [rdLoc(a)])
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
if skipTypes(n.typ, abstractInst).kind == tyVar:
|
if skipTypes(n.typ, abstractInst).kind == tyVar:
|
||||||
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField()])
|
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
|
||||||
else:
|
else:
|
||||||
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()])
|
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
|
||||||
of tyArray, tyArrayConstr:
|
of tyArray, tyArrayConstr:
|
||||||
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
|
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
|
||||||
else: internalError("openArrayLoc: " & typeToString(a.t))
|
else: internalError("openArrayLoc: " & typeToString(a.t))
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -11,11 +11,19 @@
|
||||||
|
|
||||||
# -------------------------- constant expressions ------------------------
|
# -------------------------- constant expressions ------------------------
|
||||||
|
|
||||||
|
proc int64Literal(i: BiggestInt): PRope =
|
||||||
|
if i > low(int64):
|
||||||
|
result = rfmt(nil, "IL64($1)", toRope(i))
|
||||||
|
else:
|
||||||
|
result = ~"(IL64(-9223372036854775807) - IL64(1))"
|
||||||
|
|
||||||
|
proc uint64Literal(i: uint64): PRope = toRope($i & "ULL")
|
||||||
|
|
||||||
proc intLiteral(i: BiggestInt): PRope =
|
proc intLiteral(i: BiggestInt): PRope =
|
||||||
if (i > low(int32)) and (i <= high(int32)):
|
if i > low(int32) and i <= high(int32):
|
||||||
result = toRope(i)
|
result = toRope(i)
|
||||||
elif i == low(int32):
|
elif i == low(int32):
|
||||||
# Nimrod has the same bug for the same reasons :-)
|
# Nim has the same bug for the same reasons :-)
|
||||||
result = ~"(-2147483647 -1)"
|
result = ~"(-2147483647 -1)"
|
||||||
elif i > low(int64):
|
elif i > low(int64):
|
||||||
result = rfmt(nil, "IL64($1)", toRope(i))
|
result = rfmt(nil, "IL64($1)", toRope(i))
|
||||||
|
|
@ -31,7 +39,7 @@ proc int32Literal(i: int): PRope =
|
||||||
proc genHexLiteral(v: PNode): PRope =
|
proc genHexLiteral(v: PNode): PRope =
|
||||||
# hex literals are unsigned in C
|
# hex literals are unsigned in C
|
||||||
# so we don't generate hex literals any longer.
|
# so we don't generate hex literals any longer.
|
||||||
if not (v.kind in {nkIntLit..nkUInt64Lit}):
|
if v.kind notin {nkIntLit..nkUInt64Lit}:
|
||||||
internalError(v.info, "genHexLiteral")
|
internalError(v.info, "genHexLiteral")
|
||||||
result = intLiteral(v.intVal)
|
result = intLiteral(v.intVal)
|
||||||
|
|
||||||
|
|
@ -46,16 +54,18 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCharLit..nkUInt64Lit:
|
of nkCharLit..nkUInt64Lit:
|
||||||
case skipTypes(ty, abstractVarRange).kind
|
case skipTypes(ty, abstractVarRange).kind
|
||||||
of tyChar, tyInt64, tyNil:
|
of tyChar, tyNil:
|
||||||
result = intLiteral(n.intVal)
|
result = intLiteral(n.intVal)
|
||||||
of tyInt:
|
of tyInt:
|
||||||
if (n.intVal >= low(int32)) and (n.intVal <= high(int32)):
|
if n.intVal >= low(int32) and n.intVal <= high(int32):
|
||||||
result = int32Literal(int32(n.intVal))
|
result = int32Literal(int32(n.intVal))
|
||||||
else:
|
else:
|
||||||
result = intLiteral(n.intVal)
|
result = intLiteral(n.intVal)
|
||||||
of tyBool:
|
of tyBool:
|
||||||
if n.intVal != 0: result = ~"NIM_TRUE"
|
if n.intVal != 0: result = ~"NIM_TRUE"
|
||||||
else: result = ~"NIM_FALSE"
|
else: result = ~"NIM_FALSE"
|
||||||
|
of tyInt64: result = int64Literal(n.intVal)
|
||||||
|
of tyUInt64: result = uint64Literal(uint64(n.intVal))
|
||||||
else:
|
else:
|
||||||
result = ropef("(($1) $2)", [getTypeDesc(p.module,
|
result = ropef("(($1) $2)", [getTypeDesc(p.module,
|
||||||
skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)])
|
skipTypes(ty, abstractVarRange)), intLiteral(n.intVal)])
|
||||||
|
|
@ -214,9 +224,9 @@ proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
|
||||||
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
let newflags =
|
let newflags =
|
||||||
if src.k == locData:
|
if src.k == locData:
|
||||||
flags + { needToCopy }
|
flags + {needToCopy}
|
||||||
elif tfShallow in dest.t.flags:
|
elif tfShallow in dest.t.flags:
|
||||||
flags - { needToCopy }
|
flags - {needToCopy}
|
||||||
else:
|
else:
|
||||||
flags
|
flags
|
||||||
for i in 0 .. <dest.t.len:
|
for i in 0 .. <dest.t.len:
|
||||||
|
|
@ -230,9 +240,9 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
|
||||||
if t == nil: return
|
if t == nil: return
|
||||||
let newflags =
|
let newflags =
|
||||||
if src.k == locData:
|
if src.k == locData:
|
||||||
flags + { needToCopy }
|
flags + {needToCopy}
|
||||||
elif tfShallow in dest.t.flags:
|
elif tfShallow in dest.t.flags:
|
||||||
flags - { needToCopy }
|
flags - {needToCopy}
|
||||||
else:
|
else:
|
||||||
flags
|
flags
|
||||||
case t.kind
|
case t.kind
|
||||||
|
|
@ -318,7 +328,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||||
of tyObject:
|
of tyObject:
|
||||||
# XXX: check for subtyping?
|
# XXX: check for subtyping?
|
||||||
if needsComplexAssignment(ty):
|
if not isObjLackingTypeField(ty):
|
||||||
|
genGenericAsgn(p, dest, src, flags)
|
||||||
|
elif needsComplexAssignment(ty):
|
||||||
if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
|
if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
|
||||||
discard getTypeDesc(p.module, ty)
|
discard getTypeDesc(p.module, ty)
|
||||||
internalAssert ty.n != nil
|
internalAssert ty.n != nil
|
||||||
|
|
@ -409,7 +421,6 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
|
||||||
d.k = locData
|
d.k = locData
|
||||||
d.t = getUniqueType(t)
|
d.t = getUniqueType(t)
|
||||||
d.r = r
|
d.r = r
|
||||||
d.a = -1
|
|
||||||
|
|
||||||
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
|
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
|
|
@ -425,7 +436,6 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
|
||||||
d.k = locExpr
|
d.k = locExpr
|
||||||
d.t = getUniqueType(t)
|
d.t = getUniqueType(t)
|
||||||
d.r = r
|
d.r = r
|
||||||
d.a = -1
|
|
||||||
|
|
||||||
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
|
|
@ -647,13 +657,16 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
|
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
|
||||||
getSimpleTypeDesc(p.module, e.typ)]))
|
getSimpleTypeDesc(p.module, e.typ)]))
|
||||||
|
|
||||||
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||||
var a: TLoc
|
let mt = mapType(e.sons[0].typ)
|
||||||
if mapType(e.sons[0].typ) in {ctArray, ctPtrToArray}:
|
if mt in {ctArray, ctPtrToArray} and not enforceDeref:
|
||||||
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
||||||
# simply wrap them in a struct? --> Losing auto vectorization then?
|
# simply wrap them in a struct? --> Losing auto vectorization then?
|
||||||
|
#if e[0].kind != nkBracketExpr:
|
||||||
|
# message(e.info, warnUser, "CAME HERE " & renderTree(e))
|
||||||
expr(p, e.sons[0], d)
|
expr(p, e.sons[0], d)
|
||||||
else:
|
else:
|
||||||
|
var a: TLoc
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, e.sons[0], a)
|
||||||
case skipTypes(a.t, abstractInst).kind
|
case skipTypes(a.t, abstractInst).kind
|
||||||
of tyRef:
|
of tyRef:
|
||||||
|
|
@ -663,7 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
|
||||||
of tyPtr:
|
of tyPtr:
|
||||||
d.s = OnUnknown # BUGFIX!
|
d.s = OnUnknown # BUGFIX!
|
||||||
else: internalError(e.info, "genDeref " & $a.t.kind)
|
else: internalError(e.info, "genDeref " & $a.t.kind)
|
||||||
putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
|
if enforceDeref and mt == ctPtrToArray:
|
||||||
|
# we lie about the type for better C interop: 'ptr array[3,T]' is
|
||||||
|
# translated to 'ptr T', but for deref'ing this produces wrong code.
|
||||||
|
# See tmissingderef. So we get rid of the deref instead. The codegen
|
||||||
|
# ends up using 'memcpy' for the array assignment,
|
||||||
|
# so the '&' and '*' cancel out:
|
||||||
|
putIntoDest(p, d, a.t.sons[0], rdLoc(a))
|
||||||
|
else:
|
||||||
|
putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
|
||||||
|
|
||||||
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
# careful 'addr(myptrToArray)' needs to get the ampersand:
|
# careful 'addr(myptrToArray)' needs to get the ampersand:
|
||||||
|
|
@ -723,7 +744,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
internalError(e.info, "genRecordField")
|
internalError(e.info, "genRecordField")
|
||||||
field = lookupInRecord(ty.n, f.name)
|
field = lookupInRecord(ty.n, f.name)
|
||||||
if field != nil: break
|
if field != nil: break
|
||||||
if gCmd != cmdCompileToCpp: app(r, ".Sup")
|
if not p.module.compileToCpp: app(r, ".Sup")
|
||||||
ty = getUniqueType(ty.sons[0])
|
ty = getUniqueType(ty.sons[0])
|
||||||
if field == nil: internalError(e.info, "genRecordField 2 ")
|
if field == nil: internalError(e.info, "genRecordField 2 ")
|
||||||
if field.loc.r == nil: internalError(e.info, "genRecordField 3")
|
if field.loc.r == nil: internalError(e.info, "genRecordField 3")
|
||||||
|
|
@ -775,7 +796,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
assert(ty.kind in {tyTuple, tyObject})
|
assert(ty.kind in {tyTuple, tyObject})
|
||||||
field = lookupInRecord(ty.n, f.name)
|
field = lookupInRecord(ty.n, f.name)
|
||||||
if field != nil: break
|
if field != nil: break
|
||||||
if gCmd != cmdCompileToCpp: app(r, ".Sup")
|
if not p.module.compileToCpp: app(r, ".Sup")
|
||||||
ty = getUniqueType(ty.sons[0])
|
ty = getUniqueType(ty.sons[0])
|
||||||
if field == nil: internalError(e.info, "genCheckedRecordField")
|
if field == nil: internalError(e.info, "genCheckedRecordField")
|
||||||
if field.loc.r == nil:
|
if field.loc.r == nil:
|
||||||
|
|
@ -786,15 +807,15 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
else:
|
else:
|
||||||
genRecordField(p, e.sons[0], d)
|
genRecordField(p, e.sons[0], d)
|
||||||
|
|
||||||
proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, x, a)
|
||||||
initLocExpr(p, e.sons[1], b)
|
initLocExpr(p, y, b)
|
||||||
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
|
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
|
||||||
var first = intLiteral(firstOrd(ty))
|
var first = intLiteral(firstOrd(ty))
|
||||||
# emit range check:
|
# emit range check:
|
||||||
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
|
if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
|
||||||
if not isConstExpr(e.sons[1]):
|
if not isConstExpr(y):
|
||||||
# semantic pass has already checked for const index expressions
|
# semantic pass has already checked for const index expressions
|
||||||
if firstOrd(ty) == 0:
|
if firstOrd(ty) == 0:
|
||||||
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)):
|
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)):
|
||||||
|
|
@ -804,26 +825,26 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
||||||
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
|
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
|
||||||
rdCharLoc(b), first, intLiteral(lastOrd(ty)))
|
rdCharLoc(b), first, intLiteral(lastOrd(ty)))
|
||||||
else:
|
else:
|
||||||
let idx = getOrdValue(e.sons[1])
|
let idx = getOrdValue(y)
|
||||||
if idx < firstOrd(ty) or idx > lastOrd(ty):
|
if idx < firstOrd(ty) or idx > lastOrd(ty):
|
||||||
localError(e.info, errIndexOutOfBounds)
|
localError(x.info, errIndexOutOfBounds)
|
||||||
d.inheritLocation(a)
|
d.inheritLocation(a)
|
||||||
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
|
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
|
||||||
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first))
|
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first))
|
||||||
|
|
||||||
proc genCStringElem(p: BProc, e: PNode, d: var TLoc) =
|
proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, x, a)
|
||||||
initLocExpr(p, e.sons[1], b)
|
initLocExpr(p, y, b)
|
||||||
var ty = skipTypes(a.t, abstractVarRange)
|
var ty = skipTypes(a.t, abstractVarRange)
|
||||||
if d.k == locNone: d.s = a.s
|
if d.k == locNone: d.s = a.s
|
||||||
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
|
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
|
||||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
|
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
|
||||||
|
|
||||||
proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, x, a)
|
||||||
initLocExpr(p, e.sons[1], b) # emit range check:
|
initLocExpr(p, y, b) # emit range check:
|
||||||
if optBoundsCheck in p.options:
|
if optBoundsCheck in p.options:
|
||||||
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n",
|
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n",
|
||||||
rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
|
rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
|
||||||
|
|
@ -831,10 +852,10 @@ proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
|
||||||
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
||||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
|
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
|
||||||
|
|
||||||
proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
|
proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
|
||||||
var a, b: TLoc
|
var a, b: TLoc
|
||||||
initLocExpr(p, e.sons[0], a)
|
initLocExpr(p, x, a)
|
||||||
initLocExpr(p, e.sons[1], b)
|
initLocExpr(p, y, b)
|
||||||
var ty = skipTypes(a.t, abstractVarRange)
|
var ty = skipTypes(a.t, abstractVarRange)
|
||||||
if ty.kind in {tyRef, tyPtr}:
|
if ty.kind in {tyRef, tyPtr}:
|
||||||
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
|
ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
|
||||||
|
|
@ -842,11 +863,11 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
|
||||||
if ty.kind == tyString:
|
if ty.kind == tyString:
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
|
"if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
|
||||||
rdLoc(b), rdLoc(a), lenField())
|
rdLoc(b), rdLoc(a), lenField(p))
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
|
||||||
rdLoc(b), rdLoc(a), lenField())
|
rdLoc(b), rdLoc(a), lenField(p))
|
||||||
if d.k == locNone: d.s = OnHeap
|
if d.k == locNone: d.s = OnHeap
|
||||||
d.heapRoot = a.r
|
d.heapRoot = a.r
|
||||||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||||
|
|
@ -854,6 +875,17 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
|
||||||
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
|
||||||
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)))
|
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)))
|
||||||
|
|
||||||
|
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
|
||||||
|
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
|
||||||
|
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
|
||||||
|
case ty.kind
|
||||||
|
of tyArray, tyArrayConstr: genArrayElem(p, n.sons[0], n.sons[1], d)
|
||||||
|
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n.sons[0], n.sons[1], d)
|
||||||
|
of tySequence, tyString: genSeqElem(p, n.sons[0], n.sons[1], d)
|
||||||
|
of tyCString: genCStringElem(p, n.sons[0], n.sons[1], d)
|
||||||
|
of tyTuple: genTupleElem(p, n, d)
|
||||||
|
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
||||||
|
|
||||||
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||||
# how to generate code?
|
# how to generate code?
|
||||||
# 'expr1 and expr2' becomes:
|
# 'expr1 and expr2' becomes:
|
||||||
|
|
@ -895,20 +927,21 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||||
proc genEcho(p: BProc, n: PNode) =
|
proc genEcho(p: BProc, n: PNode) =
|
||||||
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||||
# is threadsafe.
|
# is threadsafe.
|
||||||
|
internalAssert n.kind == nkBracket
|
||||||
discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
|
discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
|
||||||
var args: PRope = nil
|
var args: PRope = nil
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
for i in countup(1, n.len-1):
|
for i in countup(0, n.len-1):
|
||||||
initLocExpr(p, n.sons[i], a)
|
initLocExpr(p, n.sons[i], a)
|
||||||
appf(args, ", ($1)->data", [rdLoc(a)])
|
appf(args, ", ($1)->data", [rdLoc(a)])
|
||||||
linefmt(p, cpsStmts, "printf($1$2);$n",
|
linefmt(p, cpsStmts, "printf($1$2);$n",
|
||||||
makeCString(repeatStr(n.len-1, "%s") & tnl), args)
|
makeCString(repeatStr(n.len, "%s") & tnl), args)
|
||||||
|
|
||||||
proc gcUsage(n: PNode) =
|
proc gcUsage(n: PNode) =
|
||||||
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
||||||
|
|
||||||
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
||||||
# <Nimrod code>
|
# <Nim code>
|
||||||
# s = 'Hello ' & name & ', how do you feel?' & 'z'
|
# s = 'Hello ' & name & ', how do you feel?' & 'z'
|
||||||
#
|
#
|
||||||
# <generated C code>
|
# <generated C code>
|
||||||
|
|
@ -939,7 +972,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
||||||
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
|
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
|
||||||
inc(L, len(e.sons[i + 1].strVal))
|
inc(L, len(e.sons[i + 1].strVal))
|
||||||
else:
|
else:
|
||||||
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
|
appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
|
||||||
app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
|
app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
|
||||||
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L))
|
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L))
|
||||||
app(p.s(cpsStmts), appends)
|
app(p.s(cpsStmts), appends)
|
||||||
|
|
@ -951,7 +984,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
||||||
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
# <Nimrod code>
|
# <Nim code>
|
||||||
# s &= 'Hello ' & name & ', how do you feel?' & 'z'
|
# s &= 'Hello ' & name & ', how do you feel?' & 'z'
|
||||||
# // BUG: what if s is on the left side too?
|
# // BUG: what if s is on the left side too?
|
||||||
# <generated C code>
|
# <generated C code>
|
||||||
|
|
@ -979,7 +1012,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
|
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
|
||||||
inc(L, len(e.sons[i + 2].strVal))
|
inc(L, len(e.sons[i + 2].strVal))
|
||||||
else:
|
else:
|
||||||
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
|
appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)])
|
||||||
app(appends, rfmt(p.module, "#appendString($1, $2);$n",
|
app(appends, rfmt(p.module, "#appendString($1, $2);$n",
|
||||||
rdLoc(dest), rdLoc(a)))
|
rdLoc(dest), rdLoc(a)))
|
||||||
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
|
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
|
||||||
|
|
@ -992,7 +1025,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
# seq &= x -->
|
# seq &= x -->
|
||||||
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
|
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
|
||||||
# seq->data[seq->len-1] = x;
|
# seq->data[seq->len-1] = x;
|
||||||
let seqAppendPattern = if gCmd != cmdCompileToCpp:
|
let seqAppendPattern = if not p.module.compileToCpp:
|
||||||
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
|
"$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n"
|
||||||
else:
|
else:
|
||||||
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
|
"$1 = ($2) #incrSeq($1, sizeof($3));$n"
|
||||||
|
|
@ -1005,7 +1038,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||||
getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))])
|
getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))])
|
||||||
keepAlive(p, a)
|
keepAlive(p, a)
|
||||||
initLoc(dest, locExpr, b.t, OnHeap)
|
initLoc(dest, locExpr, b.t, OnHeap)
|
||||||
dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField())
|
dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField(p))
|
||||||
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
|
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
|
||||||
gcUsage(e)
|
gcUsage(e)
|
||||||
|
|
||||||
|
|
@ -1099,11 +1132,11 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
while ty != nil:
|
while ty != nil:
|
||||||
field = lookupInRecord(ty.n, it.sons[0].sym.name)
|
field = lookupInRecord(ty.n, it.sons[0].sym.name)
|
||||||
if field != nil: break
|
if field != nil: break
|
||||||
if gCmd != cmdCompileToCpp: app(tmp2.r, ".Sup")
|
if not p.module.compileToCpp: app(tmp2.r, ".Sup")
|
||||||
ty = getUniqueType(ty.sons[0])
|
ty = getUniqueType(ty.sons[0])
|
||||||
if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
|
if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
|
||||||
if it.len == 3 and optFieldCheck in p.options:
|
if it.len == 3 and optFieldCheck in p.options:
|
||||||
genFieldCheck(p, it.sons[2], r, field)
|
genFieldCheck(p, it.sons[2], tmp2.r, field)
|
||||||
app(tmp2.r, ".")
|
app(tmp2.r, ".")
|
||||||
app(tmp2.r, field.loc.r)
|
app(tmp2.r, field.loc.r)
|
||||||
tmp2.k = locTemp
|
tmp2.k = locTemp
|
||||||
|
|
@ -1200,8 +1233,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||||
if t.kind != tyVar: nilCheck = r
|
if t.kind != tyVar: nilCheck = r
|
||||||
r = rfmt(nil, "(*$1)", r)
|
r = rfmt(nil, "(*$1)", r)
|
||||||
t = skipTypes(t.lastSon, typedescInst)
|
t = skipTypes(t.lastSon, typedescInst)
|
||||||
if gCmd != cmdCompileToCpp:
|
if not p.module.compileToCpp:
|
||||||
while (t.kind == tyObject) and (t.sons[0] != nil):
|
while t.kind == tyObject and t.sons[0] != nil:
|
||||||
app(r, ~".Sup")
|
app(r, ~".Sup")
|
||||||
t = skipTypes(t.sons[0], typedescInst)
|
t = skipTypes(t.sons[0], typedescInst)
|
||||||
if isObjLackingTypeField(t):
|
if isObjLackingTypeField(t):
|
||||||
|
|
@ -1246,7 +1279,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||||
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
|
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
putIntoDest(p, b, e.typ,
|
putIntoDest(p, b, e.typ,
|
||||||
ropef("$1->data, $1->$2", [rdLoc(a), lenField()]))
|
ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)]))
|
||||||
of tyArray, tyArrayConstr:
|
of tyArray, tyArrayConstr:
|
||||||
putIntoDest(p, b, e.typ,
|
putIntoDest(p, b, e.typ,
|
||||||
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
|
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
|
||||||
|
|
@ -1289,7 +1322,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
|
if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
|
||||||
else: unaryExpr(p, e, d, "strlen($1)")
|
else: unaryExpr(p, e, d, "strlen($1)")
|
||||||
of tyString, tySequence:
|
of tyString, tySequence:
|
||||||
if gCmd != cmdCompileToCpp:
|
if not p.module.compileToCpp:
|
||||||
if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)")
|
if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)")
|
||||||
else: unaryExpr(p, e, d, "$1->Sup.len")
|
else: unaryExpr(p, e, d, "$1->Sup.len")
|
||||||
else:
|
else:
|
||||||
|
|
@ -1307,7 +1340,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||||
initLocExpr(p, e.sons[1], a)
|
initLocExpr(p, e.sons[1], a)
|
||||||
initLocExpr(p, e.sons[2], b)
|
initLocExpr(p, e.sons[2], b)
|
||||||
var t = skipTypes(e.sons[1].typ, abstractVar)
|
var t = skipTypes(e.sons[1].typ, abstractVar)
|
||||||
let setLenPattern = if gCmd != cmdCompileToCpp:
|
let setLenPattern = if not p.module.compileToCpp:
|
||||||
"$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
|
"$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n"
|
||||||
else:
|
else:
|
||||||
"$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n"
|
"$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n"
|
||||||
|
|
@ -1508,7 +1541,6 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
||||||
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
|
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
|
||||||
getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl)
|
getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl)
|
||||||
tmp.k = locExpr
|
tmp.k = locExpr
|
||||||
tmp.a = -1
|
|
||||||
tmp.t = srct
|
tmp.t = srct
|
||||||
tmp.s = OnStack
|
tmp.s = OnStack
|
||||||
tmp.flags = {}
|
tmp.flags = {}
|
||||||
|
|
@ -1564,11 +1596,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
|
||||||
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
|
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
|
||||||
initLocExpr(p, e.sons[2], x)
|
initLocExpr(p, e.sons[2], x)
|
||||||
putIntoDest(p, d, e.typ,
|
putIntoDest(p, d, e.typ,
|
||||||
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField()))
|
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||||
elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
|
elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
|
||||||
initLocExpr(p, e.sons[1], x)
|
initLocExpr(p, e.sons[1], x)
|
||||||
putIntoDest(p, d, e.typ,
|
putIntoDest(p, d, e.typ,
|
||||||
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField()))
|
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, e, d, "#eqStrings($1, $2)")
|
binaryExpr(p, e, d, "#eqStrings($1, $2)")
|
||||||
|
|
||||||
|
|
@ -1673,7 +1705,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
discard cgsym(p.module, opr.loc.r.ropeToStr)
|
discard cgsym(p.module, opr.loc.r.ropeToStr)
|
||||||
genCall(p, e, d)
|
genCall(p, e, d)
|
||||||
of mReset: genReset(p, e)
|
of mReset: genReset(p, e)
|
||||||
of mEcho: genEcho(p, e)
|
of mEcho: genEcho(p, e[1].skipConv)
|
||||||
of mArrToSeq: genArrToSeq(p, e, d)
|
of mArrToSeq: genArrToSeq(p, e, d)
|
||||||
of mNLen..mNError:
|
of mNLen..mNError:
|
||||||
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
|
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
|
||||||
|
|
@ -1695,7 +1727,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||||
|
|
||||||
proc genConstExpr(p: BProc, n: PNode): PRope
|
proc genConstExpr(p: BProc, n: PNode): PRope
|
||||||
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
|
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
|
||||||
if (nfAllConst in n.flags) and (d.k == locNone) and (sonsLen(n) > 0):
|
if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
|
||||||
var t = getUniqueType(n.typ)
|
var t = getUniqueType(n.typ)
|
||||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||||
|
|
@ -1827,7 +1859,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
||||||
if t.kind != tyVar: nilCheck = r
|
if t.kind != tyVar: nilCheck = r
|
||||||
r = ropef("(*$1)", [r])
|
r = ropef("(*$1)", [r])
|
||||||
t = skipTypes(t.lastSon, abstractInst)
|
t = skipTypes(t.lastSon, abstractInst)
|
||||||
if gCmd != cmdCompileToCpp:
|
if not p.module.compileToCpp:
|
||||||
while t.kind == tyObject and t.sons[0] != nil:
|
while t.kind == tyObject and t.sons[0] != nil:
|
||||||
app(r, ".Sup")
|
app(r, ".Sup")
|
||||||
t = skipTypes(t.sons[0], abstractInst)
|
t = skipTypes(t.sons[0], abstractInst)
|
||||||
|
|
@ -1845,22 +1877,38 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
||||||
[getTypeDesc(p.module, dest), addrLoc(a)]))
|
[getTypeDesc(p.module, dest), addrLoc(a)]))
|
||||||
|
|
||||||
proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
||||||
if gCmd == cmdCompileToCpp:
|
if p.module.compileToCpp:
|
||||||
expr(p, n.sons[0], d) # downcast does C++ for us
|
expr(p, n.sons[0], d) # downcast does C++ for us
|
||||||
else:
|
else:
|
||||||
var dest = skipTypes(n.typ, abstractPtrs)
|
var dest = skipTypes(n.typ, abstractPtrs)
|
||||||
var src = skipTypes(n.sons[0].typ, abstractPtrs)
|
|
||||||
|
var arg = n.sons[0]
|
||||||
|
while arg.kind == nkObjDownConv: arg = arg.sons[0]
|
||||||
|
|
||||||
|
var src = skipTypes(arg.typ, abstractPtrs)
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, n.sons[0], a)
|
initLocExpr(p, arg, a)
|
||||||
var r = rdLoc(a)
|
var r = rdLoc(a)
|
||||||
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyRef, tyPtr, tyVar} and
|
let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}
|
||||||
n.sons[0].kind notin {nkHiddenAddr, nkAddr, nkObjDownConv}:
|
if isRef:
|
||||||
app(r, "->Sup")
|
app(r, "->Sup")
|
||||||
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
|
|
||||||
r = con("&", r)
|
|
||||||
else:
|
else:
|
||||||
for i in countup(1, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
|
app(r, ".Sup")
|
||||||
putIntoDest(p, d, n.typ, r)
|
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
|
||||||
|
if isRef:
|
||||||
|
# it can happen that we end up generating '&&x->Sup' here, so we pack
|
||||||
|
# the '&x->Sup' into a temporary and then those address is taken
|
||||||
|
# (see bug #837). However sometimes using a temporary is not correct:
|
||||||
|
# init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
|
||||||
|
# this by ensuring the destination is also a pointer:
|
||||||
|
if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}:
|
||||||
|
getTemp(p, n.typ, d)
|
||||||
|
linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
|
||||||
|
else:
|
||||||
|
r = con("&", r)
|
||||||
|
putIntoDest(p, d, n.typ, r)
|
||||||
|
else:
|
||||||
|
putIntoDest(p, d, n.typ, r)
|
||||||
|
|
||||||
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
||||||
var t = getUniqueType(n.typ)
|
var t = getUniqueType(n.typ)
|
||||||
|
|
@ -1978,16 +2026,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
of nkCast: genCast(p, n, d)
|
of nkCast: genCast(p, n, d)
|
||||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
|
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
|
||||||
of nkHiddenAddr, nkAddr: genAddr(p, n, d)
|
of nkHiddenAddr, nkAddr: genAddr(p, n, d)
|
||||||
of nkBracketExpr:
|
of nkBracketExpr: genBracketExpr(p, n, d)
|
||||||
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
|
|
||||||
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
|
|
||||||
case ty.kind
|
|
||||||
of tyArray, tyArrayConstr: genArrayElem(p, n, d)
|
|
||||||
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, d)
|
|
||||||
of tySequence, tyString: genSeqElem(p, n, d)
|
|
||||||
of tyCString: genCStringElem(p, n, d)
|
|
||||||
of tyTuple: genTupleElem(p, n, d)
|
|
||||||
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
|
||||||
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
|
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
|
||||||
of nkDotExpr: genRecordField(p, n, d)
|
of nkDotExpr: genRecordField(p, n, d)
|
||||||
of nkCheckedFieldExpr: genCheckedRecordField(p, n, d)
|
of nkCheckedFieldExpr: genCheckedRecordField(p, n, d)
|
||||||
|
|
@ -2031,7 +2070,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
initLocExpr(p, n.sons[0], a)
|
initLocExpr(p, n.sons[0], a)
|
||||||
of nkAsmStmt: genAsmStmt(p, n)
|
of nkAsmStmt: genAsmStmt(p, n)
|
||||||
of nkTryStmt:
|
of nkTryStmt:
|
||||||
if gCmd == cmdCompileToCpp: genTryCpp(p, n, d)
|
if p.module.compileToCpp: genTryCpp(p, n, d)
|
||||||
else: genTry(p, n, d)
|
else: genTry(p, n, d)
|
||||||
of nkRaiseStmt: genRaiseStmt(p, n)
|
of nkRaiseStmt: genRaiseStmt(p, n)
|
||||||
of nkTypeSection:
|
of nkTypeSection:
|
||||||
|
|
@ -2043,6 +2082,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||||
nkFromStmt, nkTemplateDef, nkMacroDef:
|
nkFromStmt, nkTemplateDef, nkMacroDef:
|
||||||
discard
|
discard
|
||||||
of nkPragma: genPragma(p, n)
|
of nkPragma: genPragma(p, n)
|
||||||
|
of nkPragmaBlock: expr(p, n.lastSon, d)
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||||
if (n.sons[genericParamsPos].kind == nkEmpty):
|
if (n.sons[genericParamsPos].kind == nkEmpty):
|
||||||
var prc = n.sons[namePos].sym
|
var prc = n.sons[namePos].sym
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -83,7 +83,7 @@ proc writeTypeCache(a: TIdTable, s: var string) =
|
||||||
inc i
|
inc i
|
||||||
s.add('}')
|
s.add('}')
|
||||||
|
|
||||||
proc writeIntSet(a: TIntSet, s: var string) =
|
proc writeIntSet(a: IntSet, s: var string) =
|
||||||
var i = 0
|
var i = 0
|
||||||
for x in items(a):
|
for x in items(a):
|
||||||
if i == 10:
|
if i == 10:
|
||||||
|
|
@ -200,7 +200,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) =
|
||||||
idTablePut(result, newFakeType(key), value.toRope)
|
idTablePut(result, newFakeType(key), value.toRope)
|
||||||
inc L.bufpos
|
inc L.bufpos
|
||||||
|
|
||||||
proc readIntSet(L: var TBaseLexer, result: var TIntSet) =
|
proc readIntSet(L: var TBaseLexer, result: var IntSet) =
|
||||||
if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
|
if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
|
||||||
inc L.bufpos
|
inc L.bufpos
|
||||||
while ^L.bufpos != '}':
|
while ^L.bufpos != '}':
|
||||||
|
|
@ -249,7 +249,7 @@ proc readMergeInfo*(cfilename: string, m: BModule) =
|
||||||
break
|
break
|
||||||
|
|
||||||
type
|
type
|
||||||
TMergeSections = object {.pure.}
|
TMergeSections = object
|
||||||
f: TCFileSections
|
f: TCFileSections
|
||||||
p: TCProcSections
|
p: TCProcSections
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -46,7 +46,6 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||||
if useLowering:
|
if useLowering:
|
||||||
genStmts(p, lowerTupleUnpacking(n, p.prc))
|
genStmts(p, lowerTupleUnpacking(n, p.prc))
|
||||||
return
|
return
|
||||||
|
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
initLocExpr(p, n.sons[L-1], tup)
|
initLocExpr(p, n.sons[L-1], tup)
|
||||||
var t = tup.t
|
var t = tup.t
|
||||||
|
|
@ -69,10 +68,21 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||||
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
|
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
|
||||||
putLocIntoDest(p, v.loc, field)
|
putLocIntoDest(p, v.loc, field)
|
||||||
|
|
||||||
|
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false)
|
||||||
|
|
||||||
proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
|
proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
|
||||||
if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
|
if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or
|
||||||
ri.sons[0].sym.magic == mNone):
|
ri.sons[0].sym.magic == mNone):
|
||||||
genAsgnCall(p, le, ri, a)
|
genAsgnCall(p, le, ri, a)
|
||||||
|
elif ri.kind in {nkDerefExpr, nkHiddenDeref}:
|
||||||
|
# this is a hacky way to fix #1181 (tmissingderef)::
|
||||||
|
#
|
||||||
|
# var arr1 = cast[ptr array[4, int8]](addr foo)[]
|
||||||
|
#
|
||||||
|
# However, fixing this properly really requires modelling 'array' as
|
||||||
|
# a 'struct' in C to preserve dereferencing semantics completely. Not
|
||||||
|
# worth the effort until version 1.0 is out.
|
||||||
|
genDeref(p, ri, a, enforceDeref=true)
|
||||||
else:
|
else:
|
||||||
expr(p, ri, a)
|
expr(p, ri, a)
|
||||||
|
|
||||||
|
|
@ -294,8 +304,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||||
|
|
||||||
var alreadyPoppedCnt = p.inExceptBlock
|
var alreadyPoppedCnt = p.inExceptBlock
|
||||||
for i in countup(1, howManyTrys):
|
for i in countup(1, howManyTrys):
|
||||||
|
if not p.module.compileToCpp:
|
||||||
if gCmd != cmdCompileToCpp:
|
|
||||||
# Pop safe points generated by try
|
# Pop safe points generated by try
|
||||||
if alreadyPoppedCnt > 0:
|
if alreadyPoppedCnt > 0:
|
||||||
dec alreadyPoppedCnt
|
dec alreadyPoppedCnt
|
||||||
|
|
@ -317,7 +326,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||||
for i in countdown(howManyTrys-1, 0):
|
for i in countdown(howManyTrys-1, 0):
|
||||||
p.nestedTryStmts.add(stack[i])
|
p.nestedTryStmts.add(stack[i])
|
||||||
|
|
||||||
if gCmd != cmdCompileToCpp:
|
if not p.module.compileToCpp:
|
||||||
# Pop exceptions that was handled by the
|
# Pop exceptions that was handled by the
|
||||||
# except-blocks we are in
|
# except-blocks we are in
|
||||||
for i in countdown(howManyExcepts-1, 0):
|
for i in countdown(howManyExcepts-1, 0):
|
||||||
|
|
@ -448,7 +457,7 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) =
|
||||||
assert(t.sons[0].kind == nkSym)
|
assert(t.sons[0].kind == nkSym)
|
||||||
var sym = t.sons[0].sym
|
var sym = t.sons[0].sym
|
||||||
sym.loc.k = locOther
|
sym.loc.k = locOther
|
||||||
sym.loc.a = p.breakIdx
|
sym.position = p.breakIdx+1
|
||||||
expr(p, t.sons[1], d)
|
expr(p, t.sons[1], d)
|
||||||
endBlock(p)
|
endBlock(p)
|
||||||
|
|
||||||
|
|
@ -487,7 +496,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||||
assert(t.sons[0].kind == nkSym)
|
assert(t.sons[0].kind == nkSym)
|
||||||
var sym = t.sons[0].sym
|
var sym = t.sons[0].sym
|
||||||
assert(sym.loc.k == locOther)
|
assert(sym.loc.k == locOther)
|
||||||
idx = sym.loc.a
|
idx = sym.position-1
|
||||||
else:
|
else:
|
||||||
# an unnamed 'break' can only break a loop after 'transf' pass:
|
# an unnamed 'break' can only break a loop after 'transf' pass:
|
||||||
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
|
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
|
||||||
|
|
@ -501,8 +510,10 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||||
lineF(p, cpsStmts, "goto $1;$n", [label])
|
lineF(p, cpsStmts, "goto $1;$n", [label])
|
||||||
|
|
||||||
proc getRaiseFrmt(p: BProc): string =
|
proc getRaiseFrmt(p: BProc): string =
|
||||||
if gCmd == cmdCompileToCpp:
|
if p.module.compileToCpp:
|
||||||
result = "throw NimException($1, $2);$n"
|
result = "throw NimException($1, $2);$n"
|
||||||
|
elif getCompilerProc("Exception") != nil:
|
||||||
|
result = "#raiseException((#Exception*)$1, $2);$n"
|
||||||
else:
|
else:
|
||||||
result = "#raiseException((#E_Base*)$1, $2);$n"
|
result = "#raiseException((#E_Base*)$1, $2);$n"
|
||||||
|
|
||||||
|
|
@ -520,10 +531,10 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||||
var typ = skipTypes(t.sons[0].typ, abstractPtrs)
|
var typ = skipTypes(t.sons[0].typ, abstractPtrs)
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)])
|
lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)])
|
||||||
else:
|
else:
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
# reraise the last exception:
|
# reraise the last exception:
|
||||||
if gCmd == cmdCompileToCpp:
|
if p.module.compileToCpp:
|
||||||
line(p, cpsStmts, ~"throw;$n")
|
line(p, cpsStmts, ~"throw;$n")
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts, "#reraiseException();$n")
|
linefmt(p, cpsStmts, "#reraiseException();$n")
|
||||||
|
|
@ -559,7 +570,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||||
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||||
rangeFormat, eqFormat: TFormatStr,
|
rangeFormat, eqFormat: TFormatStr,
|
||||||
until: int, a: TLoc): TLabel =
|
until: int, a: TLoc): TLabel =
|
||||||
# generate a C-if statement for a Nimrod case statement
|
# generate a C-if statement for a Nim case statement
|
||||||
var labId = p.labels
|
var labId = p.labels
|
||||||
for i in 1..until:
|
for i in 1..until:
|
||||||
inc(p.labels)
|
inc(p.labels)
|
||||||
|
|
@ -747,7 +758,10 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
i, length, blen: int
|
i, length, blen: int
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
exc = getTempName()
|
exc = getTempName()
|
||||||
discard cgsym(p.module, "E_Base")
|
if getCompilerProc("Exception") != nil:
|
||||||
|
discard cgsym(p.module, "Exception")
|
||||||
|
else:
|
||||||
|
discard cgsym(p.module, "E_Base")
|
||||||
add(p.nestedTryStmts, t)
|
add(p.nestedTryStmts, t)
|
||||||
startBlock(p, "try {$n")
|
startBlock(p, "try {$n")
|
||||||
expr(p, t.sons[0], d)
|
expr(p, t.sons[0], d)
|
||||||
|
|
@ -784,7 +798,9 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
startBlock(p)
|
startBlock(p)
|
||||||
var finallyBlock = t.lastSon
|
var finallyBlock = t.lastSon
|
||||||
if finallyBlock.kind == nkFinally:
|
if finallyBlock.kind == nkFinally:
|
||||||
expr(p, finallyBlock.sons[0], d)
|
#expr(p, finallyBlock.sons[0], d)
|
||||||
|
genStmts(p, finallyBlock.sons[0])
|
||||||
|
|
||||||
line(p, cpsStmts, ~"throw;$n")
|
line(p, cpsStmts, ~"throw;$n")
|
||||||
endBlock(p)
|
endBlock(p)
|
||||||
|
|
||||||
|
|
@ -793,7 +809,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||||
|
|
||||||
discard pop(p.nestedTryStmts)
|
discard pop(p.nestedTryStmts)
|
||||||
if (i < length) and (t.sons[i].kind == nkFinally):
|
if (i < length) and (t.sons[i].kind == nkFinally):
|
||||||
exprBlock(p, t.sons[i].sons[0], d)
|
genSimpleBlock(p, t.sons[i].sons[0])
|
||||||
|
|
||||||
proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||||
# code to generate:
|
# code to generate:
|
||||||
|
|
@ -829,7 +845,10 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||||
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
|
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
|
||||||
genLineDir(p, t)
|
genLineDir(p, t)
|
||||||
var safePoint = getTempName()
|
var safePoint = getTempName()
|
||||||
discard cgsym(p.module, "E_Base")
|
if getCompilerProc("Exception") != nil:
|
||||||
|
discard cgsym(p.module, "Exception")
|
||||||
|
else:
|
||||||
|
discard cgsym(p.module, "E_Base")
|
||||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
||||||
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
||||||
if isDefined("nimStdSetjmp"):
|
if isDefined("nimStdSetjmp"):
|
||||||
|
|
@ -882,7 +901,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||||
endBlock(p) # end of else block
|
endBlock(p) # end of else block
|
||||||
if i < length and t.sons[i].kind == nkFinally:
|
if i < length and t.sons[i].kind == nkFinally:
|
||||||
p.finallySafePoints.add(safePoint)
|
p.finallySafePoints.add(safePoint)
|
||||||
exprBlock(p, t.sons[i].sons[0], d)
|
genSimpleBlock(p, t.sons[i].sons[0])
|
||||||
discard pop(p.finallySafePoints)
|
discard pop(p.finallySafePoints)
|
||||||
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
|
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", safePoint)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -57,6 +57,9 @@ proc generateThreadLocalStorage(m: BModule) =
|
||||||
|
|
||||||
proc generateThreadVarsSize(m: BModule) =
|
proc generateThreadVarsSize(m: BModule) =
|
||||||
if nimtv != nil:
|
if nimtv != nil:
|
||||||
app(m.s[cfsProcs],
|
let externc = if gCmd != cmdCompileToCpp and
|
||||||
"NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}" & tnl)
|
sfCompileToCpp in m.module.flags: "extern \"C\""
|
||||||
|
else: ""
|
||||||
|
appf(m.s[cfsProcs],
|
||||||
|
"$#NI NimThreadVarsSize(){return (NI)sizeof(NimThreadVars);}$n",
|
||||||
|
[externc.toRope])
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -49,8 +49,8 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) =
|
||||||
genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
|
genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t)
|
||||||
else: internalError(n.info, "genTraverseProc()")
|
else: internalError(n.info, "genTraverseProc()")
|
||||||
|
|
||||||
proc parentObj(accessor: PRope): PRope {.inline.} =
|
proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} =
|
||||||
if gCmd != cmdCompileToCpp:
|
if not m.compileToCpp:
|
||||||
result = ropef("$1.Sup", accessor)
|
result = ropef("$1.Sup", accessor)
|
||||||
else:
|
else:
|
||||||
result = accessor
|
result = accessor
|
||||||
|
|
@ -71,7 +71,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||||
lineF(p, cpsStmts, "}$n")
|
lineF(p, cpsStmts, "}$n")
|
||||||
of tyObject:
|
of tyObject:
|
||||||
for i in countup(0, sonsLen(typ) - 1):
|
for i in countup(0, sonsLen(typ) - 1):
|
||||||
genTraverseProc(c, accessor.parentObj, typ.sons[i])
|
genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i])
|
||||||
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
|
if typ.n != nil: genTraverseProc(c, accessor, typ.n)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
let typ = getUniqueType(typ)
|
let typ = getUniqueType(typ)
|
||||||
|
|
@ -91,7 +91,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) =
|
||||||
var i: TLoc
|
var i: TLoc
|
||||||
getTemp(p, getSysType(tyInt), i)
|
getTemp(p, getSysType(tyInt), i)
|
||||||
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
|
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
|
||||||
i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len"))
|
i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len"))
|
||||||
genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
|
genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0])
|
||||||
lineF(p, cpsStmts, "}$n")
|
lineF(p, cpsStmts, "}$n")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -162,10 +162,14 @@ proc mapReturnType(typ: PType): TCTypeKind =
|
||||||
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
||||||
else: result = mapType(typ)
|
else: result = mapType(typ)
|
||||||
|
|
||||||
proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope
|
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
|
||||||
proc needsComplexAssignment(typ: PType): bool =
|
proc needsComplexAssignment(typ: PType): bool =
|
||||||
result = containsGarbageCollectedRef(typ)
|
result = containsGarbageCollectedRef(typ)
|
||||||
|
|
||||||
|
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
||||||
|
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
||||||
|
(typ.sons[0] == nil) or isPureObject(typ))
|
||||||
|
|
||||||
proc isInvalidReturnType(rettype: PType): bool =
|
proc isInvalidReturnType(rettype: PType): bool =
|
||||||
# Arrays and sets cannot be returned by a C procedure, because C is
|
# Arrays and sets cannot be returned by a C procedure, because C is
|
||||||
# such a poor programming language.
|
# such a poor programming language.
|
||||||
|
|
@ -177,10 +181,12 @@ proc isInvalidReturnType(rettype: PType): bool =
|
||||||
of ctArray:
|
of ctArray:
|
||||||
result = not (skipTypes(rettype, typedescInst).kind in
|
result = not (skipTypes(rettype, typedescInst).kind in
|
||||||
{tyVar, tyRef, tyPtr})
|
{tyVar, tyRef, tyPtr})
|
||||||
of ctStruct:
|
of ctStruct:
|
||||||
result = needsComplexAssignment(skipTypes(rettype, typedescInst))
|
let t = skipTypes(rettype, typedescInst)
|
||||||
|
result = needsComplexAssignment(t) or
|
||||||
|
(t.kind == tyObject and not isObjLackingTypeField(t))
|
||||||
else: result = false
|
else: result = false
|
||||||
|
|
||||||
const
|
const
|
||||||
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
|
CallingConvToStr: array[TCallingConvention, string] = ["N_NIMCALL",
|
||||||
"N_STDCALL", "N_CDECL", "N_SAFECALL",
|
"N_STDCALL", "N_CDECL", "N_SAFECALL",
|
||||||
|
|
@ -228,7 +234,7 @@ proc fillResult(param: PSym) =
|
||||||
incl(param.loc.flags, lfIndirect)
|
incl(param.loc.flags, lfIndirect)
|
||||||
param.loc.s = OnUnknown
|
param.loc.s = OnUnknown
|
||||||
|
|
||||||
proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope =
|
proc getParamTypeDesc(m: BModule, t: PType, check: var IntSet): PRope =
|
||||||
when false:
|
when false:
|
||||||
if t.Kind in {tyRef, tyPtr, tyVar}:
|
if t.Kind in {tyRef, tyPtr, tyVar}:
|
||||||
var b = skipTypes(t.lastson, typedescInst)
|
var b = skipTypes(t.lastson, typedescInst)
|
||||||
|
|
@ -243,7 +249,7 @@ proc paramStorageLoc(param: PSym): TStorageLoc =
|
||||||
result = OnUnknown
|
result = OnUnknown
|
||||||
|
|
||||||
proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||||
check: var TIntSet, declareEnvironment=true) =
|
check: var IntSet, declareEnvironment=true) =
|
||||||
params = nil
|
params = nil
|
||||||
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
|
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
|
||||||
rettype = ~"void"
|
rettype = ~"void"
|
||||||
|
|
@ -330,7 +336,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
|
||||||
of tyNil: result = typeNameOrLiteral(typ, "0")
|
of tyNil: result = typeNameOrLiteral(typ, "0")
|
||||||
of tyInt..tyUInt64:
|
of tyInt..tyUInt64:
|
||||||
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
|
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
|
||||||
of tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
|
of tyDistinct, tyRange: result = getSimpleTypeDesc(m, typ.sons[0])
|
||||||
else: result = nil
|
else: result = nil
|
||||||
|
|
||||||
proc getTypePre(m: BModule, typ: PType): PRope =
|
proc getTypePre(m: BModule, typ: PType): PRope =
|
||||||
|
|
@ -342,8 +348,8 @@ proc getTypePre(m: BModule, typ: PType): PRope =
|
||||||
proc structOrUnion(t: PType): PRope =
|
proc structOrUnion(t: PType): PRope =
|
||||||
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
|
(if tfUnion in t.flags: toRope("union") else: toRope("struct"))
|
||||||
|
|
||||||
proc getForwardStructFormat(): string =
|
proc getForwardStructFormat(m: BModule): string =
|
||||||
if gCmd == cmdCompileToCpp: result = "$1 $2;$n"
|
if m.compileToCpp: result = "$1 $2;$n"
|
||||||
else: result = "typedef $1 $2 $2;$n"
|
else: result = "typedef $1 $2 $2;$n"
|
||||||
|
|
||||||
proc getTypeForward(m: BModule, typ: PType): PRope =
|
proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||||
|
|
@ -355,7 +361,7 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||||
of tySequence, tyTuple, tyObject:
|
of tySequence, tyTuple, tyObject:
|
||||||
result = getTypeName(typ)
|
result = getTypeName(typ)
|
||||||
if not isImportedType(typ):
|
if not isImportedType(typ):
|
||||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||||
[structOrUnion(typ), result])
|
[structOrUnion(typ), result])
|
||||||
idTablePut(m.forwTypeCache, typ, result)
|
idTablePut(m.forwTypeCache, typ, result)
|
||||||
else: internalError("getTypeForward(" & $typ.kind & ')')
|
else: internalError("getTypeForward(" & $typ.kind & ')')
|
||||||
|
|
@ -370,7 +376,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
|
||||||
|
|
||||||
proc genRecordFieldsAux(m: BModule, n: PNode,
|
proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
accessExpr: PRope, rectype: PType,
|
accessExpr: PRope, rectype: PType,
|
||||||
check: var TIntSet): PRope =
|
check: var IntSet): PRope =
|
||||||
var
|
var
|
||||||
ae, uname, sname, a: PRope
|
ae, uname, sname, a: PRope
|
||||||
k: PNode
|
k: PNode
|
||||||
|
|
@ -419,19 +425,19 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
|
appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname])
|
||||||
else: internalError(n.info, "genRecordFieldsAux()")
|
else: internalError(n.info, "genRecordFieldsAux()")
|
||||||
|
|
||||||
proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope =
|
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||||
result = genRecordFieldsAux(m, typ.n, nil, typ, check)
|
result = genRecordFieldsAux(m, typ.n, nil, typ, check)
|
||||||
|
|
||||||
proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||||
check: var TIntSet): PRope =
|
check: var IntSet): PRope =
|
||||||
# declare the record:
|
# declare the record:
|
||||||
var hasField = false
|
var hasField = false
|
||||||
|
|
||||||
var attribute: PRope =
|
var attribute: PRope =
|
||||||
if tfPacked in typ.flags: toRope(CC[ccompiler].packedPragma)
|
if tfPacked in typ.flags: toRope(CC[cCompiler].packedPragma)
|
||||||
else: nil
|
else: nil
|
||||||
|
|
||||||
result = ropecg(m, CC[ccompiler].structStmtFmt,
|
result = ropecg(m, CC[cCompiler].structStmtFmt,
|
||||||
[structOrUnion(typ), name, attribute])
|
[structOrUnion(typ), name, attribute])
|
||||||
|
|
||||||
if typ.kind == tyObject:
|
if typ.kind == tyObject:
|
||||||
|
|
@ -442,7 +448,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||||
else:
|
else:
|
||||||
appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
|
appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute])
|
||||||
hasField = true
|
hasField = true
|
||||||
elif gCmd == cmdCompileToCpp:
|
elif m.compileToCpp:
|
||||||
appcg(m, result, " : public $1 {$n",
|
appcg(m, result, " : public $1 {$n",
|
||||||
[getTypeDescAux(m, typ.sons[0], check)])
|
[getTypeDescAux(m, typ.sons[0], check)])
|
||||||
hasField = true
|
hasField = true
|
||||||
|
|
@ -461,7 +467,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope,
|
||||||
app(result, "};" & tnl)
|
app(result, "};" & tnl)
|
||||||
|
|
||||||
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
||||||
check: var TIntSet): PRope =
|
check: var IntSet): PRope =
|
||||||
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
|
result = ropef("$1 $2 {$n", [structOrUnion(typ), name])
|
||||||
var desc: PRope = nil
|
var desc: PRope = nil
|
||||||
for i in countup(0, sonsLen(typ) - 1):
|
for i in countup(0, sonsLen(typ) - 1):
|
||||||
|
|
@ -474,7 +480,7 @@ proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
||||||
proc pushType(m: BModule, typ: PType) =
|
proc pushType(m: BModule, typ: PType) =
|
||||||
add(m.typeStack, typ)
|
add(m.typeStack, typ)
|
||||||
|
|
||||||
proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||||
# returns only the type's name
|
# returns only the type's name
|
||||||
var
|
var
|
||||||
name, rettype, desc, recdesc: PRope
|
name, rettype, desc, recdesc: PRope
|
||||||
|
|
@ -538,7 +544,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = getTypeName(t)
|
result = getTypeName(t)
|
||||||
if not isImportedType(t):
|
if not isImportedType(t):
|
||||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||||
[structOrUnion(t), result])
|
[structOrUnion(t), result])
|
||||||
idTablePut(m.forwTypeCache, t, result)
|
idTablePut(m.forwTypeCache, t, result)
|
||||||
assert(cacheGetType(m.typeCache, t) == nil)
|
assert(cacheGetType(m.typeCache, t) == nil)
|
||||||
|
|
@ -550,7 +556,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||||
cSeq = "struct $2 {$n" &
|
cSeq = "struct $2 {$n" &
|
||||||
" #TGenericSeq Sup;$n"
|
" #TGenericSeq Sup;$n"
|
||||||
appcg(m, m.s[cfsSeqTypes],
|
appcg(m, m.s[cfsSeqTypes],
|
||||||
(if gCmd == cmdCompileToCpp: cppSeq else: cSeq) &
|
(if m.compileToCpp: cppSeq else: cSeq) &
|
||||||
" $1 data[SEQ_DECL_SIZE];$n" &
|
" $1 data[SEQ_DECL_SIZE];$n" &
|
||||||
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
|
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
|
||||||
else:
|
else:
|
||||||
|
|
@ -570,7 +576,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope =
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = getTypeName(t)
|
result = getTypeName(t)
|
||||||
if not isImportedType(t):
|
if not isImportedType(t):
|
||||||
appf(m.s[cfsForwardTypes], getForwardStructFormat(),
|
appf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||||
[structOrUnion(t), result])
|
[structOrUnion(t), result])
|
||||||
idTablePut(m.forwTypeCache, t, result)
|
idTablePut(m.forwTypeCache, t, result)
|
||||||
idTablePut(m.typeCache, t, result) # always call for sideeffects:
|
idTablePut(m.typeCache, t, result) # always call for sideeffects:
|
||||||
|
|
@ -678,10 +684,6 @@ when false:
|
||||||
var tmp = getNimType(m)
|
var tmp = getNimType(m)
|
||||||
appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name])
|
appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name])
|
||||||
|
|
||||||
proc isObjLackingTypeField(typ: PType): bool {.inline.} =
|
|
||||||
result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and
|
|
||||||
(typ.sons[0] == nil) or isPureObject(typ))
|
|
||||||
|
|
||||||
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
||||||
var nimtypeKind: int
|
var nimtypeKind: int
|
||||||
#allocMemTI(m, typ, name)
|
#allocMemTI(m, typ, name)
|
||||||
|
|
@ -898,7 +900,7 @@ include ccgtrav
|
||||||
|
|
||||||
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
|
proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) =
|
||||||
genProc(m, s)
|
genProc(m, s)
|
||||||
appf(m.s[cfsTypeInit3], "$1.deepcopy = (N_NIMCALL_PTR(void*, void*)) $2;$n",
|
appf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n",
|
||||||
[result, s.loc.r])
|
[result, s.loc.r])
|
||||||
|
|
||||||
proc genTypeInfo(m: BModule, t: PType): PRope =
|
proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -149,7 +149,7 @@ proc getUniqueType*(key: PType): PType =
|
||||||
idTablePut(gTypeTable[k], key, key)
|
idTablePut(gTypeTable[k], key, key)
|
||||||
result = key
|
result = key
|
||||||
|
|
||||||
proc tableGetType*(tab: TIdTable, key: PType): PObject =
|
proc tableGetType*(tab: TIdTable, key: PType): RootRef =
|
||||||
# returns nil if we need to declare this type
|
# returns nil if we need to declare this type
|
||||||
result = idTableGet(tab, key)
|
result = idTableGet(tab, key)
|
||||||
if (result == nil) and (tab.counter > 0):
|
if (result == nil) and (tab.counter > 0):
|
||||||
|
|
@ -171,7 +171,7 @@ proc mangle*(name: string): string =
|
||||||
## Lowercases the given name and manges any non-alphanumeric characters
|
## Lowercases the given name and manges any non-alphanumeric characters
|
||||||
## so they are represented as `HEX____`. If the name starts with a number,
|
## so they are represented as `HEX____`. If the name starts with a number,
|
||||||
## `N` is prepended
|
## `N` is prepended
|
||||||
result = ""
|
result = newStringOfCap(name.len)
|
||||||
case name[0]
|
case name[0]
|
||||||
of Letters:
|
of Letters:
|
||||||
result.add(name[0].toLower)
|
result.add(name[0].toLower)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -55,7 +55,6 @@ proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
|
||||||
result.s = s
|
result.s = s
|
||||||
result.t = getUniqueType(typ)
|
result.t = getUniqueType(typ)
|
||||||
result.r = nil
|
result.r = nil
|
||||||
result.a = - 1
|
|
||||||
result.flags = {}
|
result.flags = {}
|
||||||
|
|
||||||
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
|
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
|
||||||
|
|
@ -63,7 +62,6 @@ proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) =
|
||||||
if a.k == locNone:
|
if a.k == locNone:
|
||||||
a.k = k
|
a.k = k
|
||||||
a.t = getUniqueType(typ)
|
a.t = getUniqueType(typ)
|
||||||
a.a = - 1
|
|
||||||
a.s = s
|
a.s = s
|
||||||
if a.r == nil: a.r = r
|
if a.r == nil: a.r = r
|
||||||
|
|
||||||
|
|
@ -139,7 +137,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||||
if i - 1 >= start:
|
if i - 1 >= start:
|
||||||
app(result, substr(frmt, start, i - 1))
|
app(result, substr(frmt, start, i - 1))
|
||||||
|
|
||||||
const compileTimeRopeFmt = not defined(booting)
|
const compileTimeRopeFmt = false
|
||||||
|
|
||||||
when compileTimeRopeFmt:
|
when compileTimeRopeFmt:
|
||||||
import macros
|
import macros
|
||||||
|
|
@ -186,7 +184,7 @@ when compileTimeRopeFmt:
|
||||||
while s[i] in IdentChars: inc i
|
while s[i] in IdentChars: inc i
|
||||||
yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0)
|
yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0)
|
||||||
start = i
|
start = i
|
||||||
else: nil
|
else: discard
|
||||||
|
|
||||||
while i < length:
|
while i < length:
|
||||||
if s[i] != '$' and s[i] != '#': inc i
|
if s[i] != '$' and s[i] != '#': inc i
|
||||||
|
|
@ -201,7 +199,7 @@ when compileTimeRopeFmt:
|
||||||
## the compilation of nimrod itself or will the macro execution time
|
## the compilation of nimrod itself or will the macro execution time
|
||||||
## offset the gains?
|
## offset the gains?
|
||||||
result = newCall(bindSym"ropeConcat")
|
result = newCall(bindSym"ropeConcat")
|
||||||
for frag in fmtStringFragments(fmt.strVal):
|
for frag in fmtStringFragments(fmt):
|
||||||
case frag.kind
|
case frag.kind
|
||||||
of ffSym:
|
of ffSym:
|
||||||
result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value)))
|
result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value)))
|
||||||
|
|
@ -286,7 +284,7 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||||
line.toRope, makeCString(toFilename(t.info)))
|
line.toRope, makeCString(toFilename(t.info)))
|
||||||
elif ({optLineTrace, optStackTrace} * p.options ==
|
elif ({optLineTrace, optStackTrace} * p.options ==
|
||||||
{optLineTrace, optStackTrace}) and
|
{optLineTrace, optStackTrace}) and
|
||||||
(p.prc == nil or sfPure notin p.prc.flags):
|
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0:
|
||||||
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
linefmt(p, cpsStmts, "nimln($1, $2);$n",
|
||||||
line.toRope, t.info.quotedFilename)
|
line.toRope, t.info.quotedFilename)
|
||||||
|
|
||||||
|
|
@ -297,6 +295,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||||
proc emulatedThreadVars(): bool {.inline.}
|
proc emulatedThreadVars(): bool {.inline.}
|
||||||
proc genProc(m: BModule, prc: PSym)
|
proc genProc(m: BModule, prc: PSym)
|
||||||
|
|
||||||
|
template compileToCpp(m: BModule): expr =
|
||||||
|
gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
|
||||||
|
|
||||||
include "ccgtypes.nim"
|
include "ccgtypes.nim"
|
||||||
|
|
||||||
# ------------------------------ Manager of temporaries ------------------
|
# ------------------------------ Manager of temporaries ------------------
|
||||||
|
|
@ -309,7 +310,7 @@ proc rdLoc(a: TLoc): PRope =
|
||||||
proc addrLoc(a: TLoc): PRope =
|
proc addrLoc(a: TLoc): PRope =
|
||||||
result = a.r
|
result = a.r
|
||||||
if lfIndirect notin a.flags and mapType(a.t) != ctArray:
|
if lfIndirect notin a.flags and mapType(a.t) != ctArray:
|
||||||
result = con("&", result)
|
result = con("(&", result).con(")")
|
||||||
|
|
||||||
proc rdCharLoc(a: TLoc): PRope =
|
proc rdCharLoc(a: TLoc): PRope =
|
||||||
# read a location that may need a char-cast:
|
# read a location that may need a char-cast:
|
||||||
|
|
@ -326,7 +327,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||||
var r = rdLoc(a)
|
var r = rdLoc(a)
|
||||||
if not takeAddr: r = ropef("(*$1)", [r])
|
if not takeAddr: r = ropef("(*$1)", [r])
|
||||||
var s = skipTypes(t, abstractInst)
|
var s = skipTypes(t, abstractInst)
|
||||||
if gCmd != cmdCompileToCpp:
|
if not p.module.compileToCpp:
|
||||||
while (s.kind == tyObject) and (s.sons[0] != nil):
|
while (s.kind == tyObject) and (s.sons[0] != nil):
|
||||||
app(r, ".Sup")
|
app(r, ".Sup")
|
||||||
s = skipTypes(s.sons[0], abstractInst)
|
s = skipTypes(s.sons[0], abstractInst)
|
||||||
|
|
@ -407,7 +408,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||||
result.r = con("LOC", toRope(p.labels))
|
result.r = con("LOC", toRope(p.labels))
|
||||||
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
||||||
result.k = locTemp
|
result.k = locTemp
|
||||||
result.a = - 1
|
#result.a = - 1
|
||||||
result.t = getUniqueType(t)
|
result.t = getUniqueType(t)
|
||||||
result.s = OnStack
|
result.s = OnStack
|
||||||
result.flags = {}
|
result.flags = {}
|
||||||
|
|
@ -425,7 +426,7 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
||||||
[getTypeDesc(p.module, toKeepAlive.t), fid])
|
[getTypeDesc(p.module, toKeepAlive.t), fid])
|
||||||
inc(p.gcFrameId)
|
inc(p.gcFrameId)
|
||||||
result.k = locTemp
|
result.k = locTemp
|
||||||
result.a = -1
|
#result.a = -1
|
||||||
result.t = toKeepAlive.t
|
result.t = toKeepAlive.t
|
||||||
result.s = OnStack
|
result.s = OnStack
|
||||||
result.flags = {}
|
result.flags = {}
|
||||||
|
|
@ -505,9 +506,7 @@ proc assignLocalVar(p: BProc, s: PSym) =
|
||||||
if sfRegister in s.flags: app(decl, " register")
|
if sfRegister in s.flags: app(decl, " register")
|
||||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||||
# app(decl, " GC_GUARD")
|
# app(decl, " GC_GUARD")
|
||||||
if sfVolatile in s.flags or (p.nestedTryStmts.len > 0 and
|
if sfVolatile in s.flags: app(decl, " volatile")
|
||||||
gCmd != cmdCompileToCpp):
|
|
||||||
app(decl, " volatile")
|
|
||||||
appf(decl, " $1;$n", [s.loc.r])
|
appf(decl, " $1;$n", [s.loc.r])
|
||||||
else:
|
else:
|
||||||
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
|
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
|
||||||
|
|
@ -587,8 +586,8 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
|
||||||
initLoc(result, locNone, e.typ, OnUnknown)
|
initLoc(result, locNone, e.typ, OnUnknown)
|
||||||
expr(p, e, result)
|
expr(p, e, result)
|
||||||
|
|
||||||
proc lenField: PRope {.inline.} =
|
proc lenField(p: BProc): PRope =
|
||||||
result = toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len")
|
result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
|
||||||
|
|
||||||
include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
|
include ccgcalls, "ccgstmts.nim", "ccgexprs.nim"
|
||||||
|
|
||||||
|
|
@ -812,7 +811,12 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||||
app(generatedProc, returnStmt)
|
app(generatedProc, returnStmt)
|
||||||
app(generatedProc, ~"}$N")
|
app(generatedProc, ~"}$N")
|
||||||
app(m.s[cfsProcs], generatedProc)
|
app(m.s[cfsProcs], generatedProc)
|
||||||
|
|
||||||
|
proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} =
|
||||||
|
result = sfCompileToCpp in m.module.flags and
|
||||||
|
sfCompileToCpp notin sym.getModule().flags and
|
||||||
|
gCmd != cmdCompileToCpp
|
||||||
|
|
||||||
proc genProcPrototype(m: BModule, sym: PSym) =
|
proc genProcPrototype(m: BModule, sym: PSym) =
|
||||||
useHeader(m, sym)
|
useHeader(m, sym)
|
||||||
if lfNoDecl in sym.loc.flags: return
|
if lfNoDecl in sym.loc.flags: return
|
||||||
|
|
@ -824,6 +828,8 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
||||||
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
|
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
|
||||||
elif not containsOrIncl(m.declaredProtos, sym.id):
|
elif not containsOrIncl(m.declaredProtos, sym.id):
|
||||||
var header = genProcHeader(m, sym)
|
var header = genProcHeader(m, sym)
|
||||||
|
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
|
||||||
|
header = con("extern \"C\" ", header)
|
||||||
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
|
if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props:
|
||||||
header.app(" __attribute__((naked))")
|
header.app(" __attribute__((naked))")
|
||||||
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
|
app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
|
||||||
|
|
@ -915,30 +921,30 @@ proc addIntTypes(result: var PRope) {.inline.} =
|
||||||
appf(result, "#define NIM_INTBITS $1", [
|
appf(result, "#define NIM_INTBITS $1", [
|
||||||
platform.CPU[targetCPU].intSize.toRope])
|
platform.CPU[targetCPU].intSize.toRope])
|
||||||
|
|
||||||
proc getCopyright(cfilenoext: string): PRope =
|
proc getCopyright(cfile: string): PRope =
|
||||||
if optCompileOnly in gGlobalOptions:
|
if optCompileOnly in gGlobalOptions:
|
||||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
|
result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
|
||||||
"/* (c) 2014 Andreas Rumpf */$N" &
|
"/* (c) 2014 Andreas Rumpf */$N" &
|
||||||
"/* The generated code is subject to the original license. */$N",
|
"/* The generated code is subject to the original license. */$N",
|
||||||
"; Generated by Nimrod Compiler v$1$N" &
|
"; Generated by Nim Compiler v$1$N" &
|
||||||
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
|
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
|
||||||
else:
|
else:
|
||||||
result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" &
|
result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
|
||||||
"/* (c) 2014 Andreas Rumpf */$N" &
|
"/* (c) 2014 Andreas Rumpf */$N" &
|
||||||
"/* The generated code is subject to the original license. */$N" &
|
"/* The generated code is subject to the original license. */$N" &
|
||||||
"/* Compiled for: $2, $3, $4 */$N" &
|
"/* Compiled for: $2, $3, $4 */$N" &
|
||||||
"/* Command for C compiler:$n $5 */$N",
|
"/* Command for C compiler:$n $5 */$N",
|
||||||
"; Generated by Nimrod Compiler v$1$N" &
|
"; Generated by Nim Compiler v$1$N" &
|
||||||
"; (c) 2014 Andreas Rumpf$N" &
|
"; (c) 2014 Andreas Rumpf$N" &
|
||||||
"; Compiled for: $2, $3, $4$N" &
|
"; Compiled for: $2, $3, $4$N" &
|
||||||
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
|
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
|
||||||
toRope(platform.OS[targetOS].name),
|
toRope(platform.OS[targetOS].name),
|
||||||
toRope(platform.CPU[targetCPU].name),
|
toRope(platform.CPU[targetCPU].name),
|
||||||
toRope(extccomp.CC[extccomp.cCompiler].name),
|
toRope(extccomp.CC[extccomp.cCompiler].name),
|
||||||
toRope(getCompileCFileCmd(cfilenoext))])
|
toRope(getCompileCFileCmd(cfile))])
|
||||||
|
|
||||||
proc getFileHeader(cfilenoext: string): PRope =
|
proc getFileHeader(cfile: string): PRope =
|
||||||
result = getCopyright(cfilenoext)
|
result = getCopyright(cfile)
|
||||||
addIntTypes(result)
|
addIntTypes(result)
|
||||||
|
|
||||||
proc genFilenames(m: BModule): PRope =
|
proc genFilenames(m: BModule): PRope =
|
||||||
|
|
@ -963,7 +969,7 @@ proc genMainProc(m: BModule) =
|
||||||
"\tvoid (*volatile inner)();$N" &
|
"\tvoid (*volatile inner)();$N" &
|
||||||
"\tsystemDatInit();$N" &
|
"\tsystemDatInit();$N" &
|
||||||
"\tinner = PreMainInner;$N" &
|
"\tinner = PreMainInner;$N" &
|
||||||
"$4" &
|
"$4$5" &
|
||||||
"\t(*inner)();$N" &
|
"\t(*inner)();$N" &
|
||||||
"}$N$N"
|
"}$N$N"
|
||||||
|
|
||||||
|
|
@ -1051,12 +1057,16 @@ proc genMainProc(m: BModule) =
|
||||||
gBreakpoints.app(m.genFilenames)
|
gBreakpoints.app(m.genFilenames)
|
||||||
|
|
||||||
let initStackBottomCall =
|
let initStackBottomCall =
|
||||||
if emulatedThreadVars() or
|
if platform.targetOS == osStandalone: "".toRope
|
||||||
platform.targetOS == osStandalone: "".toRope
|
|
||||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
|
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
|
||||||
inc(m.labels)
|
inc(m.labels)
|
||||||
appcg(m, m.s[cfsProcs], PreMainBody, [
|
appcg(m, m.s[cfsProcs], PreMainBody, [
|
||||||
mainDatInit, gBreakpoints, otherModsInit, initStackBottomCall])
|
mainDatInit, gBreakpoints, otherModsInit,
|
||||||
|
if emulatedThreadVars() and platform.targetOS != osStandalone:
|
||||||
|
ropecg(m, "\t#initThreadVarsEmulation();$N")
|
||||||
|
else:
|
||||||
|
"".toRope,
|
||||||
|
initStackBottomCall])
|
||||||
|
|
||||||
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, toRope(m.labels)])
|
appcg(m, m.s[cfsProcs], nimMain, [mainModInit, initStackBottomCall, toRope(m.labels)])
|
||||||
if optNoMain notin gGlobalOptions:
|
if optNoMain notin gGlobalOptions:
|
||||||
|
|
@ -1078,9 +1088,9 @@ proc registerModuleToMain(m: PSym) =
|
||||||
var
|
var
|
||||||
init = m.getInitName
|
init = m.getInitName
|
||||||
datInit = m.getDatInitName
|
datInit = m.getDatInitName
|
||||||
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
|
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
|
||||||
"declare void $1() noinline$N", [init])
|
"declare void $1() noinline$N", [init])
|
||||||
appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N",
|
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
|
||||||
"declare void $1() noinline$N", [datInit])
|
"declare void $1() noinline$N", [datInit])
|
||||||
if sfSystemModule notin m.flags:
|
if sfSystemModule notin m.flags:
|
||||||
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
|
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
|
||||||
|
|
@ -1092,7 +1102,7 @@ proc registerModuleToMain(m: PSym) =
|
||||||
|
|
||||||
proc genInitCode(m: BModule) =
|
proc genInitCode(m: BModule) =
|
||||||
var initname = getInitName(m.module)
|
var initname = getInitName(m.module)
|
||||||
var prc = ropeff("N_NOINLINE(void, $1)(void) {$N",
|
var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||||
"define void $1() noinline {$n", [initname])
|
"define void $1() noinline {$n", [initname])
|
||||||
if m.typeNodes > 0:
|
if m.typeNodes > 0:
|
||||||
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
||||||
|
|
@ -1135,7 +1145,7 @@ proc genInitCode(m: BModule) =
|
||||||
app(prc, deinitGCFrame(m.initProc))
|
app(prc, deinitGCFrame(m.initProc))
|
||||||
appf(prc, "}$N$N")
|
appf(prc, "}$N$N")
|
||||||
|
|
||||||
prc.appff("N_NOINLINE(void, $1)(void) {$N",
|
prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||||
"define void $1() noinline {$n", [getDatInitName(m.module)])
|
"define void $1() noinline {$n", [getDatInitName(m.module)])
|
||||||
|
|
||||||
for i in cfsTypeInit1..cfsDynLibInit:
|
for i in cfsTypeInit1..cfsDynLibInit:
|
||||||
|
|
@ -1155,8 +1165,8 @@ proc genInitCode(m: BModule) =
|
||||||
(i.ord - '0'.ord).toRope, el)
|
(i.ord - '0'.ord).toRope, el)
|
||||||
app(m.s[cfsInitProc], ex)
|
app(m.s[cfsInitProc], ex)
|
||||||
|
|
||||||
proc genModule(m: BModule, cfilenoext: string): PRope =
|
proc genModule(m: BModule, cfile: string): PRope =
|
||||||
result = getFileHeader(cfilenoext)
|
result = getFileHeader(cfile)
|
||||||
result.app(genMergeInfo(m))
|
result.app(genMergeInfo(m))
|
||||||
|
|
||||||
generateHeaders(m)
|
generateHeaders(m)
|
||||||
|
|
@ -1297,7 +1307,11 @@ proc writeHeader(m: BModule) =
|
||||||
writeRope(result, m.filename)
|
writeRope(result, m.filename)
|
||||||
|
|
||||||
proc getCFile(m: BModule): string =
|
proc getCFile(m: BModule): string =
|
||||||
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), cExt)
|
let ext =
|
||||||
|
if m.compileToCpp: ".cpp"
|
||||||
|
elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
|
||||||
|
else: ".c"
|
||||||
|
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
|
||||||
|
|
||||||
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
||||||
assert optSymbolFiles in gGlobalOptions
|
assert optSymbolFiles in gGlobalOptions
|
||||||
|
|
@ -1326,10 +1340,10 @@ proc finishModule(m: BModule) =
|
||||||
dec(gForwardedProcsCounter, i)
|
dec(gForwardedProcsCounter, i)
|
||||||
setLen(m.forwardedProcs, 0)
|
setLen(m.forwardedProcs, 0)
|
||||||
|
|
||||||
proc shouldRecompile(code: PRope, cfile, cfilenoext: string): bool =
|
proc shouldRecompile(code: PRope, cfile: string): bool =
|
||||||
result = true
|
result = true
|
||||||
if optForceFullMake notin gGlobalOptions:
|
if optForceFullMake notin gGlobalOptions:
|
||||||
var objFile = toObjFile(cfilenoext)
|
var objFile = toObjFile(cfile)
|
||||||
if writeRopeIfNotEqual(code, cfile): return
|
if writeRopeIfNotEqual(code, cfile): return
|
||||||
if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
|
if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false
|
||||||
else:
|
else:
|
||||||
|
|
@ -1354,26 +1368,26 @@ proc writeModule(m: BModule, pending: bool) =
|
||||||
app(m.s[cfsProcHeaders], mainModProcs)
|
app(m.s[cfsProcHeaders], mainModProcs)
|
||||||
generateThreadVarsSize(m)
|
generateThreadVarsSize(m)
|
||||||
|
|
||||||
var code = genModule(m, cfilenoext)
|
var code = genModule(m, cfile)
|
||||||
when hasTinyCBackend:
|
when hasTinyCBackend:
|
||||||
if gCmd == cmdRun:
|
if gCmd == cmdRun:
|
||||||
tccgen.compileCCode(ropeToStr(code))
|
tccgen.compileCCode(ropeToStr(code))
|
||||||
return
|
return
|
||||||
|
|
||||||
if shouldRecompile(code, cfile, cfilenoext):
|
if shouldRecompile(code, cfile):
|
||||||
addFileToCompile(cfilenoext)
|
addFileToCompile(cfile)
|
||||||
elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
|
elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
|
||||||
mergeFiles(cfile, m)
|
mergeFiles(cfile, m)
|
||||||
genInitCode(m)
|
genInitCode(m)
|
||||||
finishTypeDescriptions(m)
|
finishTypeDescriptions(m)
|
||||||
var code = genModule(m, cfilenoext)
|
var code = genModule(m, cfile)
|
||||||
writeRope(code, cfile)
|
writeRope(code, cfile)
|
||||||
addFileToCompile(cfilenoext)
|
addFileToCompile(cfile)
|
||||||
elif not existsFile(toObjFile(cfilenoext)):
|
elif not existsFile(toObjFile(cfilenoext)):
|
||||||
# Consider: first compilation compiles ``system.nim`` and produces
|
# Consider: first compilation compiles ``system.nim`` and produces
|
||||||
# ``system.c`` but then compilation fails due to an error. This means
|
# ``system.c`` but then compilation fails due to an error. This means
|
||||||
# that ``system.o`` is missing, so we need to call the C compiler for it:
|
# that ``system.o`` is missing, so we need to call the C compiler for it:
|
||||||
addFileToCompile(cfilenoext)
|
addFileToCompile(cfile)
|
||||||
|
|
||||||
addFileToLink(cfilenoext)
|
addFileToLink(cfilenoext)
|
||||||
|
|
||||||
|
|
@ -1385,9 +1399,9 @@ proc updateCachedModule(m: BModule) =
|
||||||
mergeFiles(cfile, m)
|
mergeFiles(cfile, m)
|
||||||
genInitCode(m)
|
genInitCode(m)
|
||||||
finishTypeDescriptions(m)
|
finishTypeDescriptions(m)
|
||||||
var code = genModule(m, cfilenoext)
|
var code = genModule(m, cfile)
|
||||||
writeRope(code, cfile)
|
writeRope(code, cfile)
|
||||||
addFileToCompile(cfilenoext)
|
addFileToCompile(cfile)
|
||||||
|
|
||||||
addFileToLink(cfilenoext)
|
addFileToLink(cfilenoext)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -62,7 +62,7 @@ type
|
||||||
frameLen*: int16
|
frameLen*: int16
|
||||||
|
|
||||||
TCProc{.final.} = object # represents C proc that is currently generated
|
TCProc{.final.} = object # represents C proc that is currently generated
|
||||||
prc*: PSym # the Nimrod proc that this C proc belongs to
|
prc*: PSym # the Nim proc that this C proc belongs to
|
||||||
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
|
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
|
||||||
threadVarAccessed*: bool # true if the proc already accessed some threadvar
|
threadVarAccessed*: bool # true if the proc already accessed some threadvar
|
||||||
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
|
nestedTryStmts*: seq[PNode] # in how many nested try statements we are
|
||||||
|
|
@ -101,10 +101,10 @@ type
|
||||||
# without extension)
|
# without extension)
|
||||||
typeCache*: TIdTable # cache the generated types
|
typeCache*: TIdTable # cache the generated types
|
||||||
forwTypeCache*: TIdTable # cache for forward declarations of types
|
forwTypeCache*: TIdTable # cache for forward declarations of types
|
||||||
declaredThings*: TIntSet # things we have declared in this .c file
|
declaredThings*: IntSet # things we have declared in this .c file
|
||||||
declaredProtos*: TIntSet # prototypes we have declared in this .c file
|
declaredProtos*: IntSet # prototypes we have declared in this .c file
|
||||||
headerFiles*: TLinkedList # needed headers to include
|
headerFiles*: TLinkedList # needed headers to include
|
||||||
typeInfoMarker*: TIntSet # needed for generating type information
|
typeInfoMarker*: IntSet # needed for generating type information
|
||||||
initProc*: BProc # code for init procedure
|
initProc*: BProc # code for init procedure
|
||||||
postInitProc*: BProc # code to be executed after the init proc
|
postInitProc*: BProc # code to be executed after the init proc
|
||||||
preInitProc*: BProc # code executed before the init proc
|
preInitProc*: BProc # code executed before the init proc
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -155,7 +155,7 @@ proc relevantCol(methods: TSymSeq, col: int): bool =
|
||||||
if not sameType(t2, t):
|
if not sameType(t2, t):
|
||||||
return true
|
return true
|
||||||
|
|
||||||
proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
|
proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int =
|
||||||
for col in countup(1, sonsLen(a.typ) - 1):
|
for col in countup(1, sonsLen(a.typ) - 1):
|
||||||
if contains(relevantCols, col):
|
if contains(relevantCols, col):
|
||||||
var aa = skipTypes(a.typ.sons[col], skipPtrs)
|
var aa = skipTypes(a.typ.sons[col], skipPtrs)
|
||||||
|
|
@ -164,7 +164,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int =
|
||||||
if (d != high(int)):
|
if (d != high(int)):
|
||||||
return d
|
return d
|
||||||
|
|
||||||
proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
|
proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
|
||||||
# we use shellsort here; fast and simple
|
# we use shellsort here; fast and simple
|
||||||
var n = len(a)
|
var n = len(a)
|
||||||
var h = 1
|
var h = 1
|
||||||
|
|
@ -183,7 +183,7 @@ proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) =
|
||||||
a[j] = v
|
a[j] = v
|
||||||
if h == 1: break
|
if h == 1: break
|
||||||
|
|
||||||
proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
|
proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||||
var base = lastSon(methods[0].ast).sym
|
var base = lastSon(methods[0].ast).sym
|
||||||
result = base
|
result = base
|
||||||
var paramLen = sonsLen(base.typ)
|
var paramLen = sonsLen(base.typ)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -26,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none")
|
||||||
|
|
||||||
import
|
import
|
||||||
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
|
os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists,
|
||||||
wordrecg, parseutils, babelcmd, idents
|
wordrecg, parseutils, nimblecmd, idents, parseopt
|
||||||
|
|
||||||
# but some have deps to imported modules. Yay.
|
# but some have deps to imported modules. Yay.
|
||||||
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
|
bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc")
|
||||||
|
|
@ -43,7 +43,7 @@ type
|
||||||
TCmdLinePass* = enum
|
TCmdLinePass* = enum
|
||||||
passCmd1, # first pass over the command line
|
passCmd1, # first pass over the command line
|
||||||
passCmd2, # second pass over the command line
|
passCmd2, # second pass over the command line
|
||||||
passPP # preprocessor called ProcessCommand()
|
passPP # preprocessor called processCommand()
|
||||||
|
|
||||||
proc processCommand*(switch: string, pass: TCmdLinePass)
|
proc processCommand*(switch: string, pass: TCmdLinePass)
|
||||||
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
|
proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
|
||||||
|
|
@ -51,7 +51,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
const
|
const
|
||||||
HelpMessage = "Nimrod Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
|
HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
|
||||||
"Copyright (c) 2006-2014 by Andreas Rumpf\n"
|
"Copyright (c) 2006-2014 by Andreas Rumpf\n"
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -226,6 +226,7 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool =
|
||||||
of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
|
of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation)
|
||||||
of "implicitstatic": result = contains(gOptions, optImplicitStatic)
|
of "implicitstatic": result = contains(gOptions, optImplicitStatic)
|
||||||
of "patterns": result = contains(gOptions, optPatterns)
|
of "patterns": result = contains(gOptions, optPatterns)
|
||||||
|
of "experimental": result = gExperimentalMode
|
||||||
else: invalidCmdLineOption(passCmd1, switch, info)
|
else: invalidCmdLineOption(passCmd1, switch, info)
|
||||||
|
|
||||||
proc processPath(path: string, notRelativeToProj = false): string =
|
proc processPath(path: string, notRelativeToProj = false): string =
|
||||||
|
|
@ -234,7 +235,9 @@ proc processPath(path: string, notRelativeToProj = false): string =
|
||||||
path
|
path
|
||||||
else:
|
else:
|
||||||
options.gProjectPath / path
|
options.gProjectPath / path
|
||||||
result = unixToNativePath(p % ["nimrod", getPrefixDir(), "lib", libpath,
|
result = unixToNativePath(p % ["nimrod", getPrefixDir(),
|
||||||
|
"nim", getPrefixDir(),
|
||||||
|
"lib", libpath,
|
||||||
"home", removeTrailingDirSep(os.getHomeDir()),
|
"home", removeTrailingDirSep(os.getHomeDir()),
|
||||||
"projectname", options.gProjectName,
|
"projectname", options.gProjectName,
|
||||||
"projectpath", options.gProjectPath])
|
"projectpath", options.gProjectPath])
|
||||||
|
|
@ -280,14 +283,15 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
of "path", "p":
|
of "path", "p":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
addPath(processPath(arg), info)
|
addPath(processPath(arg), info)
|
||||||
of "babelpath":
|
of "nimblepath", "babelpath":
|
||||||
if pass in {passCmd2, passPP} and not options.gNoBabelPath:
|
# keep the old name for compat
|
||||||
|
if pass in {passCmd2, passPP} and not options.gNoNimblePath:
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
let path = processPath(arg, notRelativeToProj=true)
|
let path = processPath(arg, notRelativeToProj=true)
|
||||||
babelpath(path, info)
|
nimblePath(path, info)
|
||||||
of "nobabelpath":
|
of "nonimblepath", "nobabelpath":
|
||||||
expectNoArg(switch, arg, pass, info)
|
expectNoArg(switch, arg, pass, info)
|
||||||
options.gNoBabelPath = true
|
options.gNoNimblePath = true
|
||||||
of "excludepath":
|
of "excludepath":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
let path = processPath(arg)
|
let path = processPath(arg)
|
||||||
|
|
@ -307,8 +311,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
options.docSeeSrcUrl = arg
|
options.docSeeSrcUrl = arg
|
||||||
of "mainmodule", "m":
|
of "mainmodule", "m":
|
||||||
expectArg(switch, arg, pass, info)
|
discard "allow for backwards compatibility, but don't do anything"
|
||||||
optMainModule = arg
|
|
||||||
of "define", "d":
|
of "define", "d":
|
||||||
expectArg(switch, arg, pass, info)
|
expectArg(switch, arg, pass, info)
|
||||||
defineSymbol(arg)
|
defineSymbol(arg)
|
||||||
|
|
@ -566,6 +569,9 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||||
of "none": idents.firstCharIsCS = false
|
of "none": idents.firstCharIsCS = false
|
||||||
else: localError(info, errGenerated,
|
else: localError(info, errGenerated,
|
||||||
"'partial' or 'none' expected, but found " & arg)
|
"'partial' or 'none' expected, but found " & arg)
|
||||||
|
of "experimental":
|
||||||
|
expectNoArg(switch, arg, pass, info)
|
||||||
|
gExperimentalMode = true
|
||||||
else:
|
else:
|
||||||
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg)
|
||||||
else: invalidCmdLineOption(pass, switch, info)
|
else: invalidCmdLineOption(pass, switch, info)
|
||||||
|
|
@ -574,3 +580,33 @@ proc processCommand(switch: string, pass: TCmdLinePass) =
|
||||||
var cmd, arg: string
|
var cmd, arg: string
|
||||||
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
|
splitSwitch(switch, cmd, arg, pass, gCmdLineInfo)
|
||||||
processSwitch(cmd, arg, pass, gCmdLineInfo)
|
processSwitch(cmd, arg, pass, gCmdLineInfo)
|
||||||
|
|
||||||
|
|
||||||
|
var
|
||||||
|
arguments* = ""
|
||||||
|
# the arguments to be passed to the program that
|
||||||
|
# should be run
|
||||||
|
|
||||||
|
proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
|
||||||
|
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
|
||||||
|
# we fix this here
|
||||||
|
var bracketLe = strutils.find(p.key, '[')
|
||||||
|
if bracketLe >= 0:
|
||||||
|
var key = substr(p.key, 0, bracketLe - 1)
|
||||||
|
var val = substr(p.key, bracketLe + 1) & ':' & p.val
|
||||||
|
processSwitch(key, val, pass, gCmdLineInfo)
|
||||||
|
else:
|
||||||
|
processSwitch(p.key, p.val, pass, gCmdLineInfo)
|
||||||
|
|
||||||
|
proc processArgument*(pass: TCmdLinePass; p: OptParser;
|
||||||
|
argsCount: var int): bool =
|
||||||
|
if argsCount == 0:
|
||||||
|
options.command = p.key
|
||||||
|
else:
|
||||||
|
if pass == passCmd1: options.commandArgs.add p.key
|
||||||
|
if argsCount == 1:
|
||||||
|
# support UNIX style filenames anywhere for portable build scripts:
|
||||||
|
options.gProjectName = unixToNativePath(p.key)
|
||||||
|
arguments = cmdLineRest(p)
|
||||||
|
result = true
|
||||||
|
inc argsCount
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import
|
||||||
|
|
||||||
# We need to use a PStringTable here as defined symbols are always guaranteed
|
# We need to use a PStringTable here as defined symbols are always guaranteed
|
||||||
# to be style insensitive. Otherwise hell would break lose.
|
# to be style insensitive. Otherwise hell would break lose.
|
||||||
var gSymbols: PStringTable
|
var gSymbols: StringTableRef
|
||||||
|
|
||||||
proc defineSymbol*(symbol: string) =
|
proc defineSymbol*(symbol: string) =
|
||||||
gSymbols[symbol] = "true"
|
gSymbols[symbol] = "true"
|
||||||
|
|
@ -41,12 +41,12 @@ proc countDefinedSymbols*(): int =
|
||||||
for key, val in pairs(gSymbols):
|
for key, val in pairs(gSymbols):
|
||||||
if val == "true": inc(result)
|
if val == "true": inc(result)
|
||||||
|
|
||||||
# For ease of bootstrapping, we keep there here and not in the global config
|
# For ease of bootstrapping, we keep them here and not in the global config
|
||||||
# file for now:
|
# file for now:
|
||||||
const
|
const
|
||||||
additionalSymbols = """
|
additionalSymbols = """
|
||||||
x86 itanium x8664
|
x86 itanium x8664
|
||||||
msdos mswindows win32 unix posix sunos bsd macintosh RISCOS doslike hpux
|
msdos mswindows win32 unix posix sunos bsd macintosh RISCOS hpux
|
||||||
mac
|
mac
|
||||||
|
|
||||||
hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9
|
hppa hp9000 hp9000s300 hp9000s700 hp9000s800 hp9000s820 ELATE sparcv9
|
||||||
|
|
@ -88,6 +88,7 @@ proc initDefines*() =
|
||||||
defineSymbol("nimrequiresnimframe")
|
defineSymbol("nimrequiresnimframe")
|
||||||
defineSymbol("nimparsebiggestfloatmagic")
|
defineSymbol("nimparsebiggestfloatmagic")
|
||||||
defineSymbol("nimalias")
|
defineSymbol("nimalias")
|
||||||
|
defineSymbol("nimlocks")
|
||||||
|
|
||||||
# add platform specific symbols:
|
# add platform specific symbols:
|
||||||
for c in low(CPU)..high(CPU):
|
for c in low(CPU)..high(CPU):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -102,7 +102,7 @@ proc crcFromFile(filename: string): TCrc32 =
|
||||||
const
|
const
|
||||||
bufSize = 8000 # don't use 8K for the memory allocator!
|
bufSize = 8000 # don't use 8K for the memory allocator!
|
||||||
var
|
var
|
||||||
bin: TFile
|
bin: File
|
||||||
result = InitCrc32
|
result = InitCrc32
|
||||||
if not open(bin, filename):
|
if not open(bin, filename):
|
||||||
return # not equal if file does not exist
|
return # not equal if file does not exist
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -23,7 +23,7 @@ type
|
||||||
id: int # for generating IDs
|
id: int # for generating IDs
|
||||||
toc, section: TSections
|
toc, section: TSections
|
||||||
indexValFilename: string
|
indexValFilename: string
|
||||||
seenSymbols: PStringTable # avoids duplicate symbol generation for HTML.
|
seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML.
|
||||||
|
|
||||||
PDoc* = ref TDocumentor ## Alias to type less.
|
PDoc* = ref TDocumentor ## Alias to type less.
|
||||||
|
|
||||||
|
|
@ -41,6 +41,7 @@ proc compilerMsgHandler(filename: string, line, col: int,
|
||||||
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
|
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
|
||||||
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
||||||
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
||||||
|
of mwUnsupportedField: k = warnFieldXNotSupported
|
||||||
globalError(newLineInfo(filename, line, col), k, arg)
|
globalError(newLineInfo(filename, line, col), k, arg)
|
||||||
|
|
||||||
proc docgenFindFile(s: string): string {.procvar.} =
|
proc docgenFindFile(s: string): string {.procvar.} =
|
||||||
|
|
@ -55,7 +56,7 @@ proc parseRst(text, filename: string,
|
||||||
result = rstParse(text, filename, line, column, hasToc, rstOptions,
|
result = rstParse(text, filename, line, column, hasToc, rstOptions,
|
||||||
docgenFindFile, compilerMsgHandler)
|
docgenFindFile, compilerMsgHandler)
|
||||||
|
|
||||||
proc newDocumentor*(filename: string, config: PStringTable): PDoc =
|
proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
||||||
new(result)
|
new(result)
|
||||||
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
|
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
|
||||||
options.gConfigVars, filename, {roSupportRawDirective},
|
options.gConfigVars, filename, {roSupportRawDirective},
|
||||||
|
|
@ -374,11 +375,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||||
cleanPlainSymbol = renderPlainSymbolName(nameNode)
|
cleanPlainSymbol = renderPlainSymbolName(nameNode)
|
||||||
complexSymbol = complexName(k, n, cleanPlainSymbol)
|
complexSymbol = complexName(k, n, cleanPlainSymbol)
|
||||||
plainSymbolRope = toRope(cleanPlainSymbol)
|
plainSymbolRope = toRope(cleanPlainSymbol)
|
||||||
plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol))
|
plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol))
|
||||||
itemIDRope = toRope(d.id)
|
itemIDRope = toRope(d.id)
|
||||||
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
|
symbolOrId = d.newUniquePlainSymbol(complexSymbol)
|
||||||
symbolOrIdRope = symbolOrId.toRope
|
symbolOrIdRope = symbolOrId.toRope
|
||||||
symbolOrIdEncRope = URLEncode(symbolOrId).toRope
|
symbolOrIdEncRope = encodeUrl(symbolOrId).toRope
|
||||||
|
|
||||||
var seeSrcRope: PRope = nil
|
var seeSrcRope: PRope = nil
|
||||||
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
|
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
|
||||||
|
|
@ -413,7 +414,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||||
setIndexTerm(d[], symbolOrId, name, linkTitle,
|
setIndexTerm(d[], symbolOrId, name, linkTitle,
|
||||||
xmltree.escape(plainDocstring.docstringSummary))
|
xmltree.escape(plainDocstring.docstringSummary))
|
||||||
|
|
||||||
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode =
|
proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode =
|
||||||
if not isVisible(nameNode): return
|
if not isVisible(nameNode): return
|
||||||
var
|
var
|
||||||
name = getName(d, nameNode)
|
name = getName(d, nameNode)
|
||||||
|
|
@ -473,7 +474,7 @@ proc generateDoc*(d: PDoc, n: PNode) =
|
||||||
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
|
of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0])
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode =
|
proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCommentStmt:
|
of nkCommentStmt:
|
||||||
if n.comment != nil and startsWith(n.comment, "##"):
|
if n.comment != nil and startsWith(n.comment, "##"):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -26,7 +26,7 @@ proc close(p: PPassContext, n: PNode): PNode =
|
||||||
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
|
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
|
||||||
try:
|
try:
|
||||||
generateIndex(g.doc)
|
generateIndex(g.doc)
|
||||||
except EIO:
|
except IOError:
|
||||||
discard
|
discard
|
||||||
|
|
||||||
proc processNode(c: PPassContext, n: PNode): PNode =
|
proc processNode(c: PPassContext, n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## This file implements the FFI part of the evaluator for Nimrod code.
|
## This file implements the FFI part of the evaluator for Nim code.
|
||||||
|
|
||||||
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os
|
import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# module for calling the different external C compilers
|
# Module providing functions for calling the different external C compilers
|
||||||
# some things are read in from the configuration file
|
# Uses some hard-wired facts about each C/C++ compiler, plus options read
|
||||||
|
# from a configuration file, to provide generalized procedures to compile
|
||||||
|
# nim files.
|
||||||
|
|
||||||
import
|
import
|
||||||
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
|
lists, ropes, os, strutils, osproc, platform, condsyms, options, msgs, crc
|
||||||
|
|
@ -59,6 +61,7 @@ type
|
||||||
template compiler(name: expr, settings: stmt): stmt {.immediate.} =
|
template compiler(name: expr, settings: stmt): stmt {.immediate.} =
|
||||||
proc name: TInfoCC {.compileTime.} = settings
|
proc name: TInfoCC {.compileTime.} = settings
|
||||||
|
|
||||||
|
# GNU C and C++ Compiler
|
||||||
compiler gcc:
|
compiler gcc:
|
||||||
result = (
|
result = (
|
||||||
name: "gcc",
|
name: "gcc",
|
||||||
|
|
@ -84,21 +87,24 @@ compiler gcc:
|
||||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard, hasGnuAsm,
|
||||||
hasNakedAttribute})
|
hasNakedAttribute})
|
||||||
|
|
||||||
|
# LLVM Frontend for GCC/G++
|
||||||
compiler llvmGcc:
|
compiler llvmGcc:
|
||||||
result = gcc()
|
result = gcc() # Uses settings from GCC
|
||||||
|
|
||||||
result.name = "llvm_gcc"
|
result.name = "llvm_gcc"
|
||||||
result.compilerExe = "llvm-gcc"
|
result.compilerExe = "llvm-gcc"
|
||||||
result.cppCompiler = "llvm-g++"
|
result.cppCompiler = "llvm-g++"
|
||||||
result.buildLib = "llvm-ar rcs $libfile $objfiles"
|
result.buildLib = "llvm-ar rcs $libfile $objfiles"
|
||||||
|
|
||||||
|
# Clang (LLVM) C/C++ Compiler
|
||||||
compiler clang:
|
compiler clang:
|
||||||
result = llvmGcc()
|
result = llvmGcc() # Uses settings from llvmGcc
|
||||||
|
|
||||||
result.name = "clang"
|
result.name = "clang"
|
||||||
result.compilerExe = "clang"
|
result.compilerExe = "clang"
|
||||||
result.cppCompiler = "clang++"
|
result.cppCompiler = "clang++"
|
||||||
|
|
||||||
|
# Microsoft Visual C/C++ Compiler
|
||||||
compiler vcc:
|
compiler vcc:
|
||||||
result = (
|
result = (
|
||||||
name: "vcc",
|
name: "vcc",
|
||||||
|
|
@ -123,6 +129,7 @@ compiler vcc:
|
||||||
packedPragma: "#pragma pack(1)",
|
packedPragma: "#pragma pack(1)",
|
||||||
props: {hasCpp, hasAssume, hasNakedDeclspec})
|
props: {hasCpp, hasAssume, hasNakedDeclspec})
|
||||||
|
|
||||||
|
# Intel C/C++ Compiler
|
||||||
compiler icl:
|
compiler icl:
|
||||||
# Intel compilers try to imitate the native ones (gcc and msvc)
|
# Intel compilers try to imitate the native ones (gcc and msvc)
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
|
|
@ -134,6 +141,7 @@ compiler icl:
|
||||||
result.compilerExe = "icl"
|
result.compilerExe = "icl"
|
||||||
result.linkerExe = "icl"
|
result.linkerExe = "icl"
|
||||||
|
|
||||||
|
# Local C Compiler
|
||||||
compiler lcc:
|
compiler lcc:
|
||||||
result = (
|
result = (
|
||||||
name: "lcc",
|
name: "lcc",
|
||||||
|
|
@ -158,6 +166,7 @@ compiler lcc:
|
||||||
packedPragma: "", # XXX: not supported yet
|
packedPragma: "", # XXX: not supported yet
|
||||||
props: {})
|
props: {})
|
||||||
|
|
||||||
|
# Borland C Compiler
|
||||||
compiler bcc:
|
compiler bcc:
|
||||||
result = (
|
result = (
|
||||||
name: "bcc",
|
name: "bcc",
|
||||||
|
|
@ -182,6 +191,7 @@ compiler bcc:
|
||||||
packedPragma: "", # XXX: not supported yet
|
packedPragma: "", # XXX: not supported yet
|
||||||
props: {hasCpp})
|
props: {hasCpp})
|
||||||
|
|
||||||
|
# Digital Mars C Compiler
|
||||||
compiler dmc:
|
compiler dmc:
|
||||||
result = (
|
result = (
|
||||||
name: "dmc",
|
name: "dmc",
|
||||||
|
|
@ -206,6 +216,7 @@ compiler dmc:
|
||||||
packedPragma: "#pragma pack(1)",
|
packedPragma: "#pragma pack(1)",
|
||||||
props: {hasCpp})
|
props: {hasCpp})
|
||||||
|
|
||||||
|
# Watcom C Compiler
|
||||||
compiler wcc:
|
compiler wcc:
|
||||||
result = (
|
result = (
|
||||||
name: "wcc",
|
name: "wcc",
|
||||||
|
|
@ -230,6 +241,7 @@ compiler wcc:
|
||||||
packedPragma: "", # XXX: not supported yet
|
packedPragma: "", # XXX: not supported yet
|
||||||
props: {hasCpp})
|
props: {hasCpp})
|
||||||
|
|
||||||
|
# Tiny C Compiler
|
||||||
compiler tcc:
|
compiler tcc:
|
||||||
result = (
|
result = (
|
||||||
name: "tcc",
|
name: "tcc",
|
||||||
|
|
@ -254,6 +266,7 @@ compiler tcc:
|
||||||
packedPragma: "", # XXX: not supported yet
|
packedPragma: "", # XXX: not supported yet
|
||||||
props: {hasSwitchRange, hasComputedGoto})
|
props: {hasSwitchRange, hasComputedGoto})
|
||||||
|
|
||||||
|
# Pelles C Compiler
|
||||||
compiler pcc:
|
compiler pcc:
|
||||||
# Pelles C
|
# Pelles C
|
||||||
result = (
|
result = (
|
||||||
|
|
@ -279,6 +292,7 @@ compiler pcc:
|
||||||
packedPragma: "", # XXX: not supported yet
|
packedPragma: "", # XXX: not supported yet
|
||||||
props: {})
|
props: {})
|
||||||
|
|
||||||
|
# Your C Compiler
|
||||||
compiler ucc:
|
compiler ucc:
|
||||||
result = (
|
result = (
|
||||||
name: "ucc",
|
name: "ucc",
|
||||||
|
|
@ -323,10 +337,7 @@ const
|
||||||
|
|
||||||
var
|
var
|
||||||
cCompiler* = ccGcc # the used compiler
|
cCompiler* = ccGcc # the used compiler
|
||||||
|
gMixedMode*: bool # true if some module triggered C++ codegen
|
||||||
cExt* = ".c" # extension of generated C/C++ files
|
|
||||||
# (can be changed to .cpp later)
|
|
||||||
|
|
||||||
cIncludes*: seq[string] = @[] # directories to search for included files
|
cIncludes*: seq[string] = @[] # directories to search for included files
|
||||||
cLibs*: seq[string] = @[] # directories to search for lib files
|
cLibs*: seq[string] = @[] # directories to search for lib files
|
||||||
cLinkedLibs*: seq[string] = @[] # libraries to link
|
cLinkedLibs*: seq[string] = @[] # libraries to link
|
||||||
|
|
@ -342,7 +353,9 @@ var
|
||||||
compileOptions: string = ""
|
compileOptions: string = ""
|
||||||
ccompilerpath: string = ""
|
ccompilerpath: string = ""
|
||||||
|
|
||||||
proc nameToCC*(name: string): TSystemCC =
|
proc nameToCC*(name: string): TSystemCC =
|
||||||
|
## Returns the kind of compiler referred to by `name`, or ccNone
|
||||||
|
## if the name doesn't refer to any known compiler.
|
||||||
for i in countup(succ(ccNone), high(TSystemCC)):
|
for i in countup(succ(ccNone), high(TSystemCC)):
|
||||||
if cmpIgnoreStyle(name, CC[i].name) == 0:
|
if cmpIgnoreStyle(name, CC[i].name) == 0:
|
||||||
return i
|
return i
|
||||||
|
|
@ -351,17 +364,18 @@ proc nameToCC*(name: string): TSystemCC =
|
||||||
proc getConfigVar(c: TSystemCC, suffix: string): string =
|
proc getConfigVar(c: TSystemCC, suffix: string): string =
|
||||||
# use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
|
# use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
|
||||||
# for niminst support
|
# for niminst support
|
||||||
|
let fullSuffix = (if gCmd == cmdCompileToCpp: ".cpp" & suffix else: suffix)
|
||||||
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
|
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
|
||||||
optCompileOnly notin gGlobalOptions:
|
optCompileOnly notin gGlobalOptions:
|
||||||
let fullCCname = platform.CPU[targetCPU].name & '.' &
|
let fullCCname = platform.CPU[targetCPU].name & '.' &
|
||||||
platform.OS[targetOS].name & '.' &
|
platform.OS[targetOS].name & '.' &
|
||||||
CC[c].name & suffix
|
CC[c].name & fullSuffix
|
||||||
result = getConfigVar(fullCCname)
|
result = getConfigVar(fullCCname)
|
||||||
if result.len == 0:
|
if result.len == 0:
|
||||||
# not overriden for this cross compilation setting?
|
# not overriden for this cross compilation setting?
|
||||||
result = getConfigVar(CC[c].name & suffix)
|
result = getConfigVar(CC[c].name & fullSuffix)
|
||||||
else:
|
else:
|
||||||
result = getConfigVar(CC[c].name & suffix)
|
result = getConfigVar(CC[c].name & fullSuffix)
|
||||||
|
|
||||||
proc setCC*(ccname: string) =
|
proc setCC*(ccname: string) =
|
||||||
cCompiler = nameToCC(ccname)
|
cCompiler = nameToCC(ccname)
|
||||||
|
|
@ -387,8 +401,6 @@ proc initVars*() =
|
||||||
# we need to define the symbol here, because ``CC`` may have never been set!
|
# we need to define the symbol here, because ``CC`` may have never been set!
|
||||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||||
defineSymbol(CC[cCompiler].name)
|
defineSymbol(CC[cCompiler].name)
|
||||||
if gCmd == cmdCompileToCpp: cExt = ".cpp"
|
|
||||||
elif gCmd == cmdCompileToOC: cExt = ".m"
|
|
||||||
addCompileOption(getConfigVar(cCompiler, ".options.always"))
|
addCompileOption(getConfigVar(cCompiler, ".options.always"))
|
||||||
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
||||||
if len(ccompilerpath) == 0:
|
if len(ccompilerpath) == 0:
|
||||||
|
|
@ -397,9 +409,9 @@ proc initVars*() =
|
||||||
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
|
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
|
||||||
result = completeGeneratedFilePath(cfile, createSubDir)
|
result = completeGeneratedFilePath(cfile, createSubDir)
|
||||||
|
|
||||||
proc toObjFile*(filenameWithoutExt: string): string =
|
proc toObjFile*(filename: string): string =
|
||||||
# Object file for compilation
|
# Object file for compilation
|
||||||
result = changeFileExt(filenameWithoutExt, CC[cCompiler].objExt)
|
result = changeFileExt(filename, CC[cCompiler].objExt)
|
||||||
|
|
||||||
proc addFileToCompile*(filename: string) =
|
proc addFileToCompile*(filename: string) =
|
||||||
appendStr(toCompile, filename)
|
appendStr(toCompile, filename)
|
||||||
|
|
@ -417,8 +429,12 @@ proc addFileToLink*(filename: string) =
|
||||||
prependStr(toLink, filename)
|
prependStr(toLink, filename)
|
||||||
# BUGFIX: was ``appendStr``
|
# BUGFIX: was ``appendStr``
|
||||||
|
|
||||||
proc execExternalProgram*(cmd: string) =
|
proc execExternalProgram*(cmd: string, prettyCmd = "") =
|
||||||
if optListCmd in gGlobalOptions or gVerbosity > 0: msgWriteln(cmd)
|
if optListCmd in gGlobalOptions or gVerbosity > 0:
|
||||||
|
if prettyCmd != "":
|
||||||
|
msgWriteln(prettyCmd)
|
||||||
|
else:
|
||||||
|
msgWriteln(cmd)
|
||||||
if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "")
|
if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "")
|
||||||
|
|
||||||
proc generateScript(projectFile: string, script: PRope) =
|
proc generateScript(projectFile: string, script: PRope) =
|
||||||
|
|
@ -487,7 +503,7 @@ proc getLinkOptions: string =
|
||||||
|
|
||||||
proc needsExeExt(): bool {.inline.} =
|
proc needsExeExt(): bool {.inline.} =
|
||||||
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
|
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
|
||||||
(platform.hostOS == osWindows)
|
(platform.hostOS == osWindows)
|
||||||
|
|
||||||
proc getCompilerExe(compiler: TSystemCC): string =
|
proc getCompilerExe(compiler: TSystemCC): string =
|
||||||
result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler
|
result = if gCmd == cmdCompileToCpp: CC[compiler].cppCompiler
|
||||||
|
|
@ -497,6 +513,7 @@ proc getCompilerExe(compiler: TSystemCC): string =
|
||||||
|
|
||||||
proc getLinkerExe(compiler: TSystemCC): string =
|
proc getLinkerExe(compiler: TSystemCC): string =
|
||||||
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
|
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
|
||||||
|
elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
|
||||||
else: compiler.getCompilerExe
|
else: compiler.getCompilerExe
|
||||||
|
|
||||||
proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||||
|
|
@ -507,11 +524,11 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||||
|
|
||||||
if needsExeExt(): exe = addFileExt(exe, "exe")
|
if needsExeExt(): exe = addFileExt(exe, "exe")
|
||||||
if optGenDynLib in gGlobalOptions and
|
if optGenDynLib in gGlobalOptions and
|
||||||
ospNeedsPIC in platform.OS[targetOS].props:
|
ospNeedsPIC in platform.OS[targetOS].props:
|
||||||
add(options, ' ' & CC[c].pic)
|
add(options, ' ' & CC[c].pic)
|
||||||
|
|
||||||
var includeCmd, compilePattern: string
|
var includeCmd, compilePattern: string
|
||||||
if not noAbsolutePaths():
|
if not noAbsolutePaths():
|
||||||
# compute include paths:
|
# compute include paths:
|
||||||
includeCmd = CC[c].includeCmd & quoteShell(libpath)
|
includeCmd = CC[c].includeCmd & quoteShell(libpath)
|
||||||
|
|
||||||
|
|
@ -519,29 +536,31 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||||
includeCmd.add([CC[c].includeCmd, includeDir.quoteShell])
|
includeCmd.add([CC[c].includeCmd, includeDir.quoteShell])
|
||||||
|
|
||||||
compilePattern = joinPath(ccompilerpath, exe)
|
compilePattern = joinPath(ccompilerpath, exe)
|
||||||
else:
|
else:
|
||||||
includeCmd = ""
|
includeCmd = ""
|
||||||
compilePattern = c.getCompilerExe
|
compilePattern = c.getCompilerExe
|
||||||
|
|
||||||
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
|
var cfile = if noAbsolutePaths(): extractFilename(cfilename)
|
||||||
else: cfilename
|
else: cfilename
|
||||||
var objfile = if not isExternal or noAbsolutePaths():
|
var objfile = if not isExternal or noAbsolutePaths():
|
||||||
toObjFile(cfile)
|
toObjFile(cfile)
|
||||||
else:
|
else:
|
||||||
completeCFilePath(toObjFile(cfile))
|
completeCFilePath(toObjFile(cfile))
|
||||||
cfile = quoteShell(addFileExt(cfile, cExt))
|
|
||||||
objfile = quoteShell(objfile)
|
objfile = quoteShell(objfile)
|
||||||
result = quoteShell(compilePattern % [
|
result = quoteShell(compilePattern % [
|
||||||
"file", cfile, "objfile", objfile, "options", options,
|
"file", cfile, "objfile", objfile, "options", options,
|
||||||
"include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath])
|
"include", includeCmd, "nimrod", getPrefixDir(),
|
||||||
|
"nim", getPrefixDir(), "lib", libpath])
|
||||||
add(result, ' ')
|
add(result, ' ')
|
||||||
addf(result, CC[c].compileTmpl, [
|
addf(result, CC[c].compileTmpl, [
|
||||||
"file", cfile, "objfile", objfile,
|
"file", cfile, "objfile", objfile,
|
||||||
"options", options, "include", includeCmd,
|
"options", options, "include", includeCmd,
|
||||||
"nimrod", quoteShell(getPrefixDir()),
|
"nimrod", quoteShell(getPrefixDir()),
|
||||||
|
"nim", quoteShell(getPrefixDir()),
|
||||||
"lib", quoteShell(libpath)])
|
"lib", quoteShell(libpath)])
|
||||||
|
|
||||||
proc footprint(filename: string): TCrc32 =
|
proc footprint(filename: string): TCrc32 =
|
||||||
|
# note, '><' further modifies a crc value with a string.
|
||||||
result = crcFromFile(filename) ><
|
result = crcFromFile(filename) ><
|
||||||
platform.OS[targetOS].name ><
|
platform.OS[targetOS].name ><
|
||||||
platform.CPU[targetCPU].name ><
|
platform.CPU[targetCPU].name ><
|
||||||
|
|
@ -551,7 +570,7 @@ proc footprint(filename: string): TCrc32 =
|
||||||
proc externalFileChanged(filename: string): bool =
|
proc externalFileChanged(filename: string): bool =
|
||||||
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
var crcFile = toGeneratedFile(filename.withPackageName, "crc")
|
||||||
var currentCrc = int(footprint(filename))
|
var currentCrc = int(footprint(filename))
|
||||||
var f: TFile
|
var f: File
|
||||||
if open(f, crcFile, fmRead):
|
if open(f, crcFile, fmRead):
|
||||||
var line = newStringOfCap(40)
|
var line = newStringOfCap(40)
|
||||||
if not f.readLine(line): line = "0"
|
if not f.readLine(line): line = "0"
|
||||||
|
|
@ -569,14 +588,16 @@ proc addExternalFileToCompile*(filename: string) =
|
||||||
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
|
if optForceFullMake in gGlobalOptions or externalFileChanged(filename):
|
||||||
appendStr(externalToCompile, filename)
|
appendStr(externalToCompile, filename)
|
||||||
|
|
||||||
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
proc compileCFile(list: TLinkedList, script: var PRope, cmds: var TStringSeq,
|
||||||
isExternal: bool) =
|
prettyCmds: var TStringSeq, isExternal: bool) =
|
||||||
var it = PStrEntry(list.head)
|
var it = PStrEntry(list.head)
|
||||||
while it != nil:
|
while it != nil:
|
||||||
inc(fileCounter) # call the C compiler for the .c file:
|
inc(fileCounter) # call the C compiler for the .c file:
|
||||||
var compileCmd = getCompileCFileCmd(it.data, isExternal)
|
var compileCmd = getCompileCFileCmd(it.data, isExternal)
|
||||||
if optCompileOnly notin gGlobalOptions:
|
if optCompileOnly notin gGlobalOptions:
|
||||||
add(cmds, compileCmd)
|
add(cmds, compileCmd)
|
||||||
|
let (dir, name, ext) = splitFile(it.data)
|
||||||
|
add(prettyCmds, "CC: " & name)
|
||||||
if optGenScript in gGlobalOptions:
|
if optGenScript in gGlobalOptions:
|
||||||
app(script, compileCmd)
|
app(script, compileCmd)
|
||||||
app(script, tnl)
|
app(script, tnl)
|
||||||
|
|
@ -592,18 +613,24 @@ proc callCCompiler*(projectfile: string) =
|
||||||
var c = cCompiler
|
var c = cCompiler
|
||||||
var script: PRope = nil
|
var script: PRope = nil
|
||||||
var cmds: TStringSeq = @[]
|
var cmds: TStringSeq = @[]
|
||||||
compileCFile(toCompile, script, cmds, false)
|
var prettyCmds: TStringSeq = @[]
|
||||||
compileCFile(externalToCompile, script, cmds, true)
|
let prettyCb = proc (idx: int) =
|
||||||
|
echo prettyCmds[idx]
|
||||||
|
compileCFile(toCompile, script, cmds, prettyCmds, false)
|
||||||
|
compileCFile(externalToCompile, script, cmds, prettyCmds, true)
|
||||||
if optCompileOnly notin gGlobalOptions:
|
if optCompileOnly notin gGlobalOptions:
|
||||||
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
||||||
var res = 0
|
var res = 0
|
||||||
if gNumberOfProcessors <= 1:
|
if gNumberOfProcessors <= 1:
|
||||||
for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res)
|
for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res)
|
||||||
elif optListCmd in gGlobalOptions or gVerbosity > 0:
|
elif optListCmd in gGlobalOptions or gVerbosity > 1:
|
||||||
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
|
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
|
||||||
gNumberOfProcessors)
|
gNumberOfProcessors)
|
||||||
else:
|
elif gVerbosity == 1:
|
||||||
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
||||||
|
gNumberOfProcessors, prettyCb)
|
||||||
|
else:
|
||||||
|
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
||||||
gNumberOfProcessors)
|
gNumberOfProcessors)
|
||||||
if res != 0:
|
if res != 0:
|
||||||
if gNumberOfProcessors <= 1:
|
if gNumberOfProcessors <= 1:
|
||||||
|
|
@ -625,7 +652,6 @@ proc callCCompiler*(projectfile: string) =
|
||||||
if optGenStaticLib in gGlobalOptions:
|
if optGenStaticLib in gGlobalOptions:
|
||||||
linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
|
linkCmd = CC[c].buildLib % ["libfile", (libNameTmpl() % gProjectName),
|
||||||
"objfiles", objfiles]
|
"objfiles", objfiles]
|
||||||
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
|
|
||||||
else:
|
else:
|
||||||
var linkerExe = getConfigVar(c, ".linkerexe")
|
var linkerExe = getConfigVar(c, ".linkerexe")
|
||||||
if len(linkerExe) == 0: linkerExe = c.getLinkerExe
|
if len(linkerExe) == 0: linkerExe = c.getLinkerExe
|
||||||
|
|
@ -657,7 +683,11 @@ proc callCCompiler*(projectfile: string) =
|
||||||
"objfiles", objfiles, "exefile", exefile,
|
"objfiles", objfiles, "exefile", exefile,
|
||||||
"nimrod", quoteShell(getPrefixDir()),
|
"nimrod", quoteShell(getPrefixDir()),
|
||||||
"lib", quoteShell(libpath)])
|
"lib", quoteShell(libpath)])
|
||||||
if optCompileOnly notin gGlobalOptions: execExternalProgram(linkCmd)
|
if optCompileOnly notin gGlobalOptions:
|
||||||
|
if gVerbosity == 1:
|
||||||
|
execExternalProgram(linkCmd, "[Linking]")
|
||||||
|
else:
|
||||||
|
execExternalProgram(linkCmd)
|
||||||
else:
|
else:
|
||||||
linkCmd = ""
|
linkCmd = ""
|
||||||
if optGenScript in gGlobalOptions:
|
if optGenScript in gGlobalOptions:
|
||||||
|
|
@ -668,7 +698,7 @@ proc callCCompiler*(projectfile: string) =
|
||||||
proc genMappingFiles(list: TLinkedList): PRope =
|
proc genMappingFiles(list: TLinkedList): PRope =
|
||||||
var it = PStrEntry(list.head)
|
var it = PStrEntry(list.head)
|
||||||
while it != nil:
|
while it != nil:
|
||||||
appf(result, "--file:r\"$1\"$N", [toRope(addFileExt(it.data, cExt))])
|
appf(result, "--file:r\"$1\"$N", [toRope(it.data)])
|
||||||
it = PStrEntry(it.next)
|
it = PStrEntry(it.next)
|
||||||
|
|
||||||
proc writeMapping*(gSymbolMapping: PRope) =
|
proc writeMapping*(gSymbolMapping: PRope) =
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module implements Nimrod's standard template filter.
|
# This module implements Nim's standard template filter.
|
||||||
|
|
||||||
import
|
import
|
||||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||||
|
|
@ -148,7 +148,7 @@ proc parseLine(p: var TTmplParser) =
|
||||||
inc(j)
|
inc(j)
|
||||||
else:
|
else:
|
||||||
if p.x[j] == p.subsChar:
|
if p.x[j] == p.subsChar:
|
||||||
# parse Nimrod expression:
|
# parse Nim expression:
|
||||||
inc(j)
|
inc(j)
|
||||||
case p.x[j]
|
case p.x[j]
|
||||||
of '{':
|
of '{':
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module implements Nimrod's simple filters and helpers for filters.
|
# This module implements Nim's simple filters and helpers for filters.
|
||||||
|
|
||||||
import
|
import
|
||||||
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -838,6 +838,22 @@ proc addAsgnFact*(m: var TModel, key, value: PNode) =
|
||||||
fact.sons[2] = value
|
fact.sons[2] = value
|
||||||
m.add fact
|
m.add fact
|
||||||
|
|
||||||
|
proc sameSubexprs*(m: TModel; a, b: PNode): bool =
|
||||||
|
# This should be used to check whether two *path expressions* refer to the
|
||||||
|
# same memory location according to 'm'. This is tricky:
|
||||||
|
# lock a[i].guard:
|
||||||
|
# ...
|
||||||
|
# access a[i].guarded
|
||||||
|
#
|
||||||
|
# Here a[i] is the same as a[i] iff 'i' and 'a' are not changed via '...'.
|
||||||
|
# However, nil checking requires exactly the same mechanism! But for now
|
||||||
|
# we simply use sameTree and live with the unsoundness of the analysis.
|
||||||
|
var check = newNodeI(nkCall, a.info, 3)
|
||||||
|
check.sons[0] = newSymNode(opEq)
|
||||||
|
check.sons[1] = a
|
||||||
|
check.sons[2] = b
|
||||||
|
result = m.doesImply(check) == impYes
|
||||||
|
|
||||||
proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
|
proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
|
||||||
let branch = n.sons[i]
|
let branch = n.sons[i]
|
||||||
if branch.kind == nkOfBranch:
|
if branch.kind == nkOfBranch:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -15,7 +15,7 @@ import
|
||||||
hashes, strutils
|
hashes, strutils
|
||||||
|
|
||||||
type
|
type
|
||||||
TIdObj* = object of TObject
|
TIdObj* = object of RootObj
|
||||||
id*: int # unique id; use this for comparisons and not the pointers
|
id*: int # unique id; use this for comparisons and not the pointers
|
||||||
|
|
||||||
PIdObj* = ref TIdObj
|
PIdObj* = ref TIdObj
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -53,7 +53,7 @@ proc saveMaxIds*(project: string) =
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
proc loadMaxIds*(project: string) =
|
proc loadMaxIds*(project: string) =
|
||||||
var f: TFile
|
var f: File
|
||||||
if open(f, project.toGid, fmRead):
|
if open(f, project.toGid, fmRead):
|
||||||
var line = newStringOfCap(20)
|
var line = newStringOfCap(20)
|
||||||
if f.readLine(line):
|
if f.readLine(line):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -113,7 +113,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
|
||||||
e = nextIdentIter(it, fromMod.tab)
|
e = nextIdentIter(it, fromMod.tab)
|
||||||
else: rawImportSymbol(c, s)
|
else: rawImportSymbol(c, s)
|
||||||
|
|
||||||
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
|
proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
|
||||||
var i: TTabIter
|
var i: TTabIter
|
||||||
var s = initTabIter(i, fromMod.tab)
|
var s = initTabIter(i, fromMod.tab)
|
||||||
while s != nil:
|
while s != nil:
|
||||||
|
|
@ -126,10 +126,10 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) =
|
||||||
s = nextIter(i, fromMod.tab)
|
s = nextIter(i, fromMod.tab)
|
||||||
|
|
||||||
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
proc importAllSymbols*(c: PContext, fromMod: PSym) =
|
||||||
var exceptSet: TIntSet
|
var exceptSet: IntSet
|
||||||
importAllSymbolsExcept(c, fromMod, exceptSet)
|
importAllSymbolsExcept(c, fromMod, exceptSet)
|
||||||
|
|
||||||
proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) =
|
proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
|
||||||
if n.isNil: return
|
if n.isNil: return
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkExportStmt:
|
of nkExportStmt:
|
||||||
|
|
@ -166,7 +166,7 @@ proc myImportModule(c: PContext, n: PNode): PSym =
|
||||||
|
|
||||||
proc evalImport(c: PContext, n: PNode): PNode =
|
proc evalImport(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
var emptySet: TIntSet
|
var emptySet: IntSet
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var m = myImportModule(c, n.sons[i])
|
var m = myImportModule(c, n.sons[i])
|
||||||
if m != nil:
|
if m != nil:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -33,7 +33,7 @@ import
|
||||||
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
|
||||||
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
|
options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
|
||||||
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
|
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
|
||||||
intsets, cgmeth
|
intsets, cgmeth, lowerings
|
||||||
|
|
||||||
type
|
type
|
||||||
TTarget = enum
|
TTarget = enum
|
||||||
|
|
@ -71,8 +71,8 @@ type
|
||||||
TGlobals = object
|
TGlobals = object
|
||||||
typeInfo, code: PRope
|
typeInfo, code: PRope
|
||||||
forwarded: seq[PSym]
|
forwarded: seq[PSym]
|
||||||
generatedSyms: TIntSet
|
generatedSyms: IntSet
|
||||||
typeInfoGenerated: TIntSet
|
typeInfoGenerated: IntSet
|
||||||
|
|
||||||
PGlobals = ref TGlobals
|
PGlobals = ref TGlobals
|
||||||
PProc = ref TProc
|
PProc = ref TProc
|
||||||
|
|
@ -113,7 +113,7 @@ proc rdLoc(a: TCompRes): PRope {.inline.} =
|
||||||
result = ropef("$1[$2]", a.address, a.res)
|
result = ropef("$1[$2]", a.address, a.res)
|
||||||
|
|
||||||
proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
||||||
options: TOptions): PProc =
|
options: TOptions): PProc =
|
||||||
result = PProc(
|
result = PProc(
|
||||||
blocks: @[],
|
blocks: @[],
|
||||||
options: options,
|
options: options,
|
||||||
|
|
@ -601,15 +601,13 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
app(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
|
app(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
|
||||||
if i < length and n.sons[i].kind == nkFinally:
|
if i < length and n.sons[i].kind == nkFinally:
|
||||||
gen(p, n.sons[i].sons[0], a)
|
genStmt(p, n.sons[i].sons[0])
|
||||||
moveInto(p, a, r)
|
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
app(p.body, "}" & tnl)
|
app(p.body, "}" & tnl)
|
||||||
if p.target == targetLua:
|
if p.target == targetLua:
|
||||||
# we need to repeat the finally block for Lua ...
|
# we need to repeat the finally block for Lua ...
|
||||||
if i < length and n.sons[i].kind == nkFinally:
|
if i < length and n.sons[i].kind == nkFinally:
|
||||||
gen(p, n.sons[i].sons[0], a)
|
genStmt(p, n.sons[i].sons[0])
|
||||||
moveInto(p, a, r)
|
|
||||||
|
|
||||||
proc genRaiseStmt(p: PProc, n: PNode) =
|
proc genRaiseStmt(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
|
|
@ -724,7 +722,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
|
if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
|
||||||
var sym = n.sons[0].sym
|
var sym = n.sons[0].sym
|
||||||
sym.loc.k = locOther
|
sym.loc.k = locOther
|
||||||
sym.loc.a = idx
|
sym.position = idx+1
|
||||||
setLen(p.blocks, idx + 1)
|
setLen(p.blocks, idx + 1)
|
||||||
p.blocks[idx].id = - p.unique # negative because it isn't used yet
|
p.blocks[idx].id = - p.unique # negative because it isn't used yet
|
||||||
let labl = p.unique
|
let labl = p.unique
|
||||||
|
|
@ -741,7 +739,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
|
||||||
assert(n.sons[0].kind == nkSym)
|
assert(n.sons[0].kind == nkSym)
|
||||||
let sym = n.sons[0].sym
|
let sym = n.sons[0].sym
|
||||||
assert(sym.loc.k == locOther)
|
assert(sym.loc.k == locOther)
|
||||||
idx = sym.loc.a
|
idx = sym.position-1
|
||||||
else:
|
else:
|
||||||
# an unnamed 'break' can only break a loop after 'transf' pass:
|
# an unnamed 'break' can only break a loop after 'transf' pass:
|
||||||
idx = len(p.blocks) - 1
|
idx = len(p.blocks) - 1
|
||||||
|
|
@ -942,22 +940,21 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
case s.kind
|
case s.kind
|
||||||
of skVar, skLet, skResult:
|
of skVar, skLet, skResult:
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
if mapType(n.typ) == etyObject:
|
if mapType(n.sons[0].typ) == etyObject:
|
||||||
# make addr() a no-op:
|
# make addr() a no-op:
|
||||||
r.typ = etyNone
|
r.typ = etyNone
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
r.address = nil
|
r.address = nil
|
||||||
elif sfGlobal in s.flags:
|
elif {sfGlobal, sfAddrTaken} * s.flags != {}:
|
||||||
# globals are always indirect accessible
|
# for ease of code generation, we do not distinguish between
|
||||||
r.typ = etyBaseIndex
|
# sfAddrTaken and sfGlobal.
|
||||||
r.address = toRope("Globals")
|
|
||||||
r.res = makeJSString(ropeToStr(s.loc.r))
|
|
||||||
elif sfAddrTaken in s.flags:
|
|
||||||
r.typ = etyBaseIndex
|
r.typ = etyBaseIndex
|
||||||
r.address = s.loc.r
|
r.address = s.loc.r
|
||||||
r.res = toRope("0")
|
r.res = toRope("0")
|
||||||
else:
|
else:
|
||||||
internalError(n.info, "genAddr: 4")
|
# 'var openArray' for instance produces an 'addr' but this is harmless:
|
||||||
|
gen(p, n.sons[0], r)
|
||||||
|
#internalError(n.info, "genAddr: 4 " & renderTree(n))
|
||||||
else: internalError(n.info, "genAddr: 2")
|
else: internalError(n.info, "genAddr: 2")
|
||||||
of nkCheckedFieldExpr:
|
of nkCheckedFieldExpr:
|
||||||
genCheckedFieldAddr(p, n, r)
|
genCheckedFieldAddr(p, n, r)
|
||||||
|
|
@ -981,7 +978,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of skVar, skLet, skParam, skTemp, skResult:
|
of skVar, skLet, skParam, skTemp, skResult:
|
||||||
if s.loc.r == nil:
|
if s.loc.r == nil:
|
||||||
internalError(n.info, "symbol has no generated name: " & s.name.s)
|
internalError(n.info, "symbol has no generated name: " & s.name.s)
|
||||||
var k = mapType(s.typ)
|
let k = mapType(s.typ)
|
||||||
if k == etyBaseIndex:
|
if k == etyBaseIndex:
|
||||||
r.typ = etyBaseIndex
|
r.typ = etyBaseIndex
|
||||||
if {sfAddrTaken, sfGlobal} * s.flags != {}:
|
if {sfAddrTaken, sfGlobal} * s.flags != {}:
|
||||||
|
|
@ -990,7 +987,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
else:
|
else:
|
||||||
r.address = s.loc.r
|
r.address = s.loc.r
|
||||||
r.res = con(s.loc.r, "_Idx")
|
r.res = con(s.loc.r, "_Idx")
|
||||||
elif k != etyObject and sfAddrTaken in s.flags:
|
elif k != etyObject and {sfAddrTaken, sfGlobal} * s.flags != {}:
|
||||||
r.res = ropef("$1[0]", [s.loc.r])
|
r.res = ropef("$1[0]", [s.loc.r])
|
||||||
else:
|
else:
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
|
|
@ -1078,8 +1075,16 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
|
|
||||||
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
useMagic(p, "rawEcho")
|
useMagic(p, "rawEcho")
|
||||||
app(r.res, "rawEcho")
|
app(r.res, "rawEcho(")
|
||||||
genArgs(p, n, r)
|
let n = n[1].skipConv
|
||||||
|
internalAssert n.kind == nkBracket
|
||||||
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
let it = n.sons[i]
|
||||||
|
if it.typ.isCompileTimeOnly: continue
|
||||||
|
if i > 0: app(r.res, ", ")
|
||||||
|
genArg(p, it, r)
|
||||||
|
app(r.res, ")")
|
||||||
|
r.kind = resExpr
|
||||||
|
|
||||||
proc putToSeq(s: string, indirect: bool): PRope =
|
proc putToSeq(s: string, indirect: bool): PRope =
|
||||||
result = toRope(s)
|
result = toRope(s)
|
||||||
|
|
@ -1162,8 +1167,9 @@ proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
|
||||||
internalError("createVar: " & $t.kind)
|
internalError("createVar: " & $t.kind)
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc isIndirect(v: PSym): bool =
|
proc isIndirect(v: PSym): bool =
|
||||||
result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and
|
result = {sfAddrTaken, sfGlobal} * v.flags != {} and
|
||||||
|
(mapType(v.typ) != etyObject) and
|
||||||
v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
|
v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
|
||||||
|
|
||||||
proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||||
|
|
@ -1203,13 +1209,17 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||||
proc genVarStmt(p: PProc, n: PNode) =
|
proc genVarStmt(p: PProc, n: PNode) =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind != nkCommentStmt:
|
||||||
assert(a.kind == nkIdentDefs)
|
if a.kind == nkVarTuple:
|
||||||
assert(a.sons[0].kind == nkSym)
|
let unpacked = lowerTupleUnpacking(a, p.prc)
|
||||||
var v = a.sons[0].sym
|
genStmt(p, unpacked)
|
||||||
if lfNoDecl in v.loc.flags: continue
|
else:
|
||||||
genLineDir(p, a)
|
assert(a.kind == nkIdentDefs)
|
||||||
genVarInit(p, v, a.sons[2])
|
assert(a.sons[0].kind == nkSym)
|
||||||
|
var v = a.sons[0].sym
|
||||||
|
if lfNoDecl notin v.loc.flags:
|
||||||
|
genLineDir(p, a)
|
||||||
|
genVarInit(p, v, a.sons[2])
|
||||||
|
|
||||||
proc genConstant(p: PProc, c: PSym) =
|
proc genConstant(p: PProc, c: PSym) =
|
||||||
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
|
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
|
||||||
|
|
@ -1425,7 +1435,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.res = toRope("{")
|
r.res = toRope("{")
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(1, sonsLen(n) - 1):
|
||||||
if i > 0: app(r.res, ", ")
|
if i > 1: app(r.res, ", ")
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
internalAssert it.kind == nkExprColonExpr
|
internalAssert it.kind == nkExprColonExpr
|
||||||
gen(p, it.sons[1], a)
|
gen(p, it.sons[1], a)
|
||||||
|
|
@ -1654,6 +1664,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.res = nil
|
r.res = nil
|
||||||
of nkGotoState, nkState:
|
of nkGotoState, nkState:
|
||||||
internalError(n.info, "first class iterators not implemented")
|
internalError(n.info, "first class iterators not implemented")
|
||||||
|
of nkPragmaBlock: gen(p, n.lastSon, r)
|
||||||
else: internalError(n.info, "gen: unknown node type: " & $n.kind)
|
else: internalError(n.info, "gen: unknown node type: " & $n.kind)
|
||||||
|
|
||||||
var globals: PGlobals
|
var globals: PGlobals
|
||||||
|
|
@ -1664,11 +1675,11 @@ proc newModule(module: PSym): BModule =
|
||||||
if globals == nil: globals = newGlobals()
|
if globals == nil: globals = newGlobals()
|
||||||
|
|
||||||
proc genHeader(): PRope =
|
proc genHeader(): PRope =
|
||||||
result = ropef("/* Generated by the Nimrod Compiler v$1 */$n" &
|
result = ropef("/* Generated by the Nim Compiler v$1 */$n" &
|
||||||
"/* (c) 2014 Andreas Rumpf */$n$n" &
|
"/* (c) 2014 Andreas Rumpf */$n$n" &
|
||||||
"$nvar Globals = this;$n" &
|
|
||||||
"var framePtr = null;$n" &
|
"var framePtr = null;$n" &
|
||||||
"var excHandler = null;$n",
|
"var excHandler = null;$n" &
|
||||||
|
"var lastJSError = null;$n",
|
||||||
[toRope(VersionAsString)])
|
[toRope(VersionAsString)])
|
||||||
|
|
||||||
proc genModule(p: PProc, n: PNode) =
|
proc genModule(p: PProc, n: PNode) =
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -128,7 +128,7 @@ type
|
||||||
obj: PType
|
obj: PType
|
||||||
|
|
||||||
PEnv = ref TEnv
|
PEnv = ref TEnv
|
||||||
TEnv {.final.} = object of TObject
|
TEnv {.final.} = object of RootObj
|
||||||
attachedNode, replacementNode: PNode
|
attachedNode, replacementNode: PNode
|
||||||
createdVar: PNode # if != nil it is a used environment; for closure
|
createdVar: PNode # if != nil it is a used environment; for closure
|
||||||
# iterators this can be 'envParam.env'
|
# iterators this can be 'envParam.env'
|
||||||
|
|
@ -140,12 +140,12 @@ type
|
||||||
fn: PSym # function that belongs to this scope;
|
fn: PSym # function that belongs to this scope;
|
||||||
# if up.fn != fn then we cross function boundaries.
|
# if up.fn != fn then we cross function boundaries.
|
||||||
# This is an important case to consider.
|
# This is an important case to consider.
|
||||||
vars: TIntSet # variables belonging to this environment
|
vars: IntSet # variables belonging to this environment
|
||||||
|
|
||||||
TOuterContext = object
|
TOuterContext = object
|
||||||
fn: PSym # may also be a module!
|
fn: PSym # may also be a module!
|
||||||
head: PEnv
|
head: PEnv
|
||||||
capturedVars, processed: TIntSet
|
capturedVars, processed: IntSet
|
||||||
localsToAccess: TIdNodeTable
|
localsToAccess: TIdNodeTable
|
||||||
lambdasToEnv: TIdTable # PSym->PEnv mapping
|
lambdasToEnv: TIdTable # PSym->PEnv mapping
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -21,10 +21,10 @@ import
|
||||||
|
|
||||||
const
|
const
|
||||||
MaxLineLength* = 80 # lines longer than this lead to a warning
|
MaxLineLength* = 80 # lines longer than this lead to a warning
|
||||||
numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'}
|
||||||
SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
||||||
SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
|
SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
|
||||||
OpChars*: TCharSet = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
|
OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.',
|
||||||
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
|
'|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'}
|
||||||
|
|
||||||
# don't forget to update the 'highlite' module if these charsets should change
|
# don't forget to update the 'highlite' module if these charsets should change
|
||||||
|
|
@ -35,9 +35,10 @@ type
|
||||||
tkSymbol, # keywords:
|
tkSymbol, # keywords:
|
||||||
tkAddr, tkAnd, tkAs, tkAsm, tkAtomic,
|
tkAddr, tkAnd, tkAs, tkAsm, tkAtomic,
|
||||||
tkBind, tkBlock, tkBreak, tkCase, tkCast,
|
tkBind, tkBlock, tkBreak, tkCase, tkCast,
|
||||||
tkConst, tkContinue, tkConverter, tkDiscard, tkDistinct, tkDiv, tkDo,
|
tkConst, tkContinue, tkConverter,
|
||||||
|
tkDefer, tkDiscard, tkDistinct, tkDiv, tkDo,
|
||||||
tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport,
|
tkElif, tkElse, tkEnd, tkEnum, tkExcept, tkExport,
|
||||||
tkFinally, tkFor, tkFrom,
|
tkFinally, tkFor, tkFrom, tkFunc,
|
||||||
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
|
tkGeneric, tkIf, tkImport, tkIn, tkInclude, tkInterface,
|
||||||
tkIs, tkIsnot, tkIterator,
|
tkIs, tkIsnot, tkIterator,
|
||||||
tkLet,
|
tkLet,
|
||||||
|
|
@ -71,11 +72,12 @@ const
|
||||||
"tkSymbol",
|
"tkSymbol",
|
||||||
"addr", "and", "as", "asm", "atomic",
|
"addr", "and", "as", "asm", "atomic",
|
||||||
"bind", "block", "break", "case", "cast",
|
"bind", "block", "break", "case", "cast",
|
||||||
"const", "continue", "converter", "discard", "distinct", "div", "do",
|
"const", "continue", "converter",
|
||||||
|
"defer", "discard", "distinct", "div", "do",
|
||||||
"elif", "else", "end", "enum", "except", "export",
|
"elif", "else", "end", "enum", "except", "export",
|
||||||
"finally", "for", "from", "generic", "if",
|
"finally", "for", "from", "func", "generic", "if",
|
||||||
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
"import", "in", "include", "interface", "is", "isnot", "iterator",
|
||||||
"let",
|
"let",
|
||||||
"macro", "method", "mixin", "mod",
|
"macro", "method", "mixin", "mod",
|
||||||
"nil", "not", "notin", "object", "of", "or",
|
"nil", "not", "notin", "object", "of", "or",
|
||||||
"out", "proc", "ptr", "raise", "ref", "return",
|
"out", "proc", "ptr", "raise", "ref", "return",
|
||||||
|
|
@ -102,7 +104,7 @@ type
|
||||||
# so that it is the correct default value
|
# so that it is the correct default value
|
||||||
base2, base8, base16
|
base2, base8, base16
|
||||||
|
|
||||||
TToken* = object # a Nimrod token
|
TToken* = object # a Nim token
|
||||||
tokType*: TTokType # the type of the token
|
tokType*: TTokType # the type of the token
|
||||||
indent*: int # the indentation; != -1 if the token has been
|
indent*: int # the indentation; != -1 if the token has been
|
||||||
# preceeded with indentation
|
# preceeded with indentation
|
||||||
|
|
@ -116,7 +118,8 @@ type
|
||||||
literal*: string # the parsed (string) literal; and
|
literal*: string # the parsed (string) literal; and
|
||||||
# documentation comments are here too
|
# documentation comments are here too
|
||||||
line*, col*: int
|
line*, col*: int
|
||||||
|
|
||||||
|
TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
|
||||||
TLexer* = object of TBaseLexer
|
TLexer* = object of TBaseLexer
|
||||||
fileIdx*: int32
|
fileIdx*: int32
|
||||||
indentAhead*: int # if > 0 an indendation has already been read
|
indentAhead*: int # if > 0 an indendation has already been read
|
||||||
|
|
@ -124,7 +127,7 @@ type
|
||||||
# needs so much look-ahead
|
# needs so much look-ahead
|
||||||
currLineIndent*: int
|
currLineIndent*: int
|
||||||
strongSpaces*: bool
|
strongSpaces*: bool
|
||||||
|
errorHandler*: TErrorHandler
|
||||||
|
|
||||||
var gLinesCompiled*: int # all lines that have been compiled
|
var gLinesCompiled*: int # all lines that have been compiled
|
||||||
|
|
||||||
|
|
@ -148,7 +151,7 @@ proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
|
||||||
proc isKeyword(kind: TTokType): bool =
|
proc isKeyword(kind: TTokType): bool =
|
||||||
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
|
result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh)
|
||||||
|
|
||||||
proc isNimrodIdentifier*(s: string): bool =
|
proc isNimIdentifier*(s: string): bool =
|
||||||
if s[0] in SymStartChars:
|
if s[0] in SymStartChars:
|
||||||
var i = 1
|
var i = 1
|
||||||
while i < s.len:
|
while i < s.len:
|
||||||
|
|
@ -222,14 +225,20 @@ proc getColumn(L: TLexer): int =
|
||||||
proc getLineInfo(L: TLexer): TLineInfo =
|
proc getLineInfo(L: TLexer): TLineInfo =
|
||||||
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
|
result = newLineInfo(L.fileIdx, L.lineNumber, getColNumber(L, L.bufpos))
|
||||||
|
|
||||||
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
|
proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
|
||||||
msgs.message(getLineInfo(L), msg, arg)
|
if L.errorHandler.isNil:
|
||||||
|
msgs.message(info, msg, arg)
|
||||||
|
else:
|
||||||
|
L.errorHandler(info, msg, arg)
|
||||||
|
|
||||||
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
proc lexMessage(L: TLexer, msg: TMsgKind, arg = "") =
|
||||||
|
L.dispMessage(getLineInfo(L), msg, arg)
|
||||||
|
|
||||||
|
proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") =
|
||||||
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
|
var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart)
|
||||||
msgs.message(info, msg, arg)
|
L.dispMessage(info, msg, arg)
|
||||||
|
|
||||||
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
|
||||||
var pos = L.bufpos # use registers for pos, buf
|
var pos = L.bufpos # use registers for pos, buf
|
||||||
var buf = L.buf
|
var buf = L.buf
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -246,7 +255,7 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) =
|
||||||
inc(pos)
|
inc(pos)
|
||||||
L.bufpos = pos
|
L.bufpos = pos
|
||||||
|
|
||||||
proc matchTwoChars(L: TLexer, first: char, second: TCharSet): bool =
|
proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool =
|
||||||
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
|
result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second)
|
||||||
|
|
||||||
proc isFloatLiteral(s: string): bool =
|
proc isFloatLiteral(s: string): bool =
|
||||||
|
|
@ -429,9 +438,9 @@ proc getNumber(L: var TLexer): TToken =
|
||||||
elif result.tokType == tkInt16Lit and
|
elif result.tokType == tkInt16Lit and
|
||||||
(result.iNumber < int16.low or result.iNumber > int16.high):
|
(result.iNumber < int16.low or result.iNumber > int16.high):
|
||||||
lexMessage(L, errNumberOutOfRange, result.literal)
|
lexMessage(L, errNumberOutOfRange, result.literal)
|
||||||
except EInvalidValue:
|
except ValueError:
|
||||||
lexMessage(L, errInvalidNumber, result.literal)
|
lexMessage(L, errInvalidNumber, result.literal)
|
||||||
except EOverflow, EOutOfRange:
|
except OverflowError, RangeError:
|
||||||
lexMessage(L, errNumberOutOfRange, result.literal)
|
lexMessage(L, errNumberOutOfRange, result.literal)
|
||||||
L.bufpos = endpos
|
L.bufpos = endpos
|
||||||
|
|
||||||
|
|
@ -482,7 +491,7 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
|
||||||
add(tok.literal, VT)
|
add(tok.literal, VT)
|
||||||
inc(L.bufpos)
|
inc(L.bufpos)
|
||||||
of 't', 'T':
|
of 't', 'T':
|
||||||
add(tok.literal, Tabulator)
|
add(tok.literal, '\t')
|
||||||
inc(L.bufpos)
|
inc(L.bufpos)
|
||||||
of '\'', '\"':
|
of '\'', '\"':
|
||||||
add(tok.literal, L.buf[L.bufpos])
|
add(tok.literal, L.buf[L.bufpos])
|
||||||
|
|
@ -519,7 +528,7 @@ proc handleCRLF(L: var TLexer, pos: int): int =
|
||||||
lexMessagePos(L, hintLineTooLong, pos)
|
lexMessagePos(L, hintLineTooLong, pos)
|
||||||
|
|
||||||
if optEmbedOrigSrc in gGlobalOptions:
|
if optEmbedOrigSrc in gGlobalOptions:
|
||||||
let lineStart = cast[TAddress](L.buf) + L.lineStart
|
let lineStart = cast[ByteAddress](L.buf) + L.lineStart
|
||||||
let line = newString(cast[cstring](lineStart), col)
|
let line = newString(cast[cstring](lineStart), col)
|
||||||
addSourceLine(L.fileIdx, line)
|
addSourceLine(L.fileIdx, line)
|
||||||
|
|
||||||
|
|
@ -659,28 +668,32 @@ proc getOperator(L: var TLexer, tok: var TToken) =
|
||||||
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
|
if buf[pos] in {CR, LF, nimlexbase.EndOfFile}:
|
||||||
tok.strongSpaceB = -1
|
tok.strongSpaceB = -1
|
||||||
|
|
||||||
proc scanComment(L: var TLexer, tok: var TToken) =
|
proc scanComment(L: var TLexer, tok: var TToken) =
|
||||||
var pos = L.bufpos
|
var pos = L.bufpos
|
||||||
var buf = L.buf
|
var buf = L.buf
|
||||||
# a comment ends if the next line does not start with the # on the same
|
when not defined(nimfix):
|
||||||
# column after only whitespace
|
assert buf[pos+1] == '#'
|
||||||
|
if buf[pos+2] == '[':
|
||||||
|
lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['")
|
||||||
tok.tokType = tkComment
|
tok.tokType = tkComment
|
||||||
# iNumber contains the number of '\n' in the token
|
# iNumber contains the number of '\n' in the token
|
||||||
tok.iNumber = 0
|
tok.iNumber = 0
|
||||||
var col = getColNumber(L, pos)
|
when defined(nimfix):
|
||||||
|
var col = getColNumber(L, pos)
|
||||||
while true:
|
while true:
|
||||||
var lastBackslash = -1
|
var lastBackslash = -1
|
||||||
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}:
|
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}:
|
||||||
if buf[pos] == '\\': lastBackslash = pos+1
|
if buf[pos] == '\\': lastBackslash = pos+1
|
||||||
add(tok.literal, buf[pos])
|
add(tok.literal, buf[pos])
|
||||||
inc(pos)
|
inc(pos)
|
||||||
if lastBackslash > 0:
|
when defined(nimfix):
|
||||||
# a backslash is a continuation character if only followed by spaces
|
if lastBackslash > 0:
|
||||||
# plus a newline:
|
# a backslash is a continuation character if only followed by spaces
|
||||||
while buf[lastBackslash] == ' ': inc(lastBackslash)
|
# plus a newline:
|
||||||
if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}:
|
while buf[lastBackslash] == ' ': inc(lastBackslash)
|
||||||
# false positive:
|
if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}:
|
||||||
lastBackslash = -1
|
# false positive:
|
||||||
|
lastBackslash = -1
|
||||||
|
|
||||||
pos = handleCRLF(L, pos)
|
pos = handleCRLF(L, pos)
|
||||||
buf = L.buf
|
buf = L.buf
|
||||||
|
|
@ -688,9 +701,16 @@ proc scanComment(L: var TLexer, tok: var TToken) =
|
||||||
while buf[pos] == ' ':
|
while buf[pos] == ' ':
|
||||||
inc(pos)
|
inc(pos)
|
||||||
inc(indent)
|
inc(indent)
|
||||||
if buf[pos] == '#' and (col == indent or lastBackslash > 0):
|
|
||||||
|
when defined(nimfix):
|
||||||
|
template doContinue(): expr =
|
||||||
|
buf[pos] == '#' and (col == indent or lastBackslash > 0)
|
||||||
|
else:
|
||||||
|
template doContinue(): expr =
|
||||||
|
buf[pos] == '#' and buf[pos+1] == '#'
|
||||||
|
if doContinue():
|
||||||
tok.literal.add "\n"
|
tok.literal.add "\n"
|
||||||
col = indent
|
when defined(nimfix): col = indent
|
||||||
inc tok.iNumber
|
inc tok.iNumber
|
||||||
else:
|
else:
|
||||||
if buf[pos] > ' ':
|
if buf[pos] > ' ':
|
||||||
|
|
@ -707,7 +727,7 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||||
of ' ':
|
of ' ':
|
||||||
inc(pos)
|
inc(pos)
|
||||||
inc(tok.strongSpaceA)
|
inc(tok.strongSpaceA)
|
||||||
of Tabulator:
|
of '\t':
|
||||||
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
|
lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
|
||||||
inc(pos)
|
inc(pos)
|
||||||
of CR, LF:
|
of CR, LF:
|
||||||
|
|
@ -718,10 +738,24 @@ proc skip(L: var TLexer, tok: var TToken) =
|
||||||
inc(pos)
|
inc(pos)
|
||||||
inc(indent)
|
inc(indent)
|
||||||
tok.strongSpaceA = 0
|
tok.strongSpaceA = 0
|
||||||
if buf[pos] > ' ':
|
when defined(nimfix):
|
||||||
|
template doBreak(): expr = buf[pos] > ' '
|
||||||
|
else:
|
||||||
|
template doBreak(): expr =
|
||||||
|
buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#')
|
||||||
|
if doBreak():
|
||||||
tok.indent = indent
|
tok.indent = indent
|
||||||
L.currLineIndent = indent
|
L.currLineIndent = indent
|
||||||
break
|
break
|
||||||
|
of '#':
|
||||||
|
when defined(nimfix):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# do not skip documentation comment:
|
||||||
|
if buf[pos+1] == '#': break
|
||||||
|
if buf[pos+1] == '[':
|
||||||
|
lexMessagePos(L, warnDeprecated, pos, "use '# [' instead; '#['")
|
||||||
|
while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos)
|
||||||
else:
|
else:
|
||||||
break # EndOfFile also leaves the loop
|
break # EndOfFile also leaves the loop
|
||||||
L.bufpos = pos
|
L.bufpos = pos
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
import os
|
import os
|
||||||
type
|
type
|
||||||
PListEntry* = ref TListEntry
|
PListEntry* = ref TListEntry
|
||||||
TListEntry* = object of TObject
|
TListEntry* = object of RootObj
|
||||||
prev*, next*: PListEntry
|
prev*, next*: PListEntry
|
||||||
|
|
||||||
TStrEntry* = object of TListEntry
|
TStrEntry* = object of TListEntry
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -21,9 +21,9 @@ type
|
||||||
llsString, # stream encapsulates a string
|
llsString, # stream encapsulates a string
|
||||||
llsFile, # stream encapsulates a file
|
llsFile, # stream encapsulates a file
|
||||||
llsStdIn # stream encapsulates stdin
|
llsStdIn # stream encapsulates stdin
|
||||||
TLLStream* = object of TObject
|
TLLStream* = object of RootObj
|
||||||
kind*: TLLStreamKind # accessible for low-level access (lexbase uses this)
|
kind*: TLLStreamKind # accessible for low-level access (lexbase uses this)
|
||||||
f*: TFile
|
f*: File
|
||||||
s*: string
|
s*: string
|
||||||
rd*, wr*: int # for string streams
|
rd*, wr*: int # for string streams
|
||||||
lineOffset*: int # for fake stdin line numbers
|
lineOffset*: int # for fake stdin line numbers
|
||||||
|
|
@ -31,8 +31,8 @@ type
|
||||||
PLLStream* = ref TLLStream
|
PLLStream* = ref TLLStream
|
||||||
|
|
||||||
proc llStreamOpen*(data: string): PLLStream
|
proc llStreamOpen*(data: string): PLLStream
|
||||||
proc llStreamOpen*(f: var TFile): PLLStream
|
proc llStreamOpen*(f: var File): PLLStream
|
||||||
proc llStreamOpen*(filename: string, mode: TFileMode): PLLStream
|
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream
|
||||||
proc llStreamOpen*(): PLLStream
|
proc llStreamOpen*(): PLLStream
|
||||||
proc llStreamOpenStdIn*(): PLLStream
|
proc llStreamOpenStdIn*(): PLLStream
|
||||||
proc llStreamClose*(s: PLLStream)
|
proc llStreamClose*(s: PLLStream)
|
||||||
|
|
@ -50,12 +50,12 @@ proc llStreamOpen(data: string): PLLStream =
|
||||||
result.s = data
|
result.s = data
|
||||||
result.kind = llsString
|
result.kind = llsString
|
||||||
|
|
||||||
proc llStreamOpen(f: var TFile): PLLStream =
|
proc llStreamOpen(f: var File): PLLStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.f = f
|
result.f = f
|
||||||
result.kind = llsFile
|
result.kind = llsFile
|
||||||
|
|
||||||
proc llStreamOpen(filename: string, mode: TFileMode): PLLStream =
|
proc llStreamOpen(filename: string, mode: FileMode): PLLStream =
|
||||||
new(result)
|
new(result)
|
||||||
result.kind = llsFile
|
result.kind = llsFile
|
||||||
if not open(result.f, filename, mode): result = nil
|
if not open(result.f, filename, mode): result = nil
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ type
|
||||||
mode*: TOverloadIterMode
|
mode*: TOverloadIterMode
|
||||||
symChoiceIndex*: int
|
symChoiceIndex*: int
|
||||||
scope*: PScope
|
scope*: PScope
|
||||||
inSymChoice: TIntSet
|
inSymChoice: IntSet
|
||||||
|
|
||||||
proc getSymRepr*(s: PSym): string =
|
proc getSymRepr*(s: PSym): string =
|
||||||
case s.kind
|
case s.kind
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -51,13 +51,14 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
|
||||||
incl(temp.flags, sfFromGeneric)
|
incl(temp.flags, sfFromGeneric)
|
||||||
|
|
||||||
var v = newNodeI(nkVarSection, value.info)
|
var v = newNodeI(nkVarSection, value.info)
|
||||||
v.addVar(newSymNode(temp))
|
let tempAsNode = newSymNode(temp)
|
||||||
|
v.addVar(tempAsNode)
|
||||||
result.add(v)
|
result.add(v)
|
||||||
|
|
||||||
result.add newAsgnStmt(newSymNode(temp), value)
|
result.add newAsgnStmt(tempAsNode, value)
|
||||||
for i in 0 .. n.len-3:
|
for i in 0 .. n.len-3:
|
||||||
if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
|
if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
|
||||||
result.add newAsgnStmt(n.sons[i], newTupleAccess(value, i))
|
result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
|
||||||
|
|
||||||
proc createObj*(owner: PSym, info: TLineInfo): PType =
|
proc createObj*(owner: PSym, info: TLineInfo): PType =
|
||||||
result = newType(tyObject, owner)
|
result = newType(tyObject, owner)
|
||||||
|
|
@ -204,7 +205,7 @@ proc flowVarKind(t: PType): TFlowVarKind =
|
||||||
else: fvBlob
|
else: fvBlob
|
||||||
|
|
||||||
proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
|
proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
|
||||||
v: PNode): PSym =
|
v: PNode; useShallowCopy=false): PSym =
|
||||||
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
|
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
incl(result.flags, sfFromGeneric)
|
incl(result.flags, sfFromGeneric)
|
||||||
|
|
@ -215,11 +216,14 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
|
||||||
vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
|
vpart.sons[2] = if varInit.isNil: v else: ast.emptyNode
|
||||||
varSection.add vpart
|
varSection.add vpart
|
||||||
if varInit != nil:
|
if varInit != nil:
|
||||||
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
|
if useShallowCopy:
|
||||||
deepCopyCall.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
|
varInit.add newFastAsgnStmt(newSymNode(result), v)
|
||||||
deepCopyCall.sons[1] = newSymNode(result)
|
else:
|
||||||
deepCopyCall.sons[2] = v
|
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
|
||||||
varInit.add deepCopyCall
|
deepCopyCall.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
|
||||||
|
deepCopyCall.sons[1] = newSymNode(result)
|
||||||
|
deepCopyCall.sons[2] = v
|
||||||
|
varInit.add deepCopyCall
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
We generate roughly this:
|
We generate roughly this:
|
||||||
|
|
@ -261,7 +265,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
||||||
threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
|
threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
|
||||||
barrier.typ, barrier)
|
barrier.typ, barrier)
|
||||||
body.add varSection2
|
body.add varSection2
|
||||||
body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode)
|
body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode)
|
||||||
var threadLocalProm: PSym
|
var threadLocalProm: PSym
|
||||||
if spawnKind == srByVar:
|
if spawnKind == srByVar:
|
||||||
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
|
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
|
||||||
|
|
@ -276,7 +280,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
||||||
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
|
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
|
||||||
"owner", fv.info), threadParam.newSymNode)
|
"owner", fv.info), threadParam.newSymNode)
|
||||||
|
|
||||||
body.add callCodeGenProc("nimArgsPassingDone", threadParam.newSymNode)
|
body.add callCodegenProc("nimArgsPassingDone", threadParam.newSymNode)
|
||||||
if spawnKind == srByVar:
|
if spawnKind == srByVar:
|
||||||
body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
|
body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
|
||||||
elif fv != nil:
|
elif fv != nil:
|
||||||
|
|
@ -286,14 +290,20 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
|
||||||
typeToString(fv.typ.sons[1]))
|
typeToString(fv.typ.sons[1]))
|
||||||
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
|
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
|
||||||
if fk == fvGC: "data" else: "blob", fv.info), call)
|
if fk == fvGC: "data" else: "blob", fv.info), call)
|
||||||
|
if fk == fvGC:
|
||||||
|
let incRefCall = newNodeI(nkCall, fv.info, 2)
|
||||||
|
incRefCall.sons[0] = newSymNode(createMagic("GCref", mGCref))
|
||||||
|
incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
|
||||||
|
"data", fv.info)
|
||||||
|
body.add incRefCall
|
||||||
if barrier == nil:
|
if barrier == nil:
|
||||||
# by now 'fv' is shared and thus might have beeen overwritten! we need
|
# by now 'fv' is shared and thus might have beeen overwritten! we need
|
||||||
# to use the thread-local view instead:
|
# to use the thread-local view instead:
|
||||||
body.add callCodeGenProc("nimFlowVarSignal", threadLocalProm.newSymNode)
|
body.add callCodegenProc("nimFlowVarSignal", threadLocalProm.newSymNode)
|
||||||
else:
|
else:
|
||||||
body.add call
|
body.add call
|
||||||
if barrier != nil:
|
if barrier != nil:
|
||||||
body.add callCodeGenProc("barrierLeave", threadLocalBarrier.newSymNode)
|
body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode)
|
||||||
|
|
||||||
var params = newNodeI(nkFormalParams, f.info)
|
var params = newNodeI(nkFormalParams, f.info)
|
||||||
params.add emptyNode
|
params.add emptyNode
|
||||||
|
|
@ -414,7 +424,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
|
||||||
|
|
||||||
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ,
|
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ,
|
||||||
indirectAccess(castExpr, fieldA, n.info))
|
indirectAccess(castExpr, fieldA, n.info),
|
||||||
|
useShallowCopy=true)
|
||||||
slice.sons[2] = threadLocal.newSymNode
|
slice.sons[2] = threadLocal.newSymNode
|
||||||
else:
|
else:
|
||||||
let a = genAddrOf(n)
|
let a = genAddrOf(n)
|
||||||
|
|
@ -428,7 +439,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
|
slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
|
||||||
|
|
||||||
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ,
|
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ,
|
||||||
indirectAccess(castExpr, fieldB, n.info))
|
indirectAccess(castExpr, fieldB, n.info),
|
||||||
|
useShallowCopy=true)
|
||||||
slice.sons[3] = threadLocal.newSymNode
|
slice.sons[3] = threadLocal.newSymNode
|
||||||
call.add slice
|
call.add slice
|
||||||
elif (let size = computeSize(argType); size < 0 or size > 16) and
|
elif (let size = computeSize(argType); size < 0 or size > 16) and
|
||||||
|
|
@ -439,7 +451,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
objType.addField(field)
|
objType.addField(field)
|
||||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
|
||||||
let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ,
|
let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ,
|
||||||
indirectAccess(castExpr, field, n.info))
|
indirectAccess(castExpr, field, n.info),
|
||||||
|
useShallowCopy=true)
|
||||||
call.add(genDeref(threadLocal.newSymNode))
|
call.add(genDeref(threadLocal.newSymNode))
|
||||||
else:
|
else:
|
||||||
# boring case
|
# boring case
|
||||||
|
|
@ -448,7 +461,8 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
|
||||||
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
|
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
|
||||||
let threadLocal = addLocalVar(varSection, varInit,
|
let threadLocal = addLocalVar(varSection, varInit,
|
||||||
objType.owner, field.typ,
|
objType.owner, field.typ,
|
||||||
indirectAccess(castExpr, field, n.info))
|
indirectAccess(castExpr, field, n.info),
|
||||||
|
useShallowCopy=true)
|
||||||
call.add(threadLocal.newSymNode)
|
call.add(threadLocal.newSymNode)
|
||||||
|
|
||||||
proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
||||||
|
|
@ -543,7 +557,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
||||||
# create flowVar:
|
# create flowVar:
|
||||||
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[2]))
|
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[2]))
|
||||||
if barrier == nil:
|
if barrier == nil:
|
||||||
result.add callCodeGenProc("nimFlowVarCreateCondVar", fvField)
|
result.add callCodegenProc("nimFlowVarCreateSemaphore", fvField)
|
||||||
|
|
||||||
elif spawnKind == srByVar:
|
elif spawnKind == srByVar:
|
||||||
var field = newSym(skField, getIdent"fv", owner, n.info)
|
var field = newSym(skField, getIdent"fv", owner, n.info)
|
||||||
|
|
@ -556,7 +570,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
|
||||||
let wrapper = createWrapperProc(fn, threadParam, argsParam,
|
let wrapper = createWrapperProc(fn, threadParam, argsParam,
|
||||||
varSection, varInit, call,
|
varSection, varInit, call,
|
||||||
barrierAsExpr, fvAsExpr, spawnKind)
|
barrierAsExpr, fvAsExpr, spawnKind)
|
||||||
result.add callCodeGenProc("nimSpawn", wrapper.newSymNode,
|
result.add callCodegenProc("nimSpawn", wrapper.newSymNode,
|
||||||
genAddrOf(scratchObj.newSymNode))
|
genAddrOf(scratchObj.newSymNode))
|
||||||
|
|
||||||
if spawnKind == srFlowVar: result.add fvField
|
if spawnKind == srFlowVar: result.add fvField
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -35,7 +35,7 @@ proc registerSysType(t: PType) =
|
||||||
proc newSysType(kind: TTypeKind, size: int): PType =
|
proc newSysType(kind: TTypeKind, size: int): PType =
|
||||||
result = newType(kind, systemModule)
|
result = newType(kind, systemModule)
|
||||||
result.size = size
|
result.size = size
|
||||||
result.align = size
|
result.align = size.int16
|
||||||
|
|
||||||
proc getSysSym(name: string): PSym =
|
proc getSysSym(name: string): PSym =
|
||||||
result = strTableGet(systemModule.tab, getIdent(name))
|
result = strTableGet(systemModule.tab, getIdent(name))
|
||||||
|
|
@ -44,6 +44,7 @@ proc getSysSym(name: string): PSym =
|
||||||
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
|
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
|
||||||
result.typ = newType(tyError, systemModule)
|
result.typ = newType(tyError, systemModule)
|
||||||
if result.kind == skStub: loadStub(result)
|
if result.kind == skStub: loadStub(result)
|
||||||
|
if result.kind == skAlias: result = result.owner
|
||||||
|
|
||||||
proc getSysMagic*(name: string, m: TMagic): PSym =
|
proc getSysMagic*(name: string, m: TMagic): PSym =
|
||||||
var ti: TIdentIter
|
var ti: TIdentIter
|
||||||
|
|
@ -165,13 +166,14 @@ proc setIntLitType*(result: PNode) =
|
||||||
proc getCompilerProc(name: string): PSym =
|
proc getCompilerProc(name: string): PSym =
|
||||||
var ident = getIdent(name, hashIgnoreStyle(name))
|
var ident = getIdent(name, hashIgnoreStyle(name))
|
||||||
result = strTableGet(compilerprocs, ident)
|
result = strTableGet(compilerprocs, ident)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = strTableGet(rodCompilerprocs, ident)
|
result = strTableGet(rodCompilerprocs, ident)
|
||||||
if result != nil:
|
if result != nil:
|
||||||
strTableAdd(compilerprocs, result)
|
strTableAdd(compilerprocs, result)
|
||||||
if result.kind == skStub: loadStub(result)
|
if result.kind == skStub: loadStub(result)
|
||||||
|
if result.kind == skAlias: result = result.owner
|
||||||
proc registerCompilerProc(s: PSym) =
|
|
||||||
|
proc registerCompilerProc(s: PSym) =
|
||||||
strTableAdd(compilerprocs, s)
|
strTableAdd(compilerprocs, s)
|
||||||
|
|
||||||
proc finishSystem(tab: TStrTable) = discard
|
proc finishSystem(tab: TStrTable) = discard
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -15,8 +15,7 @@ import
|
||||||
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
||||||
cgen, jsgen, json, nversion,
|
cgen, jsgen, json, nversion,
|
||||||
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
||||||
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
|
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists
|
||||||
pretty
|
|
||||||
|
|
||||||
from magicsys import systemModule, resetSysTypes
|
from magicsys import systemModule, resetSysTypes
|
||||||
|
|
||||||
|
|
@ -164,19 +163,6 @@ proc commandEval(exp: string) =
|
||||||
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
|
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
|
||||||
evalNim(echoExp.parseString, makeStdinModule())
|
evalNim(echoExp.parseString, makeStdinModule())
|
||||||
|
|
||||||
proc commandPrettyOld =
|
|
||||||
var projectFile = addFileExt(mainCommandArg(), NimExt)
|
|
||||||
var module = parseFile(projectFile.fileInfoIdx)
|
|
||||||
if module != nil:
|
|
||||||
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
|
|
||||||
|
|
||||||
proc commandPretty =
|
|
||||||
msgs.gErrorMax = high(int) # do not stop after first error
|
|
||||||
semanticPasses()
|
|
||||||
registerPass(prettyPass)
|
|
||||||
compileProject()
|
|
||||||
pretty.overwriteFiles()
|
|
||||||
|
|
||||||
proc commandScan =
|
proc commandScan =
|
||||||
var f = addFileExt(mainCommandArg(), NimExt)
|
var f = addFileExt(mainCommandArg(), NimExt)
|
||||||
var stream = llStreamOpen(f, fmRead)
|
var stream = llStreamOpen(f, fmRead)
|
||||||
|
|
@ -217,25 +203,6 @@ proc commandSuggest =
|
||||||
else: gProjectMainIdx
|
else: gProjectMainIdx
|
||||||
compileProject(projFile)
|
compileProject(projFile)
|
||||||
|
|
||||||
proc wantMainModule =
|
|
||||||
if gProjectFull.len == 0:
|
|
||||||
if optMainModule.len == 0:
|
|
||||||
fatal(gCmdLineInfo, errCommandExpectsFilename)
|
|
||||||
else:
|
|
||||||
gProjectName = optMainModule
|
|
||||||
gProjectFull = gProjectPath / gProjectName
|
|
||||||
|
|
||||||
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
|
|
||||||
|
|
||||||
proc requireMainModuleOption =
|
|
||||||
if optMainModule.len == 0:
|
|
||||||
fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
|
|
||||||
else:
|
|
||||||
gProjectName = optMainModule
|
|
||||||
gProjectFull = gProjectPath / gProjectName
|
|
||||||
|
|
||||||
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
|
|
||||||
|
|
||||||
proc resetMemory =
|
proc resetMemory =
|
||||||
resetCompilationLists()
|
resetCompilationLists()
|
||||||
ccgutils.resetCaches()
|
ccgutils.resetCaches()
|
||||||
|
|
@ -299,30 +266,22 @@ proc mainCommand* =
|
||||||
# current path is always looked first for modules
|
# current path is always looked first for modules
|
||||||
prependStr(searchPaths, gProjectPath)
|
prependStr(searchPaths, gProjectPath)
|
||||||
setId(100)
|
setId(100)
|
||||||
passes.gIncludeFile = includeModule
|
|
||||||
passes.gImportModule = importModule
|
|
||||||
case command.normalize
|
case command.normalize
|
||||||
of "c", "cc", "compile", "compiletoc":
|
of "c", "cc", "compile", "compiletoc":
|
||||||
# compile means compileToC currently
|
# compile means compileToC currently
|
||||||
gCmd = cmdCompileToC
|
gCmd = cmdCompileToC
|
||||||
wantMainModule()
|
|
||||||
commandCompileToC()
|
commandCompileToC()
|
||||||
of "cpp", "compiletocpp":
|
of "cpp", "compiletocpp":
|
||||||
extccomp.cExt = ".cpp"
|
|
||||||
gCmd = cmdCompileToCpp
|
gCmd = cmdCompileToCpp
|
||||||
if cCompiler == ccGcc: setCC("gcc")
|
if cCompiler == ccGcc: setCC("gcc")
|
||||||
wantMainModule()
|
|
||||||
defineSymbol("cpp")
|
defineSymbol("cpp")
|
||||||
commandCompileToC()
|
commandCompileToC()
|
||||||
of "objc", "compiletooc":
|
of "objc", "compiletooc":
|
||||||
extccomp.cExt = ".m"
|
|
||||||
gCmd = cmdCompileToOC
|
gCmd = cmdCompileToOC
|
||||||
wantMainModule()
|
|
||||||
defineSymbol("objc")
|
defineSymbol("objc")
|
||||||
commandCompileToC()
|
commandCompileToC()
|
||||||
of "run":
|
of "run":
|
||||||
gCmd = cmdRun
|
gCmd = cmdRun
|
||||||
wantMainModule()
|
|
||||||
when hasTinyCBackend:
|
when hasTinyCBackend:
|
||||||
extccomp.setCC("tcc")
|
extccomp.setCC("tcc")
|
||||||
commandCompileToC()
|
commandCompileToC()
|
||||||
|
|
@ -330,41 +289,33 @@ proc mainCommand* =
|
||||||
rawMessage(errInvalidCommandX, command)
|
rawMessage(errInvalidCommandX, command)
|
||||||
of "js", "compiletojs":
|
of "js", "compiletojs":
|
||||||
gCmd = cmdCompileToJS
|
gCmd = cmdCompileToJS
|
||||||
wantMainModule()
|
|
||||||
commandCompileToJS()
|
commandCompileToJS()
|
||||||
of "compiletollvm":
|
of "compiletollvm":
|
||||||
gCmd = cmdCompileToLLVM
|
gCmd = cmdCompileToLLVM
|
||||||
wantMainModule()
|
|
||||||
when hasLLVM_Backend:
|
when hasLLVM_Backend:
|
||||||
CommandCompileToLLVM()
|
CommandCompileToLLVM()
|
||||||
else:
|
else:
|
||||||
rawMessage(errInvalidCommandX, command)
|
rawMessage(errInvalidCommandX, command)
|
||||||
of "pretty":
|
|
||||||
gCmd = cmdPretty
|
|
||||||
wantMainModule()
|
|
||||||
commandPretty()
|
|
||||||
of "doc":
|
of "doc":
|
||||||
|
wantMainModule()
|
||||||
gCmd = cmdDoc
|
gCmd = cmdDoc
|
||||||
loadConfigs(DocConfig)
|
loadConfigs(DocConfig)
|
||||||
wantMainModule()
|
|
||||||
commandDoc()
|
commandDoc()
|
||||||
of "doc2":
|
of "doc2":
|
||||||
gCmd = cmdDoc
|
gCmd = cmdDoc
|
||||||
loadConfigs(DocConfig)
|
loadConfigs(DocConfig)
|
||||||
wantMainModule()
|
|
||||||
defineSymbol("nimdoc")
|
defineSymbol("nimdoc")
|
||||||
commandDoc2()
|
commandDoc2()
|
||||||
of "rst2html":
|
of "rst2html":
|
||||||
gCmd = cmdRst2html
|
gCmd = cmdRst2html
|
||||||
loadConfigs(DocConfig)
|
loadConfigs(DocConfig)
|
||||||
wantMainModule()
|
|
||||||
commandRst2Html()
|
commandRst2Html()
|
||||||
of "rst2tex":
|
of "rst2tex":
|
||||||
gCmd = cmdRst2tex
|
gCmd = cmdRst2tex
|
||||||
loadConfigs(DocTexConfig)
|
loadConfigs(DocTexConfig)
|
||||||
wantMainModule()
|
|
||||||
commandRst2TeX()
|
commandRst2TeX()
|
||||||
of "jsondoc":
|
of "jsondoc":
|
||||||
|
wantMainModule()
|
||||||
gCmd = cmdDoc
|
gCmd = cmdDoc
|
||||||
loadConfigs(DocConfig)
|
loadConfigs(DocConfig)
|
||||||
wantMainModule()
|
wantMainModule()
|
||||||
|
|
@ -376,12 +327,11 @@ proc mainCommand* =
|
||||||
commandBuildIndex()
|
commandBuildIndex()
|
||||||
of "gendepend":
|
of "gendepend":
|
||||||
gCmd = cmdGenDepend
|
gCmd = cmdGenDepend
|
||||||
wantMainModule()
|
|
||||||
commandGenDepend()
|
commandGenDepend()
|
||||||
of "dump":
|
of "dump":
|
||||||
gCmd = cmdDump
|
gCmd = cmdDump
|
||||||
if getConfigVar("dump.format") == "json":
|
if getConfigVar("dump.format") == "json":
|
||||||
requireMainModuleOption()
|
wantMainModule()
|
||||||
|
|
||||||
var definedSymbols = newJArray()
|
var definedSymbols = newJArray()
|
||||||
for s in definedSymbolNames(): definedSymbols.elems.add(%s)
|
for s in definedSymbolNames(): definedSymbols.elems.add(%s)
|
||||||
|
|
@ -405,7 +355,6 @@ proc mainCommand* =
|
||||||
for it in iterSearchPath(searchPaths): msgWriteln(it)
|
for it in iterSearchPath(searchPaths): msgWriteln(it)
|
||||||
of "check":
|
of "check":
|
||||||
gCmd = cmdCheck
|
gCmd = cmdCheck
|
||||||
wantMainModule()
|
|
||||||
commandCheck()
|
commandCheck()
|
||||||
of "parse":
|
of "parse":
|
||||||
gCmd = cmdParse
|
gCmd = cmdParse
|
||||||
|
|
@ -429,7 +378,6 @@ proc mainCommand* =
|
||||||
if gEvalExpr != "":
|
if gEvalExpr != "":
|
||||||
commandEval(gEvalExpr)
|
commandEval(gEvalExpr)
|
||||||
else:
|
else:
|
||||||
wantMainModule()
|
|
||||||
commandSuggest()
|
commandSuggest()
|
||||||
of "serve":
|
of "serve":
|
||||||
isServing = true
|
isServing = true
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -117,7 +117,7 @@ proc newModule(fileIdx: int32): PSym =
|
||||||
result.kind = skModule
|
result.kind = skModule
|
||||||
let filename = fileIdx.toFullPath
|
let filename = fileIdx.toFullPath
|
||||||
result.name = getIdent(splitFile(filename).name)
|
result.name = getIdent(splitFile(filename).name)
|
||||||
if not isNimrodIdentifier(result.name.s):
|
if not isNimIdentifier(result.name.s):
|
||||||
rawMessage(errInvalidModuleName, result.name.s)
|
rawMessage(errInvalidModuleName, result.name.s)
|
||||||
|
|
||||||
result.info = newLineInfo(fileIdx, 1, 1)
|
result.info = newLineInfo(fileIdx, 1, 1)
|
||||||
|
|
@ -177,7 +177,7 @@ proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} =
|
||||||
proc `==^`(a, b: string): bool =
|
proc `==^`(a, b: string): bool =
|
||||||
try:
|
try:
|
||||||
result = sameFile(a, b)
|
result = sameFile(a, b)
|
||||||
except EOS:
|
except OSError:
|
||||||
result = false
|
result = false
|
||||||
|
|
||||||
proc compileSystemModule* =
|
proc compileSystemModule* =
|
||||||
|
|
@ -185,8 +185,18 @@ proc compileSystemModule* =
|
||||||
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
|
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
|
||||||
discard compileModule(systemFileIdx, {sfSystemModule})
|
discard compileModule(systemFileIdx, {sfSystemModule})
|
||||||
|
|
||||||
proc compileProject*(projectFile = gProjectMainIdx) =
|
proc wantMainModule* =
|
||||||
|
if gProjectFull.len == 0:
|
||||||
|
fatal(gCmdLineInfo, errCommandExpectsFilename)
|
||||||
|
gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx
|
||||||
|
|
||||||
|
passes.gIncludeFile = includeModule
|
||||||
|
passes.gImportModule = importModule
|
||||||
|
|
||||||
|
proc compileProject*(projectFileIdx = -1'i32) =
|
||||||
|
wantMainModule()
|
||||||
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
|
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
|
||||||
|
let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx
|
||||||
if projectFile == systemFileIdx:
|
if projectFile == systemFileIdx:
|
||||||
discard compileModule(projectFile, {sfMainModule, sfSystemModule})
|
discard compileModule(projectFile, {sfMainModule, sfSystemModule})
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -114,17 +114,18 @@ type
|
||||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||||
warnDeprecated, warnConfigDeprecated,
|
warnDeprecated, warnConfigDeprecated,
|
||||||
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
|
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
|
||||||
warnUnknownSubstitutionX, warnLanguageXNotSupported, warnCommentXIgnored,
|
warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
||||||
|
warnFieldXNotSupported, warnCommentXIgnored,
|
||||||
warnNilStatement, warnAnalysisLoophole,
|
warnNilStatement, warnAnalysisLoophole,
|
||||||
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
||||||
warnEachIdentIsTuple, warnShadowIdent,
|
warnEachIdentIsTuple, warnShadowIdent,
|
||||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||||
warnUninit, warnGcMem, warnUser,
|
warnUninit, warnGcMem, warnLockLevel, warnUser,
|
||||||
hintSuccess, hintSuccessX,
|
hintSuccess, hintSuccessX,
|
||||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||||
hintConditionAlwaysTrue, hintPattern,
|
hintConditionAlwaysTrue, hintName, hintPattern,
|
||||||
hintUser
|
hintUser
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -368,13 +369,14 @@ const
|
||||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
|
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]",
|
||||||
warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]",
|
warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]",
|
||||||
warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]",
|
warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]",
|
||||||
warnDeprecated: "\'$1\' is deprecated [Deprecated]",
|
warnDeprecated: "$1 is deprecated [Deprecated]",
|
||||||
warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]",
|
warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]",
|
||||||
warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]",
|
warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]",
|
||||||
warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]",
|
warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]",
|
||||||
warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]",
|
warnRedefinitionOfLabel: "redefinition of label \'$1\' [RedefinitionOfLabel]",
|
||||||
warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]",
|
warnUnknownSubstitutionX: "unknown substitution \'$1\' [UnknownSubstitutionX]",
|
||||||
warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]",
|
warnLanguageXNotSupported: "language \'$1\' not supported [LanguageXNotSupported]",
|
||||||
|
warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
|
||||||
warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
|
warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
|
||||||
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
|
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
|
||||||
warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]",
|
warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]",
|
||||||
|
|
@ -387,9 +389,10 @@ const
|
||||||
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
|
warnProveField: "cannot prove that field '$1' is accessible [ProveField]",
|
||||||
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
|
warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]",
|
||||||
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
|
warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]",
|
||||||
warnGcUnsafe2: "cannot prove '$1' is GC-safe. This will become a compile time error in the future.",
|
warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.",
|
||||||
warnUninit: "'$1' might not have been initialized [Uninit]",
|
warnUninit: "'$1' might not have been initialized [Uninit]",
|
||||||
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
warnGcMem: "'$1' uses GC'ed memory [GcMem]",
|
||||||
|
warnLockLevel: "$1 [LockLevel]",
|
||||||
warnUser: "$1 [User]",
|
warnUser: "$1 [User]",
|
||||||
hintSuccess: "operation successful [Success]",
|
hintSuccess: "operation successful [Success]",
|
||||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]",
|
||||||
|
|
@ -405,25 +408,27 @@ const
|
||||||
hintConf: "used config file \'$1\' [Conf]",
|
hintConf: "used config file \'$1\' [Conf]",
|
||||||
hintPath: "added path: '$1' [Path]",
|
hintPath: "added path: '$1' [Path]",
|
||||||
hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
|
hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
|
||||||
|
hintName: "name should be: '$1' [Name]",
|
||||||
hintPattern: "$1 [Pattern]",
|
hintPattern: "$1 [Pattern]",
|
||||||
hintUser: "$1 [User]"]
|
hintUser: "$1 [User]"]
|
||||||
|
|
||||||
const
|
const
|
||||||
WarningsToStr*: array[0..26, string] = ["CannotOpenFile", "OctalEscape",
|
WarningsToStr*: array[0..28, string] = ["CannotOpenFile", "OctalEscape",
|
||||||
"XIsNeverRead", "XmightNotBeenInit",
|
"XIsNeverRead", "XmightNotBeenInit",
|
||||||
"Deprecated", "ConfigDeprecated",
|
"Deprecated", "ConfigDeprecated",
|
||||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||||
"RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported",
|
"RedefinitionOfLabel", "UnknownSubstitutionX",
|
||||||
|
"LanguageXNotSupported", "FieldXNotSupported",
|
||||||
"CommentXIgnored", "NilStmt",
|
"CommentXIgnored", "NilStmt",
|
||||||
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
|
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
|
||||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||||
"GcMem", "User"]
|
"GcMem", "LockLevel", "User"]
|
||||||
|
|
||||||
HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong",
|
HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong",
|
||||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||||
"Path", "CondTrue", "Pattern",
|
"Path", "CondTrue", "Name", "Pattern",
|
||||||
"User"]
|
"User"]
|
||||||
|
|
||||||
const
|
const
|
||||||
|
|
@ -441,11 +446,11 @@ type
|
||||||
TNoteKinds* = set[TNoteKind]
|
TNoteKinds* = set[TNoteKind]
|
||||||
|
|
||||||
TFileInfo*{.final.} = object
|
TFileInfo*{.final.} = object
|
||||||
fullPath*: string # This is a canonical full filesystem path
|
fullPath: string # This is a canonical full filesystem path
|
||||||
projPath*: string # This is relative to the project's root
|
projPath*: string # This is relative to the project's root
|
||||||
shortName*: string # short name of the module
|
shortName*: string # short name of the module
|
||||||
quotedName*: PRope # cached quoted short name for codegen
|
quotedName*: PRope # cached quoted short name for codegen
|
||||||
# purpoes
|
# purposes
|
||||||
|
|
||||||
lines*: seq[PRope] # the source code of the module
|
lines*: seq[PRope] # the source code of the module
|
||||||
# used for better error messages and
|
# used for better error messages and
|
||||||
|
|
@ -468,8 +473,8 @@ type
|
||||||
|
|
||||||
TErrorOutputs* = set[TErrorOutput]
|
TErrorOutputs* = set[TErrorOutput]
|
||||||
|
|
||||||
ERecoverableError* = object of EInvalidValue
|
ERecoverableError* = object of ValueError
|
||||||
ESuggestDone* = object of E_Base
|
ESuggestDone* = object of Exception
|
||||||
|
|
||||||
const
|
const
|
||||||
InvalidFileIDX* = int32(-1)
|
InvalidFileIDX* = int32(-1)
|
||||||
|
|
@ -567,7 +572,7 @@ var
|
||||||
gErrorMax*: int = 1 # stop after gErrorMax errors
|
gErrorMax*: int = 1 # stop after gErrorMax errors
|
||||||
|
|
||||||
when useCaas:
|
when useCaas:
|
||||||
var stdoutSocket*: TSocket
|
var stdoutSocket*: Socket
|
||||||
|
|
||||||
proc unknownLineInfo*(): TLineInfo =
|
proc unknownLineInfo*(): TLineInfo =
|
||||||
result.line = int16(-1)
|
result.line = int16(-1)
|
||||||
|
|
@ -784,6 +789,14 @@ proc writeSurroundingSrc(info: TLineInfo) =
|
||||||
msgWriteln(indent & info.sourceLine.ropeToStr)
|
msgWriteln(indent & info.sourceLine.ropeToStr)
|
||||||
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
|
msgWriteln(indent & repeatChar(info.col, ' ') & '^')
|
||||||
|
|
||||||
|
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||||
|
let frmt = case msg
|
||||||
|
of warnMin..warnMax: PosWarningFormat
|
||||||
|
of hintMin..hintMax: PosHintFormat
|
||||||
|
else: PosErrorFormat
|
||||||
|
result = frmt % [toMsgFilename(info), coordToStr(info.line),
|
||||||
|
coordToStr(info.col), getMessageStr(msg, arg)]
|
||||||
|
|
||||||
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||||
eh: TErrorHandling) =
|
eh: TErrorHandling) =
|
||||||
var frmt: string
|
var frmt: string
|
||||||
|
|
@ -858,7 +871,7 @@ proc sourceLine*(i: TLineInfo): PRope =
|
||||||
try:
|
try:
|
||||||
for line in lines(i.toFullPath):
|
for line in lines(i.toFullPath):
|
||||||
addSourceLine i.fileIndex, line.string
|
addSourceLine i.fileIndex, line.string
|
||||||
except EIO:
|
except IOError:
|
||||||
discard
|
discard
|
||||||
internalAssert i.fileIndex < fileInfos.len
|
internalAssert i.fileIndex < fileInfos.len
|
||||||
# can happen if the error points to EOF:
|
# can happen if the error points to EOF:
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
; and project.
|
; and project.
|
||||||
|
|
||||||
[Project]
|
[Project]
|
||||||
Name: "Nimrod"
|
Name: "Nim"
|
||||||
Version: "$version"
|
Version: "$version"
|
||||||
Platforms: """
|
Platforms: """
|
||||||
windows: i386;amd64
|
windows: i386;amd64
|
||||||
|
|
@ -16,15 +16,15 @@ Platforms: """
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Authors: "Andreas Rumpf"
|
Authors: "Andreas Rumpf"
|
||||||
Description: """This is the Nimrod Compiler. Nimrod is a new statically typed,
|
Description: """This is the Nim Compiler. Nim is a new statically typed,
|
||||||
imperative programming language, that supports procedural, functional, object
|
imperative programming language, that supports procedural, functional, object
|
||||||
oriented and generic programming styles while remaining simple and efficient.
|
oriented and generic programming styles while remaining simple and efficient.
|
||||||
A special feature that Nimrod inherited from Lisp is that Nimrod's abstract
|
A special feature that Nim inherited from Lisp is that Nim's abstract
|
||||||
syntax tree (AST) is part of the specification - this allows a powerful macro
|
syntax tree (AST) is part of the specification - this allows a powerful macro
|
||||||
system which can be used to create domain specific languages.
|
system which can be used to create domain specific languages.
|
||||||
|
|
||||||
Nimrod is a compiled, garbage-collected systems programming language
|
Nim is a compiled, garbage-collected systems programming language
|
||||||
which has an excellent productivity/performance ratio. Nimrod's design
|
which has an excellent productivity/performance ratio. Nim's design
|
||||||
focuses on the 3E: efficiency, expressiveness, elegance (in the order of
|
focuses on the 3E: efficiency, expressiveness, elegance (in the order of
|
||||||
priority)."""
|
priority)."""
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ App: Console
|
||||||
License: "copying.txt"
|
License: "copying.txt"
|
||||||
|
|
||||||
[Config]
|
[Config]
|
||||||
Files: "config/nimrod.cfg"
|
Files: "config/nim.cfg"
|
||||||
Files: "config/nimdoc.cfg"
|
Files: "config/nimdoc.cfg"
|
||||||
Files: "config/nimdoc.tex.cfg"
|
Files: "config/nimdoc.tex.cfg"
|
||||||
|
|
||||||
|
|
@ -61,8 +61,8 @@ Files: "icons/koch.res"
|
||||||
Files: "icons/koch_icon.o"
|
Files: "icons/koch_icon.o"
|
||||||
|
|
||||||
Files: "compiler/readme.txt"
|
Files: "compiler/readme.txt"
|
||||||
Files: "compiler/nimrod.ini"
|
Files: "compiler/nim.ini"
|
||||||
Files: "compiler/nimrod.cfg"
|
Files: "compiler/nim.nimrod.cfg"
|
||||||
Files: "compiler/*.nim"
|
Files: "compiler/*.nim"
|
||||||
Files: "doc/*.txt"
|
Files: "doc/*.txt"
|
||||||
Files: "compiler/nimfix/*.nim"
|
Files: "compiler/nimfix/*.nim"
|
||||||
|
|
@ -113,10 +113,9 @@ Files: "examples/*.tmpl"
|
||||||
|
|
||||||
|
|
||||||
[Windows]
|
[Windows]
|
||||||
Files: "bin/nimrod.exe"
|
Files: "bin/nim.exe"
|
||||||
Files: "bin/nimrod_debug.exe"
|
Files: "bin/nim_debug.exe"
|
||||||
Files: "bin/c2nim.exe"
|
Files: "bin/c2nim.exe"
|
||||||
Files: "bin/niminst.exe"
|
|
||||||
Files: "bin/nimgrep.exe"
|
Files: "bin/nimgrep.exe"
|
||||||
|
|
||||||
Files: "dist/*.dll"
|
Files: "dist/*.dll"
|
||||||
|
|
@ -132,7 +131,7 @@ Download: r"Aporia IDE|dist|aporia.zip|97997|http://nim-lang.org/download/aporia
|
||||||
; for now only NSIS supports optional downloads
|
; for now only NSIS supports optional downloads
|
||||||
|
|
||||||
[UnixBin]
|
[UnixBin]
|
||||||
Files: "bin/nimrod"
|
Files: "bin/nim"
|
||||||
|
|
||||||
|
|
||||||
[Unix]
|
[Unix]
|
||||||
|
|
@ -156,6 +155,5 @@ flags = "-w"
|
||||||
[deb]
|
[deb]
|
||||||
buildDepends: "gcc (>= 4:4.3.2)"
|
buildDepends: "gcc (>= 4:4.3.2)"
|
||||||
pkgDepends: "gcc (>= 4:4.3.2)"
|
pkgDepends: "gcc (>= 4:4.3.2)"
|
||||||
shortDesc: "The Nimrod Compiler"
|
shortDesc: "The Nim Compiler"
|
||||||
licenses: "bin/nimrod,MIT;lib/*,MIT;"
|
licenses: "bin/nim,MIT;lib/*,MIT;"
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -40,7 +40,7 @@ proc handleCmdLine() =
|
||||||
if gProjectName != "":
|
if gProjectName != "":
|
||||||
try:
|
try:
|
||||||
gProjectFull = canonicalizePath(gProjectName)
|
gProjectFull = canonicalizePath(gProjectName)
|
||||||
except EOS:
|
except OSError:
|
||||||
gProjectFull = gProjectName
|
gProjectFull = gProjectName
|
||||||
var p = splitFile(gProjectFull)
|
var p = splitFile(gProjectFull)
|
||||||
gProjectPath = p.dir
|
gProjectPath = p.dir
|
||||||
|
|
@ -58,7 +58,7 @@ proc handleCmdLine() =
|
||||||
if msgs.gErrorCounter == 0:
|
if msgs.gErrorCounter == 0:
|
||||||
when hasTinyCBackend:
|
when hasTinyCBackend:
|
||||||
if gCmd == cmdRun:
|
if gCmd == cmdRun:
|
||||||
tccgen.run(service.arguments)
|
tccgen.run(commands.arguments)
|
||||||
if optRun in gGlobalOptions:
|
if optRun in gGlobalOptions:
|
||||||
if gCmd == cmdCompileToJS:
|
if gCmd == cmdCompileToJS:
|
||||||
var ex: string
|
var ex: string
|
||||||
|
|
@ -67,7 +67,7 @@ proc handleCmdLine() =
|
||||||
else:
|
else:
|
||||||
ex = quoteShell(
|
ex = quoteShell(
|
||||||
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
|
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
|
||||||
execExternalProgram("node " & ex & ' ' & service.arguments)
|
execExternalProgram("node " & ex & ' ' & commands.arguments)
|
||||||
else:
|
else:
|
||||||
var binPath: string
|
var binPath: string
|
||||||
if options.outFile.len > 0:
|
if options.outFile.len > 0:
|
||||||
|
|
@ -77,7 +77,7 @@ proc handleCmdLine() =
|
||||||
# Figure out ourselves a valid binary name.
|
# Figure out ourselves a valid binary name.
|
||||||
binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
|
binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
|
||||||
var ex = quoteShell(binPath)
|
var ex = quoteShell(binPath)
|
||||||
execExternalProgram(ex & ' ' & service.arguments)
|
execExternalProgram(ex & ' ' & commands.arguments)
|
||||||
|
|
||||||
when declared(GC_setMaxPause):
|
when declared(GC_setMaxPause):
|
||||||
GC_setMaxPause 2_000
|
GC_setMaxPause 2_000
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
# Special configuration file for the Nimrod project
|
# Special configuration file for the Nim project
|
||||||
|
|
||||||
mainModule:"nimrod.nim"
|
|
||||||
|
|
||||||
# gc:markAndSweep
|
# gc:markAndSweep
|
||||||
|
|
||||||
|
|
@ -21,3 +19,4 @@ define:useStdoutAsStdmsg
|
||||||
|
|
||||||
cs:partial
|
cs:partial
|
||||||
#define:useNodeIds
|
#define:useNodeIds
|
||||||
|
symbol:nimfix
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## Implements some helper procs for Babel (Nimrod's package manager) support.
|
## Implements some helper procs for Nimble (Nim's package manager) support.
|
||||||
|
|
||||||
import parseutils, strutils, strtabs, os, options, msgs, lists
|
import parseutils, strutils, strtabs, os, options, msgs, lists
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ proc `<.`(a, b: string): bool =
|
||||||
if a[i] == '.': inc i
|
if a[i] == '.': inc i
|
||||||
if b[j] == '.': inc j
|
if b[j] == '.': inc j
|
||||||
|
|
||||||
proc addPackage(packages: PStringTable, p: string) =
|
proc addPackage(packages: StringTableRef, p: string) =
|
||||||
let x = versionSplitPos(p)
|
let x = versionSplitPos(p)
|
||||||
let name = p.substr(0, x-1)
|
let name = p.substr(0, x-1)
|
||||||
if x < p.len:
|
if x < p.len:
|
||||||
|
|
@ -53,12 +53,12 @@ proc addPackage(packages: PStringTable, p: string) =
|
||||||
else:
|
else:
|
||||||
packages[name] = latest
|
packages[name] = latest
|
||||||
|
|
||||||
iterator chosen(packages: PStringTable): string =
|
iterator chosen(packages: StringTableRef): string =
|
||||||
for key, val in pairs(packages):
|
for key, val in pairs(packages):
|
||||||
let res = if val == latest: key else: key & '-' & val
|
let res = if val == latest: key else: key & '-' & val
|
||||||
yield res
|
yield res
|
||||||
|
|
||||||
proc addBabelPath(p: string, info: TLineInfo) =
|
proc addNimblePath(p: string, info: TLineInfo) =
|
||||||
if not contains(options.searchPaths, p):
|
if not contains(options.searchPaths, p):
|
||||||
if gVerbosity >= 1: message(info, hintPath, p)
|
if gVerbosity >= 1: message(info, hintPath, p)
|
||||||
lists.prependStr(options.lazyPaths, p)
|
lists.prependStr(options.lazyPaths, p)
|
||||||
|
|
@ -70,10 +70,10 @@ proc addPathWithNimFiles(p: string, info: TLineInfo) =
|
||||||
result = true
|
result = true
|
||||||
break
|
break
|
||||||
if hasNimFile(p):
|
if hasNimFile(p):
|
||||||
addBabelPath(p, info)
|
addNimblePath(p, info)
|
||||||
else:
|
else:
|
||||||
for kind, p2 in walkDir(p):
|
for kind, p2 in walkDir(p):
|
||||||
if hasNimFile(p2): addBabelPath(p2, info)
|
if hasNimFile(p2): addNimblePath(p2, info)
|
||||||
|
|
||||||
proc addPathRec(dir: string, info: TLineInfo) =
|
proc addPathRec(dir: string, info: TLineInfo) =
|
||||||
var packages = newStringTable(modeStyleInsensitive)
|
var packages = newStringTable(modeStyleInsensitive)
|
||||||
|
|
@ -83,8 +83,8 @@ proc addPathRec(dir: string, info: TLineInfo) =
|
||||||
if k == pcDir and p[pos] != '.':
|
if k == pcDir and p[pos] != '.':
|
||||||
addPackage(packages, p)
|
addPackage(packages, p)
|
||||||
for p in packages.chosen:
|
for p in packages.chosen:
|
||||||
addBabelPath(p, info)
|
addNimblePath(p, info)
|
||||||
|
|
||||||
proc babelPath*(path: string, info: TLineInfo) =
|
proc nimblePath*(path: string, info: TLineInfo) =
|
||||||
addPathRec(path, info)
|
addPathRec(path, info)
|
||||||
addBabelPath(path, info)
|
addNimblePath(path, info)
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -14,7 +14,7 @@ import
|
||||||
options, idents, wordrecg
|
options, idents, wordrecg
|
||||||
|
|
||||||
# ---------------- configuration file parser -----------------------------
|
# ---------------- configuration file parser -----------------------------
|
||||||
# we use Nimrod's scanner here to safe space and work
|
# we use Nim's scanner here to safe space and work
|
||||||
|
|
||||||
proc ppGetTok(L: var TLexer, tok: var TToken) =
|
proc ppGetTok(L: var TLexer, tok: var TToken) =
|
||||||
# simple filter
|
# simple filter
|
||||||
|
|
@ -113,7 +113,7 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
|
||||||
case whichKeyword(tok.ident)
|
case whichKeyword(tok.ident)
|
||||||
of wIf:
|
of wIf:
|
||||||
setLen(condStack, len(condStack) + 1)
|
setLen(condStack, len(condStack) + 1)
|
||||||
var res = evalppIf(L, tok)
|
let res = evalppIf(L, tok)
|
||||||
condStack[high(condStack)] = res
|
condStack[high(condStack)] = res
|
||||||
if not res: jumpToDirective(L, tok, jdElseEndif)
|
if not res: jumpToDirective(L, tok, jdElseEndif)
|
||||||
of wElif: doElif(L, tok)
|
of wElif: doElif(L, tok)
|
||||||
|
|
@ -224,8 +224,10 @@ proc loadConfigs*(cfg: string) =
|
||||||
if libpath == "":
|
if libpath == "":
|
||||||
# choose default libpath:
|
# choose default libpath:
|
||||||
var prefix = getPrefixDir()
|
var prefix = getPrefixDir()
|
||||||
if prefix == "/usr": libpath = "/usr/lib/nimrod"
|
when defined(posix):
|
||||||
elif prefix == "/usr/local": libpath = "/usr/local/lib/nimrod"
|
if prefix == "/usr": libpath = "/usr/lib/nim"
|
||||||
|
elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
|
||||||
|
else: libpath = joinPath(prefix, "lib")
|
||||||
else: libpath = joinPath(prefix, "lib")
|
else: libpath = joinPath(prefix, "lib")
|
||||||
|
|
||||||
if optSkipConfigFile notin gGlobalOptions:
|
if optSkipConfigFile notin gGlobalOptions:
|
||||||
|
|
@ -244,5 +246,6 @@ proc loadConfigs*(cfg: string) =
|
||||||
|
|
||||||
if gProjectName.len != 0:
|
if gProjectName.len != 0:
|
||||||
# new project wide config file:
|
# new project wide config file:
|
||||||
readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
|
let projectConfig = changeFileExt(gProjectFull, "nim.cfg")
|
||||||
|
if fileExists(projectConfig): readConfigFile(projectConfig)
|
||||||
|
else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
## exposes the Nimrod VM to clients.
|
## exposes the Nim VM to clients.
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, modules, passes, passaux, condsyms,
|
ast, modules, passes, passaux, condsyms,
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf,
|
||||||
const Usage = """
|
const Usage = """
|
||||||
Nimfix - Tool to patch Nim code
|
Nimfix - Tool to patch Nim code
|
||||||
Usage:
|
Usage:
|
||||||
nimfix [options] projectflie.nim
|
nimfix [options] projectfile.nim
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--overwriteFiles:on|off overwrite the original nim files.
|
--overwriteFiles:on|off overwrite the original nim files.
|
||||||
|
|
@ -26,12 +26,13 @@ Options:
|
||||||
--styleCheck:on|off|auto performs style checking for identifiers
|
--styleCheck:on|off|auto performs style checking for identifiers
|
||||||
and suggests an alternative spelling;
|
and suggests an alternative spelling;
|
||||||
'auto' corrects the spelling.
|
'auto' corrects the spelling.
|
||||||
|
--bestEffort try to fix the code even when there
|
||||||
|
are errors.
|
||||||
|
|
||||||
In addition, all command line options of Nim are supported.
|
In addition, all command line options of Nim are supported.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
proc mainCommand =
|
proc mainCommand =
|
||||||
#msgs.gErrorMax = high(int) # do not stop after first error
|
|
||||||
registerPass verbosePass
|
registerPass verbosePass
|
||||||
registerPass semPass
|
registerPass semPass
|
||||||
gCmd = cmdPretty
|
gCmd = cmdPretty
|
||||||
|
|
@ -63,13 +64,14 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||||
of "on": gCheckExtern = true
|
of "on": gCheckExtern = true
|
||||||
of "off": gCheckExtern = false
|
of "off": gCheckExtern = false
|
||||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||||
of "stylecheck":
|
of "stylecheck":
|
||||||
case p.val.normalize
|
case p.val.normalize
|
||||||
of "off": gStyleCheck = StyleCheck.None
|
of "off": gStyleCheck = StyleCheck.None
|
||||||
of "on": gStyleCheck = StyleCheck.Warn
|
of "on": gStyleCheck = StyleCheck.Warn
|
||||||
of "auto": gStyleCheck = StyleCheck.Auto
|
of "auto": gStyleCheck = StyleCheck.Auto
|
||||||
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
else: localError(gCmdLineInfo, errOnOrOffExpected)
|
||||||
of "wholeproject": gOnlyMainfile = false
|
of "wholeproject": gOnlyMainfile = false
|
||||||
|
of "besteffort": msgs.gErrorMax = high(int) # dont stop after first error
|
||||||
else:
|
else:
|
||||||
processSwitch(pass, p)
|
processSwitch(pass, p)
|
||||||
of cmdArgument:
|
of cmdArgument:
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ proc loadFile*(info: TLineInfo) =
|
||||||
for line in lines(path):
|
for line in lines(path):
|
||||||
gSourceFiles[i].lines.add(line)
|
gSourceFiles[i].lines.add(line)
|
||||||
# extract line ending of the file:
|
# extract line ending of the file:
|
||||||
var lex: TBaseLexer
|
var lex: BaseLexer
|
||||||
open(lex, newFileStream(path, fmRead))
|
open(lex, newFileStream(path, fmRead))
|
||||||
var pos = lex.bufpos
|
var pos = lex.bufpos
|
||||||
while true:
|
while true:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -37,7 +37,7 @@ const
|
||||||
NewLines* = {CR, LF}
|
NewLines* = {CR, LF}
|
||||||
|
|
||||||
type
|
type
|
||||||
TBaseLexer* = object of TObject
|
TBaseLexer* = object of RootObj
|
||||||
bufpos*: int
|
bufpos*: int
|
||||||
buf*: cstring
|
buf*: cstring
|
||||||
bufLen*: int # length of buffer in characters
|
bufLen*: int # length of buffer in characters
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# this unit handles Nimrod sets; it implements symbolic sets
|
# this unit handles Nim sets; it implements symbolic sets
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer
|
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,17 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module contains Nimrod's version. It is the only place where it needs
|
# This module contains Nim's version. It is the only place where it needs
|
||||||
# to be changed.
|
# to be changed.
|
||||||
|
|
||||||
const
|
const
|
||||||
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
MaxSetElements* = 1 shl 16 # (2^16) to support unicode character sets?
|
||||||
VersionMajor* = 0
|
VersionAsString* = system.NimVersion
|
||||||
VersionMinor* = 9
|
|
||||||
VersionPatch* = 7
|
|
||||||
VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
|
|
||||||
|
|
||||||
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
RodFileVersion* = "1215" # modify this if the rod-format changes!
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -68,7 +68,7 @@ type # please make sure we have under 32 options
|
||||||
# also: generate header file
|
# also: generate header file
|
||||||
|
|
||||||
TGlobalOptions* = set[TGlobalOption]
|
TGlobalOptions* = set[TGlobalOption]
|
||||||
TCommands* = enum # Nimrod's commands
|
TCommands* = enum # Nim's commands
|
||||||
# **keep binary compatible**
|
# **keep binary compatible**
|
||||||
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
|
||||||
cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
|
cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
|
||||||
|
|
@ -114,7 +114,8 @@ var
|
||||||
gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of
|
gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of
|
||||||
# the tracked source X, saved by the CAAS client.
|
# the tracked source X, saved by the CAAS client.
|
||||||
gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer.
|
gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer.
|
||||||
gNoBabelPath* = false
|
gNoNimblePath* = false
|
||||||
|
gExperimentalMode*: bool
|
||||||
|
|
||||||
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
|
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
|
||||||
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
|
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
|
||||||
|
|
@ -139,7 +140,7 @@ const
|
||||||
JsonExt* = "json"
|
JsonExt* = "json"
|
||||||
TexExt* = "tex"
|
TexExt* = "tex"
|
||||||
IniExt* = "ini"
|
IniExt* = "ini"
|
||||||
DefaultConfig* = "nimrod.cfg"
|
DefaultConfig* = "nim.cfg"
|
||||||
DocConfig* = "nimdoc.cfg"
|
DocConfig* = "nimdoc.cfg"
|
||||||
DocTexConfig* = "nimdoc.tex.cfg"
|
DocTexConfig* = "nimdoc.tex.cfg"
|
||||||
|
|
||||||
|
|
@ -152,7 +153,6 @@ var
|
||||||
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
|
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
|
||||||
gProjectFull* = "" # projectPath/projectName
|
gProjectFull* = "" # projectPath/projectName
|
||||||
gProjectMainIdx*: int32 # the canonical path id of the main module
|
gProjectMainIdx*: int32 # the canonical path id of the main module
|
||||||
optMainModule* = "" # the main module that should be used for idetools commands
|
|
||||||
nimcacheDir* = ""
|
nimcacheDir* = ""
|
||||||
command* = "" # the main command (e.g. cc, check, scan, etc)
|
command* = "" # the main command (e.g. cc, check, scan, etc)
|
||||||
commandArgs*: seq[string] = @[] # any arguments after the main command
|
commandArgs*: seq[string] = @[] # any arguments after the main command
|
||||||
|
|
@ -189,8 +189,8 @@ proc getPrefixDir*(): string =
|
||||||
result = splitPath(getAppDir()).head
|
result = splitPath(getAppDir()).head
|
||||||
|
|
||||||
proc canonicalizePath*(path: string): string =
|
proc canonicalizePath*(path: string): string =
|
||||||
result = path.expandFilename
|
when not FileSystemCaseSensitive: result = path.expandFilename.toLower
|
||||||
when not FileSystemCaseSensitive: result = result.toLower
|
else: result = path.expandFilename
|
||||||
|
|
||||||
proc shortenDir*(dir: string): string =
|
proc shortenDir*(dir: string): string =
|
||||||
## returns the interesting part of a dir
|
## returns the interesting part of a dir
|
||||||
|
|
@ -238,6 +238,9 @@ proc getPackageName*(path: string): string =
|
||||||
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
|
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
|
||||||
return packageCache[d]
|
return packageCache[d]
|
||||||
inc parents
|
inc parents
|
||||||
|
for file in walkFiles(d / "*.nimble"):
|
||||||
|
result = file.splitFile.name
|
||||||
|
break packageSearch
|
||||||
for file in walkFiles(d / "*.babel"):
|
for file in walkFiles(d / "*.babel"):
|
||||||
result = file.splitFile.name
|
result = file.splitFile.name
|
||||||
break packageSearch
|
break packageSearch
|
||||||
|
|
@ -295,7 +298,7 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
||||||
createDir(subdir)
|
createDir(subdir)
|
||||||
when noTimeMachine:
|
when noTimeMachine:
|
||||||
excludeDirFromTimeMachine(subdir)
|
excludeDirFromTimeMachine(subdir)
|
||||||
except EOS:
|
except OSError:
|
||||||
writeln(stdout, "cannot create directory: " & subdir)
|
writeln(stdout, "cannot create directory: " & subdir)
|
||||||
quit(1)
|
quit(1)
|
||||||
result = joinPath(subdir, tail)
|
result = joinPath(subdir, tail)
|
||||||
|
|
@ -335,6 +338,16 @@ proc findFile*(f: string): string {.procvar.} =
|
||||||
|
|
||||||
proc findModule*(modulename, currentModule: string): string =
|
proc findModule*(modulename, currentModule: string): string =
|
||||||
# returns path to module
|
# returns path to module
|
||||||
|
when defined(nimfix):
|
||||||
|
# '.nimfix' modules are preferred over '.nim' modules so that specialized
|
||||||
|
# versions can be kept for 'nimfix'.
|
||||||
|
block:
|
||||||
|
let m = addFileExt(modulename, "nimfix")
|
||||||
|
let currentPath = currentModule.splitFile.dir
|
||||||
|
result = currentPath / m
|
||||||
|
if not existsFile(result):
|
||||||
|
result = findFile(m)
|
||||||
|
if existsFile(result): return result
|
||||||
let m = addFileExt(modulename, NimExt)
|
let m = addFileExt(modulename, NimExt)
|
||||||
let currentPath = currentModule.splitFile.dir
|
let currentPath = currentModule.splitFile.dir
|
||||||
result = currentPath / m
|
result = currentPath / m
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module implements the parser of the standard Nimrod syntax.
|
# This module implements the parser of the standard Nim syntax.
|
||||||
# The parser strictly reflects the grammar ("doc/grammar.txt"); however
|
# The parser strictly reflects the grammar ("doc/grammar.txt"); however
|
||||||
# it uses several helper routines to keep the parser small. A special
|
# it uses several helper routines to keep the parser small. A special
|
||||||
# efficient algorithm is used for the precedence levels. The parser here can
|
# efficient algorithm is used for the precedence levels. The parser here can
|
||||||
|
|
@ -41,8 +41,7 @@ type
|
||||||
proc parseAll*(p: var TParser): PNode
|
proc parseAll*(p: var TParser): PNode
|
||||||
proc closeParser*(p: var TParser)
|
proc closeParser*(p: var TParser)
|
||||||
proc parseTopLevelStmt*(p: var TParser): PNode
|
proc parseTopLevelStmt*(p: var TParser): PNode
|
||||||
proc parseString*(s: string, filename: string = "", line: int = 0): PNode
|
|
||||||
|
|
||||||
# helpers for the other parsers
|
# helpers for the other parsers
|
||||||
proc isOperator*(tok: TToken): bool
|
proc isOperator*(tok: TToken): bool
|
||||||
proc getTok*(p: var TParser)
|
proc getTok*(p: var TParser)
|
||||||
|
|
@ -84,7 +83,7 @@ proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream,
|
||||||
|
|
||||||
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
|
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
|
||||||
strongSpaces=false) =
|
strongSpaces=false) =
|
||||||
openParser(p, filename.fileInfoIdx, inputstream, strongSpaces)
|
openParser(p, filename.fileInfoIdx, inputStream, strongSpaces)
|
||||||
|
|
||||||
proc closeParser(p: var TParser) =
|
proc closeParser(p: var TParser) =
|
||||||
## Close a parser, freeing up its resources.
|
## Close a parser, freeing up its resources.
|
||||||
|
|
@ -96,7 +95,7 @@ proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
|
||||||
|
|
||||||
proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
|
proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
|
||||||
## Produce and emit a parser message to output about the token `tok`
|
## Produce and emit a parser message to output about the token `tok`
|
||||||
lexMessage(p.lex, msg, prettyTok(tok))
|
parMessage(p, msg, prettyTok(tok))
|
||||||
|
|
||||||
template withInd(p: expr, body: stmt) {.immediate.} =
|
template withInd(p: expr, body: stmt) {.immediate.} =
|
||||||
let oldInd = p.currInd
|
let oldInd = p.currInd
|
||||||
|
|
@ -189,18 +188,13 @@ proc parseTypeDesc(p: var TParser): PNode
|
||||||
proc parseDoBlocks(p: var TParser, call: PNode)
|
proc parseDoBlocks(p: var TParser, call: PNode)
|
||||||
proc parseParamList(p: var TParser, retColon = true): PNode
|
proc parseParamList(p: var TParser, retColon = true): PNode
|
||||||
|
|
||||||
proc relevantOprChar(ident: PIdent): char {.inline.} =
|
|
||||||
result = ident.s[0]
|
|
||||||
var L = ident.s.len
|
|
||||||
if result == '\\' and L > 1:
|
|
||||||
result = ident.s[1]
|
|
||||||
|
|
||||||
proc isSigilLike(tok: TToken): bool {.inline.} =
|
proc isSigilLike(tok: TToken): bool {.inline.} =
|
||||||
result = tok.tokType == tkOpr and relevantOprChar(tok.ident) == '@'
|
result = tok.tokType == tkOpr and tok.ident.s[0] == '@'
|
||||||
|
|
||||||
proc isLeftAssociative(tok: TToken): bool {.inline.} =
|
proc isRightAssociative(tok: TToken): bool {.inline.} =
|
||||||
## Determines whether the token is left assocative.
|
## Determines whether the token is right assocative.
|
||||||
result = tok.tokType != tkOpr or relevantOprChar(tok.ident) != '^'
|
result = tok.tokType == tkOpr and (tok.ident.s[0] == '^' or
|
||||||
|
(let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
|
||||||
|
|
||||||
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
||||||
## Calculates the precedence of the given token.
|
## Calculates the precedence of the given token.
|
||||||
|
|
@ -210,7 +204,10 @@ proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
||||||
case tok.tokType
|
case tok.tokType
|
||||||
of tkOpr:
|
of tkOpr:
|
||||||
let L = tok.ident.s.len
|
let L = tok.ident.s.len
|
||||||
let relevantChar = relevantOprChar(tok.ident)
|
let relevantChar = tok.ident.s[0]
|
||||||
|
|
||||||
|
# arrow like?
|
||||||
|
if L > 1 and tok.ident.s[L-1] == '>': return considerStrongSpaces(1)
|
||||||
|
|
||||||
template considerAsgn(value: expr) =
|
template considerAsgn(value: expr) =
|
||||||
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
|
result = if tok.ident.s[L-1] == '=': 1 else: considerStrongSpaces(value)
|
||||||
|
|
@ -270,17 +267,18 @@ proc checkBinary(p: TParser) {.inline.} =
|
||||||
#|
|
#|
|
||||||
#| optInd = COMMENT?
|
#| optInd = COMMENT?
|
||||||
#| optPar = (IND{>} | IND{=})?
|
#| optPar = (IND{>} | IND{=})?
|
||||||
#|
|
#|
|
||||||
#| simpleExpr = assignExpr (OP0 optInd assignExpr)*
|
#| simpleExpr = arrowExpr (OP0 optInd arrowExpr)*
|
||||||
#| assignExpr = orExpr (OP1 optInd orExpr)*
|
#| arrowExpr = assignExpr (OP1 optInd assignExpr)*
|
||||||
#| orExpr = andExpr (OP2 optInd andExpr)*
|
#| assignExpr = orExpr (OP2 optInd orExpr)*
|
||||||
#| andExpr = cmpExpr (OP3 optInd cmpExpr)*
|
#| orExpr = andExpr (OP3 optInd andExpr)*
|
||||||
#| cmpExpr = sliceExpr (OP4 optInd sliceExpr)*
|
#| andExpr = cmpExpr (OP4 optInd cmpExpr)*
|
||||||
#| sliceExpr = ampExpr (OP5 optInd ampExpr)*
|
#| cmpExpr = sliceExpr (OP5 optInd sliceExpr)*
|
||||||
#| ampExpr = plusExpr (OP6 optInd plusExpr)*
|
#| sliceExpr = ampExpr (OP6 optInd ampExpr)*
|
||||||
#| plusExpr = mulExpr (OP7 optInd mulExpr)*
|
#| ampExpr = plusExpr (OP7 optInd plusExpr)*
|
||||||
#| mulExpr = dollarExpr (OP8 optInd dollarExpr)*
|
#| plusExpr = mulExpr (OP8 optInd mulExpr)*
|
||||||
#| dollarExpr = primary (OP9 optInd primary)*
|
#| mulExpr = dollarExpr (OP9 optInd dollarExpr)*
|
||||||
|
#| dollarExpr = primary (OP10 optInd primary)*
|
||||||
|
|
||||||
proc colcom(p: var TParser, n: PNode) =
|
proc colcom(p: var TParser, n: PNode) =
|
||||||
eat(p, tkColon)
|
eat(p, tkColon)
|
||||||
|
|
@ -507,7 +505,7 @@ proc parsePar(p: var TParser): PNode =
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
|
if p.tok.tokType in {tkDiscard, tkInclude, tkIf, tkWhile, tkCase,
|
||||||
tkTry, tkFinally, tkExcept, tkFor, tkBlock,
|
tkTry, tkDefer, tkFinally, tkExcept, tkFor, tkBlock,
|
||||||
tkConst, tkLet, tkWhen, tkVar,
|
tkConst, tkLet, tkWhen, tkVar,
|
||||||
tkMixin}:
|
tkMixin}:
|
||||||
# XXX 'bind' used to be an expression, so we exclude it here;
|
# XXX 'bind' used to be an expression, so we exclude it here;
|
||||||
|
|
@ -735,7 +733,7 @@ proc parseOperators(p: var TParser, headNode: PNode,
|
||||||
# the operator itself must not start on a new line:
|
# the operator itself must not start on a new line:
|
||||||
while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
|
while opPrec >= limit and p.tok.indent < 0 and not isUnary(p):
|
||||||
checkBinary(p)
|
checkBinary(p)
|
||||||
var leftAssoc = ord(isLeftAssociative(p.tok))
|
var leftAssoc = 1-ord(isRightAssociative(p.tok))
|
||||||
var a = newNodeP(nkInfix, p)
|
var a = newNodeP(nkInfix, p)
|
||||||
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
|
var opNode = newIdentNodeP(p.tok.ident, p) # skip operator:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
|
|
@ -896,7 +894,8 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
|
||||||
var a: PNode
|
var a: PNode
|
||||||
result = newNodeP(nkFormalParams, p)
|
result = newNodeP(nkFormalParams, p)
|
||||||
addSon(result, ast.emptyNode) # return type
|
addSon(result, ast.emptyNode) # return type
|
||||||
if p.tok.tokType == tkParLe and p.tok.indent < 0:
|
let hasParLe = p.tok.tokType == tkParLe and p.tok.indent < 0
|
||||||
|
if hasParLe:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -920,6 +919,9 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
|
||||||
getTok(p)
|
getTok(p)
|
||||||
optInd(p, result)
|
optInd(p, result)
|
||||||
result.sons[0] = parseTypeDesc(p)
|
result.sons[0] = parseTypeDesc(p)
|
||||||
|
elif not retColon and not hasParle:
|
||||||
|
# Mark as "not there" in order to mark for deprecation in the semantic pass:
|
||||||
|
result = ast.emptyNode
|
||||||
|
|
||||||
proc optPragmas(p: var TParser): PNode =
|
proc optPragmas(p: var TParser): PNode =
|
||||||
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
|
if p.tok.tokType == tkCurlyDotLe and (p.tok.indent < 0 or realInd(p)):
|
||||||
|
|
@ -1132,7 +1134,7 @@ proc parseMacroColon(p: var TParser, x: PNode): PNode =
|
||||||
skipComment(p, result)
|
skipComment(p, result)
|
||||||
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
|
||||||
let body = parseStmt(p)
|
let body = parseStmt(p)
|
||||||
addSon(result, newProcNode(nkDo, body.info, body))
|
addSon(result, makeStmtList(body))
|
||||||
while sameInd(p):
|
while sameInd(p):
|
||||||
var b: PNode
|
var b: PNode
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
|
|
@ -1424,9 +1426,10 @@ proc parseBlock(p: var TParser): PNode =
|
||||||
colcom(p, result)
|
colcom(p, result)
|
||||||
addSon(result, parseStmt(p))
|
addSon(result, parseStmt(p))
|
||||||
|
|
||||||
proc parseStatic(p: var TParser): PNode =
|
proc parseStaticOrDefer(p: var TParser; k: TNodeKind): PNode =
|
||||||
#| staticStmt = 'static' colcom stmt
|
#| staticStmt = 'static' colcom stmt
|
||||||
result = newNodeP(nkStaticStmt, p)
|
#| deferStmt = 'defer' colcom stmt
|
||||||
|
result = newNodeP(k, p)
|
||||||
getTokNoInd(p)
|
getTokNoInd(p)
|
||||||
colcom(p, result)
|
colcom(p, result)
|
||||||
addSon(result, parseStmt(p))
|
addSon(result, parseStmt(p))
|
||||||
|
|
@ -1864,7 +1867,7 @@ proc simpleStmt(p: var TParser): PNode =
|
||||||
proc complexOrSimpleStmt(p: var TParser): PNode =
|
proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||||
#| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
|
#| complexOrSimpleStmt = (ifStmt | whenStmt | whileStmt
|
||||||
#| | tryStmt | finallyStmt | exceptStmt | forStmt
|
#| | tryStmt | finallyStmt | exceptStmt | forStmt
|
||||||
#| | blockStmt | staticStmt | asmStmt
|
#| | blockStmt | staticStmt | deferStmt | asmStmt
|
||||||
#| | 'proc' routine
|
#| | 'proc' routine
|
||||||
#| | 'method' routine
|
#| | 'method' routine
|
||||||
#| | 'iterator' routine
|
#| | 'iterator' routine
|
||||||
|
|
@ -1885,7 +1888,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
|
||||||
of tkExcept: result = parseExceptBlock(p, nkExceptBranch)
|
of tkExcept: result = parseExceptBlock(p, nkExceptBranch)
|
||||||
of tkFor: result = parseFor(p)
|
of tkFor: result = parseFor(p)
|
||||||
of tkBlock: result = parseBlock(p)
|
of tkBlock: result = parseBlock(p)
|
||||||
of tkStatic: result = parseStatic(p)
|
of tkStatic: result = parseStaticOrDefer(p, nkStaticStmt)
|
||||||
|
of tkDefer: result = parseStaticOrDefer(p, nkDefer)
|
||||||
of tkAsm: result = parseAsm(p)
|
of tkAsm: result = parseAsm(p)
|
||||||
of tkProc: result = parseRoutine(p, nkProcDef)
|
of tkProc: result = parseRoutine(p, nkProcDef)
|
||||||
of tkMethod: result = parseRoutine(p, nkMethodDef)
|
of tkMethod: result = parseRoutine(p, nkMethodDef)
|
||||||
|
|
@ -1980,22 +1984,25 @@ proc parseTopLevelStmt(p: var TParser): PNode =
|
||||||
## top-level statement or emptyNode if end of stream.
|
## top-level statement or emptyNode if end of stream.
|
||||||
result = ast.emptyNode
|
result = ast.emptyNode
|
||||||
while true:
|
while true:
|
||||||
if p.tok.indent != 0:
|
if p.tok.indent != 0:
|
||||||
if p.firstTok and p.tok.indent < 0: discard
|
if p.firstTok and p.tok.indent < 0: discard
|
||||||
else: parMessage(p, errInvalidIndentation)
|
elif p.tok.tokType != tkSemiColon:
|
||||||
|
parMessage(p, errInvalidIndentation)
|
||||||
p.firstTok = false
|
p.firstTok = false
|
||||||
case p.tok.tokType
|
case p.tok.tokType
|
||||||
of tkSemiColon:
|
of tkSemiColon:
|
||||||
getTok(p)
|
getTok(p)
|
||||||
if p.tok.indent <= 0: discard
|
if p.tok.indent <= 0: discard
|
||||||
else: parMessage(p, errInvalidIndentation)
|
else: parMessage(p, errInvalidIndentation)
|
||||||
|
p.firstTok = true
|
||||||
of tkEof: break
|
of tkEof: break
|
||||||
else:
|
else:
|
||||||
result = complexOrSimpleStmt(p)
|
result = complexOrSimpleStmt(p)
|
||||||
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
|
if result.kind == nkEmpty: parMessage(p, errExprExpected, p.tok)
|
||||||
break
|
break
|
||||||
|
|
||||||
proc parseString(s: string, filename: string = "", line: int = 0): PNode =
|
proc parseString*(s: string; filename: string = ""; line: int = 0;
|
||||||
|
errorHandler: TErrorHandler = nil): PNode =
|
||||||
## Parses a string into an AST, returning the top node.
|
## Parses a string into an AST, returning the top node.
|
||||||
## `filename` and `line`, although optional, provide info so that the
|
## `filename` and `line`, although optional, provide info so that the
|
||||||
## compiler can generate correct error messages referring to the original
|
## compiler can generate correct error messages referring to the original
|
||||||
|
|
@ -2007,6 +2014,7 @@ proc parseString(s: string, filename: string = "", line: int = 0): PNode =
|
||||||
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
|
# XXX for now the builtin 'parseStmt/Expr' functions do not know about strong
|
||||||
# spaces...
|
# spaces...
|
||||||
openParser(parser, filename, stream, false)
|
openParser(parser, filename, stream, false)
|
||||||
|
parser.lex.errorHandler = errorHandler
|
||||||
|
|
||||||
result = parser.parseAll
|
result = parser.parseAll
|
||||||
closeParser(parser)
|
closeParser(parser)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -16,7 +16,7 @@ import
|
||||||
nimsets, syntaxes, times, rodread, idgen
|
nimsets, syntaxes, times, rodread, idgen
|
||||||
|
|
||||||
type
|
type
|
||||||
TPassContext* = object of TObject # the pass's context
|
TPassContext* = object of RootObj # the pass's context
|
||||||
fromCache*: bool # true if created by "openCached"
|
fromCache*: bool # true if created by "openCached"
|
||||||
|
|
||||||
PPassContext* = ref TPassContext
|
PPassContext* = ref TPassContext
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -260,7 +260,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||||
# couldn't bind parameter:
|
# couldn't bind parameter:
|
||||||
if isNil(x): return nil
|
if isNil(x): return nil
|
||||||
result.add(x)
|
result.add(x)
|
||||||
if requiresAA: addToArgList(args, n)
|
if requiresAA: addToArgList(args, x)
|
||||||
# perform alias analysis here:
|
# perform alias analysis here:
|
||||||
if requiresAA:
|
if requiresAA:
|
||||||
for i in 1 .. < params.len:
|
for i in 1 .. < params.len:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ const
|
||||||
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated,
|
||||||
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
|
||||||
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto,
|
||||||
wInjectStmt, wDeprecated}
|
wInjectStmt, wDeprecated, wExperimental}
|
||||||
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
|
||||||
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader,
|
||||||
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame,
|
||||||
|
|
@ -71,7 +71,7 @@ const
|
||||||
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc invalidPragma(n: PNode) =
|
proc invalidPragma(n: PNode) =
|
||||||
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
|
localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments}))
|
||||||
|
|
||||||
proc pragmaAsm*(c: PContext, n: PNode): char =
|
proc pragmaAsm*(c: PContext, n: PNode): char =
|
||||||
|
|
@ -130,6 +130,7 @@ proc processImportCpp(s: PSym, extname: string) =
|
||||||
excl(s.flags, sfForward)
|
excl(s.flags, sfForward)
|
||||||
let m = s.getModule()
|
let m = s.getModule()
|
||||||
incl(m.flags, sfCompileToCpp)
|
incl(m.flags, sfCompileToCpp)
|
||||||
|
extccomp.gMixedMode = true
|
||||||
|
|
||||||
proc processImportObjC(s: PSym, extname: string) =
|
proc processImportObjC(s: PSym, extname: string) =
|
||||||
setExternName(s, extname)
|
setExternName(s, extname)
|
||||||
|
|
@ -356,11 +357,11 @@ proc processPush(c: PContext, n: PNode, start: int) =
|
||||||
append(c.optionStack, x)
|
append(c.optionStack, x)
|
||||||
for i in countup(start, sonsLen(n) - 1):
|
for i in countup(start, sonsLen(n) - 1):
|
||||||
if processOption(c, n.sons[i]):
|
if processOption(c, n.sons[i]):
|
||||||
# simply store it somehwere:
|
# simply store it somewhere:
|
||||||
if x.otherPragmas.isNil:
|
if x.otherPragmas.isNil:
|
||||||
x.otherPragmas = newNodeI(nkPragma, n.info)
|
x.otherPragmas = newNodeI(nkPragma, n.info)
|
||||||
x.otherPragmas.add n.sons[i]
|
x.otherPragmas.add n.sons[i]
|
||||||
#LocalError(n.info, errOptionExpected)
|
#localError(n.info, errOptionExpected)
|
||||||
|
|
||||||
proc processPop(c: PContext, n: PNode) =
|
proc processPop(c: PContext, n: PNode) =
|
||||||
if c.optionStack.counter <= 1:
|
if c.optionStack.counter <= 1:
|
||||||
|
|
@ -447,6 +448,9 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode =
|
||||||
addSon(result, newSymNode(e))
|
addSon(result, newSymNode(e))
|
||||||
else:
|
else:
|
||||||
addSon(result, newStrNode(nkStrLit, sub))
|
addSon(result, newStrNode(nkStrLit, sub))
|
||||||
|
else:
|
||||||
|
# an empty '``' produces a single '`'
|
||||||
|
addSon(result, newStrNode(nkStrLit, $marker))
|
||||||
if c < 0: break
|
if c < 0: break
|
||||||
a = c + 1
|
a = c + 1
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
|
|
@ -518,6 +522,28 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) =
|
||||||
else:
|
else:
|
||||||
invalidPragma(n)
|
invalidPragma(n)
|
||||||
|
|
||||||
|
proc pragmaLockStmt(c: PContext; it: PNode) =
|
||||||
|
if it.kind != nkExprColonExpr:
|
||||||
|
invalidPragma(it)
|
||||||
|
else:
|
||||||
|
let n = it[1]
|
||||||
|
if n.kind != nkBracket:
|
||||||
|
localError(n.info, errGenerated, "locks pragma takes a list of expressions")
|
||||||
|
else:
|
||||||
|
for i in 0 .. <n.len:
|
||||||
|
n.sons[i] = c.semExpr(c, n.sons[i])
|
||||||
|
|
||||||
|
proc pragmaLocks(c: PContext, it: PNode): TLockLevel =
|
||||||
|
if it.kind != nkExprColonExpr:
|
||||||
|
invalidPragma(it)
|
||||||
|
else:
|
||||||
|
if it[1].kind != nkNilLit:
|
||||||
|
let x = expectIntLit(c, it)
|
||||||
|
if x < 0 or x > MaxLockLevel:
|
||||||
|
localError(it[1].info, "integer must be within 0.." & $MaxLockLevel)
|
||||||
|
else:
|
||||||
|
result = TLockLevel(x)
|
||||||
|
|
||||||
proc typeBorrow(sym: PSym, n: PNode) =
|
proc typeBorrow(sym: PSym, n: PNode) =
|
||||||
if n.kind == nkExprColonExpr:
|
if n.kind == nkExprColonExpr:
|
||||||
let it = n.sons[1]
|
let it = n.sons[1]
|
||||||
|
|
@ -575,6 +601,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
if c.instCounter > 100:
|
if c.instCounter > 100:
|
||||||
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
|
globalError(it.info, errRecursiveDependencyX, userPragma.name.s)
|
||||||
pragma(c, sym, userPragma.ast, validPragmas)
|
pragma(c, sym, userPragma.ast, validPragmas)
|
||||||
|
# ensure the pragma is also remember for generic instantiations in other
|
||||||
|
# modules:
|
||||||
|
n.sons[i] = userPragma.ast
|
||||||
dec c.instCounter
|
dec c.instCounter
|
||||||
else:
|
else:
|
||||||
var k = whichKeyword(key.ident)
|
var k = whichKeyword(key.ident)
|
||||||
|
|
@ -807,6 +836,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
if sym == nil: invalidPragma(it)
|
if sym == nil: invalidPragma(it)
|
||||||
of wLine: pragmaLine(c, it)
|
of wLine: pragmaLine(c, it)
|
||||||
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
of wRaises, wTags: pragmaRaisesOrTags(c, it)
|
||||||
|
of wLocks:
|
||||||
|
if sym == nil: pragmaLockStmt(c, it)
|
||||||
|
elif sym.typ == nil: invalidPragma(it)
|
||||||
|
else: sym.typ.lockLevel = pragmaLocks(c, it)
|
||||||
of wGuard:
|
of wGuard:
|
||||||
if sym == nil or sym.kind notin {skVar, skLet, skField}:
|
if sym == nil or sym.kind notin {skVar, skLet, skField}:
|
||||||
invalidPragma(it)
|
invalidPragma(it)
|
||||||
|
|
@ -817,6 +850,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||||
localError(it.info, errExprExpected)
|
localError(it.info, errExprExpected)
|
||||||
else:
|
else:
|
||||||
it.sons[1] = c.semExpr(c, it.sons[1])
|
it.sons[1] = c.semExpr(c, it.sons[1])
|
||||||
|
of wExperimental:
|
||||||
|
noVal(it)
|
||||||
|
if isTopLevel(c):
|
||||||
|
c.module.flags.incl sfExperimental
|
||||||
|
else:
|
||||||
|
localError(it.info, "'experimental' pragma only valid as toplevel statement")
|
||||||
else: invalidPragma(it)
|
else: invalidPragma(it)
|
||||||
else: invalidPragma(it)
|
else: invalidPragma(it)
|
||||||
else: processNote(c, it)
|
else: processNote(c, it)
|
||||||
|
|
@ -853,8 +892,13 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if singlePragma(c, sym, n, i, validPragmas): break
|
if n.sons[i].kind == nkPragma: pragmaRec(c, sym, n.sons[i], validPragmas)
|
||||||
|
elif singlePragma(c, sym, n, i, validPragmas): break
|
||||||
|
|
||||||
|
proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
|
||||||
|
if n == nil: return
|
||||||
|
pragmaRec(c, sym, n, validPragmas)
|
||||||
implicitPragmas(c, sym, n, validPragmas)
|
implicitPragmas(c, sym, n, validPragmas)
|
||||||
|
|
|
||||||
|
|
@ -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
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
# This is needed for proper handling of forward declarations.
|
# This is needed for proper handling of forward declarations.
|
||||||
|
|
||||||
import
|
import
|
||||||
ast, astalgo, msgs, semdata, types, trees
|
ast, astalgo, msgs, semdata, types, trees, strutils
|
||||||
|
|
||||||
proc equalGenericParams(procA, procB: PNode): bool =
|
proc equalGenericParams(procA, procB: PNode): bool =
|
||||||
if sonsLen(procA) != sonsLen(procB): return
|
if sonsLen(procA) != sonsLen(procB): return
|
||||||
|
|
@ -68,11 +68,17 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
|
||||||
ExactConstraints, IgnoreCC}
|
ExactConstraints, IgnoreCC}
|
||||||
|
|
||||||
var it: TIdentIter
|
var it: TIdentIter
|
||||||
|
|
||||||
result = initIdentIter(it, scope.symbols, fn.name)
|
result = initIdentIter(it, scope.symbols, fn.name)
|
||||||
while result != nil:
|
while result != nil:
|
||||||
if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags):
|
if result.kind in skProcKinds and sameType(result.typ, fn.typ, flags):
|
||||||
case equalParams(result.typ.n, fn.typ.n)
|
case equalParams(result.typ.n, fn.typ.n)
|
||||||
of paramsEqual:
|
of paramsEqual:
|
||||||
|
if (sfExported notin result.flags) and (sfExported in fn.flags):
|
||||||
|
let message = ("public implementation '$1' has non-public " &
|
||||||
|
"forward declaration in $2") %
|
||||||
|
[getProcHeader(result), $result.info]
|
||||||
|
localError(fn.info, errGenerated, message)
|
||||||
return
|
return
|
||||||
of paramsIncompatible:
|
of paramsIncompatible:
|
||||||
localError(fn.info, errNotOverloadable, fn.name.s)
|
localError(fn.info, errNotOverloadable, fn.name.s)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
This directory contains the Nimrod compiler written in Nimrod. Note that this
|
This directory contains the Nim compiler written in Nim. Note that this
|
||||||
code has been translated from a bootstrapping version written in Pascal, so
|
code has been translated from a bootstrapping version written in Pascal, so
|
||||||
the code is **not** a poster child of good Nimrod code.
|
the code is **not** a poster child of good Nim code.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
# distribution, for details about the copyright.
|
# distribution, for details about the copyright.
|
||||||
#
|
#
|
||||||
|
|
||||||
# This module implements the renderer of the standard Nimrod representation.
|
# This module implements the renderer of the standard Nim representation.
|
||||||
|
|
||||||
import
|
import
|
||||||
lexer, options, idents, strutils, ast, msgs, lists
|
lexer, options, idents, strutils, ast, msgs, lists
|
||||||
|
|
@ -34,6 +34,7 @@ type
|
||||||
comStack*: seq[PNode] # comment stack
|
comStack*: seq[PNode] # comment stack
|
||||||
flags*: TRenderFlags
|
flags*: TRenderFlags
|
||||||
checkAnon: bool # we're in a context that can contain sfAnon
|
checkAnon: bool # we're in a context that can contain sfAnon
|
||||||
|
inPragma: int
|
||||||
|
|
||||||
|
|
||||||
proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
|
proc renderModule*(n: PNode, filename: string, renderFlags: TRenderFlags = {})
|
||||||
|
|
@ -620,7 +621,7 @@ proc gpattern(g: var TSrcGen, n: PNode) =
|
||||||
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
|
if longMode(n) or (lsub(n.sons[0]) + g.lineLen > MaxLineLen):
|
||||||
incl(c.flags, rfLongMode)
|
incl(c.flags, rfLongMode)
|
||||||
gcoms(g) # a good place for comments
|
gcoms(g) # a good place for comments
|
||||||
gstmts(g, n.sons[0], c)
|
gstmts(g, n, c)
|
||||||
put(g, tkCurlyRi, "}")
|
put(g, tkCurlyRi, "}")
|
||||||
|
|
||||||
proc gpragmaBlock(g: var TSrcGen, n: PNode) =
|
proc gpragmaBlock(g: var TSrcGen, n: PNode) =
|
||||||
|
|
@ -894,8 +895,15 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
put(g, tkParLe, "(")
|
put(g, tkParLe, "(")
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
if i > 0: put(g, tkOpr, "|")
|
if i > 0: put(g, tkOpr, "|")
|
||||||
gsub(g, n.sons[i], c)
|
if n.sons[i].kind == nkSym:
|
||||||
put(g, tkParRi, ")")
|
let s = n[i].sym
|
||||||
|
if s.owner != nil:
|
||||||
|
put g, tkSymbol, n[i].sym.owner.name.s
|
||||||
|
put g, tkOpr, "."
|
||||||
|
put g, tkSymbol, n[i].sym.name.s
|
||||||
|
else:
|
||||||
|
gsub(g, n.sons[i], c)
|
||||||
|
put(g, tkParRi, if n.kind == nkOpenSymChoice: "|...)" else: ")")
|
||||||
of nkPar, nkClosure:
|
of nkPar, nkClosure:
|
||||||
put(g, tkParLe, "(")
|
put(g, tkParLe, "(")
|
||||||
gcomma(g, n, c)
|
gcomma(g, n, c)
|
||||||
|
|
@ -940,10 +948,10 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
of nkConstDef, nkIdentDefs:
|
of nkConstDef, nkIdentDefs:
|
||||||
gcomma(g, n, 0, -3)
|
gcomma(g, n, 0, -3)
|
||||||
var L = sonsLen(n)
|
var L = sonsLen(n)
|
||||||
if n.sons[L - 2].kind != nkEmpty:
|
if L >= 2 and n.sons[L - 2].kind != nkEmpty:
|
||||||
putWithSpace(g, tkColon, ":")
|
putWithSpace(g, tkColon, ":")
|
||||||
gsub(g, n.sons[L - 2])
|
gsub(g, n.sons[L - 2])
|
||||||
if n.sons[L - 1].kind != nkEmpty:
|
if L >= 1 and n.sons[L - 1].kind != nkEmpty:
|
||||||
put(g, tkSpaces, Space)
|
put(g, tkSpaces, Space)
|
||||||
putWithSpace(g, tkEquals, "=")
|
putWithSpace(g, tkEquals, "=")
|
||||||
gsub(g, n.sons[L - 1], c)
|
gsub(g, n.sons[L - 1], c)
|
||||||
|
|
@ -1009,9 +1017,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
put(g, tkElse, " else")
|
put(g, tkElse, " else")
|
||||||
putWithSpace(g, tkColon, ":")
|
putWithSpace(g, tkColon, ":")
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
of nkTypeOfExpr:
|
of nkTypeOfExpr:
|
||||||
putWithSpace(g, tkType, "type")
|
putWithSpace(g, tkType, "type")
|
||||||
gsub(g, n.sons[0])
|
if n.len > 0: gsub(g, n.sons[0])
|
||||||
of nkRefTy:
|
of nkRefTy:
|
||||||
if sonsLen(n) > 0:
|
if sonsLen(n) > 0:
|
||||||
putWithSpace(g, tkRef, "ref")
|
putWithSpace(g, tkRef, "ref")
|
||||||
|
|
@ -1177,12 +1185,17 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||||
of nkContinueStmt:
|
of nkContinueStmt:
|
||||||
putWithSpace(g, tkContinue, "continue")
|
putWithSpace(g, tkContinue, "continue")
|
||||||
gsub(g, n.sons[0])
|
gsub(g, n.sons[0])
|
||||||
of nkPragma:
|
of nkPragma:
|
||||||
if renderNoPragmas notin g.flags:
|
if renderNoPragmas notin g.flags:
|
||||||
put(g, tkSpaces, Space)
|
if g.inPragma <= 0:
|
||||||
put(g, tkCurlyDotLe, "{.")
|
inc g.inPragma
|
||||||
gcomma(g, n, emptyContext)
|
put(g, tkSpaces, Space)
|
||||||
put(g, tkCurlyDotRi, ".}")
|
put(g, tkCurlyDotLe, "{.")
|
||||||
|
gcomma(g, n, emptyContext)
|
||||||
|
put(g, tkCurlyDotRi, ".}")
|
||||||
|
dec g.inPragma
|
||||||
|
else:
|
||||||
|
gcomma(g, n, emptyContext)
|
||||||
of nkImportStmt, nkExportStmt:
|
of nkImportStmt, nkExportStmt:
|
||||||
if n.kind == nkImportStmt:
|
if n.kind == nkImportStmt:
|
||||||
putWithSpace(g, tkImport, "import")
|
putWithSpace(g, tkImport, "import")
|
||||||
|
|
@ -1306,7 +1319,7 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
|
||||||
proc renderModule(n: PNode, filename: string,
|
proc renderModule(n: PNode, filename: string,
|
||||||
renderFlags: TRenderFlags = {}) =
|
renderFlags: TRenderFlags = {}) =
|
||||||
var
|
var
|
||||||
f: TFile
|
f: File
|
||||||
g: TSrcGen
|
g: TSrcGen
|
||||||
initSrcGen(g, renderFlags)
|
initSrcGen(g, renderFlags)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -121,7 +121,7 @@ type
|
||||||
r*: string # writers use this
|
r*: string # writers use this
|
||||||
offset*: int # readers use this
|
offset*: int # readers use this
|
||||||
|
|
||||||
TRodReader* = object of TObject
|
TRodReader* = object of RootObj
|
||||||
pos: int # position; used for parsing
|
pos: int # position; used for parsing
|
||||||
s: cstring # mmap'ed file contents
|
s: cstring # mmap'ed file contents
|
||||||
options: TOptions
|
options: TOptions
|
||||||
|
|
@ -137,7 +137,7 @@ type
|
||||||
line: int # only used for debugging, but is always in the code
|
line: int # only used for debugging, but is always in the code
|
||||||
moduleID: int
|
moduleID: int
|
||||||
syms: TIdTable # already processed symbols
|
syms: TIdTable # already processed symbols
|
||||||
memfile: TMemFile # unfortunately there is no point in time where we
|
memfile: MemFile # unfortunately there is no point in time where we
|
||||||
# can close this! XXX
|
# can close this! XXX
|
||||||
methods*: TSymSeq
|
methods*: TSymSeq
|
||||||
origFile: string
|
origFile: string
|
||||||
|
|
@ -280,11 +280,6 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
|
||||||
loc.r = toRope(decodeStr(r.s, r.pos))
|
loc.r = toRope(decodeStr(r.s, r.pos))
|
||||||
else:
|
else:
|
||||||
loc.r = nil
|
loc.r = nil
|
||||||
if r.s[r.pos] == '?':
|
|
||||||
inc(r.pos)
|
|
||||||
loc.a = decodeVInt(r.s, r.pos)
|
|
||||||
else:
|
|
||||||
loc.a = 0
|
|
||||||
if r.s[r.pos] == '>': inc(r.pos)
|
if r.s[r.pos] == '>': inc(r.pos)
|
||||||
else: internalError(info, "decodeLoc " & r.s[r.pos])
|
else: internalError(info, "decodeLoc " & r.s[r.pos])
|
||||||
|
|
||||||
|
|
@ -326,7 +321,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
|
||||||
result.size = - 1
|
result.size = - 1
|
||||||
if r.s[r.pos] == '=':
|
if r.s[r.pos] == '=':
|
||||||
inc(r.pos)
|
inc(r.pos)
|
||||||
result.align = decodeVInt(r.s, r.pos)
|
result.align = decodeVInt(r.s, r.pos).int16
|
||||||
else:
|
else:
|
||||||
result.align = 2
|
result.align = 2
|
||||||
decodeLoc(r, result.loc, info)
|
decodeLoc(r, result.loc, info)
|
||||||
|
|
@ -503,7 +498,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
|
||||||
idTablePut(r.syms, s, s)
|
idTablePut(r.syms, s, s)
|
||||||
strTableAdd(rodCompilerprocs, s)
|
strTableAdd(rodCompilerprocs, s)
|
||||||
|
|
||||||
proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) =
|
proc processIndex(r: PRodReader; idx: var TIndex; outf: File = nil) =
|
||||||
var key, val, tmp: int
|
var key, val, tmp: int
|
||||||
inc(r.pos, 2) # skip "(\10"
|
inc(r.pos, 2) # skip "(\10"
|
||||||
inc(r.line)
|
inc(r.line)
|
||||||
|
|
@ -659,7 +654,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||||
new(result)
|
new(result)
|
||||||
try:
|
try:
|
||||||
result.memfile = memfiles.open(modfilename)
|
result.memfile = memfiles.open(modfilename)
|
||||||
except EOS:
|
except OSError:
|
||||||
return nil
|
return nil
|
||||||
result.files = @[]
|
result.files = @[]
|
||||||
result.modDeps = @[]
|
result.modDeps = @[]
|
||||||
|
|
@ -916,7 +911,7 @@ initIdTable(gTypeTable)
|
||||||
initStrTable(rodCompilerprocs)
|
initStrTable(rodCompilerprocs)
|
||||||
|
|
||||||
# viewer:
|
# viewer:
|
||||||
proc writeNode(f: TFile; n: PNode) =
|
proc writeNode(f: File; n: PNode) =
|
||||||
f.write("(")
|
f.write("(")
|
||||||
if n != nil:
|
if n != nil:
|
||||||
f.write($n.kind)
|
f.write($n.kind)
|
||||||
|
|
@ -947,7 +942,7 @@ proc writeNode(f: TFile; n: PNode) =
|
||||||
writeNode(f, n.sons[i])
|
writeNode(f, n.sons[i])
|
||||||
f.write(")")
|
f.write(")")
|
||||||
|
|
||||||
proc writeSym(f: TFile; s: PSym) =
|
proc writeSym(f: File; s: PSym) =
|
||||||
if s == nil:
|
if s == nil:
|
||||||
f.write("{}\n")
|
f.write("{}\n")
|
||||||
return
|
return
|
||||||
|
|
@ -985,7 +980,7 @@ proc writeSym(f: TFile; s: PSym) =
|
||||||
f.writeNode(s.ast)
|
f.writeNode(s.ast)
|
||||||
f.write("}\n")
|
f.write("}\n")
|
||||||
|
|
||||||
proc writeType(f: TFile; t: PType) =
|
proc writeType(f: File; t: PType) =
|
||||||
if t == nil:
|
if t == nil:
|
||||||
f.write("[]\n")
|
f.write("[]\n")
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -187,9 +187,6 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
|
||||||
if loc.r != nil:
|
if loc.r != nil:
|
||||||
add(result, '!')
|
add(result, '!')
|
||||||
encodeStr(ropeToStr(loc.r), result)
|
encodeStr(ropeToStr(loc.r), result)
|
||||||
if loc.a != 0:
|
|
||||||
add(result, '?')
|
|
||||||
encodeVInt(loc.a, result)
|
|
||||||
if oldLen + 1 == result.len:
|
if oldLen + 1 == result.len:
|
||||||
# no data was necessary, so remove the '<' again:
|
# no data was necessary, so remove the '<' again:
|
||||||
setLen(result, oldLen)
|
setLen(result, oldLen)
|
||||||
|
|
@ -297,7 +294,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
|
||||||
# the last entry of a symbol:
|
# the last entry of a symbol:
|
||||||
if s.ast != nil:
|
if s.ast != nil:
|
||||||
# we used to attempt to save space here by only storing a dummy AST if
|
# we used to attempt to save space here by only storing a dummy AST if
|
||||||
# it is not necessary, but Nimrod's heavy compile-time evaluation features
|
# it is not necessary, but Nim's heavy compile-time evaluation features
|
||||||
# make that unfeasible nowadays:
|
# make that unfeasible nowadays:
|
||||||
encodeNode(w, s.info, s.ast, result)
|
encodeNode(w, s.info, s.ast, result)
|
||||||
when false:
|
when false:
|
||||||
|
|
@ -422,7 +419,7 @@ proc addStmt(w: PRodWriter, n: PNode) =
|
||||||
|
|
||||||
proc writeRod(w: PRodWriter) =
|
proc writeRod(w: PRodWriter) =
|
||||||
processStacks(w, true)
|
processStacks(w, true)
|
||||||
var f: TFile
|
var f: File
|
||||||
if not open(f, completeGeneratedFilePath(changeFileExt(
|
if not open(f, completeGeneratedFilePath(changeFileExt(
|
||||||
w.filename.withPackageName, RodExt)),
|
w.filename.withPackageName, RodExt)),
|
||||||
fmWrite):
|
fmWrite):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
# Ropes are a data structure that represents a very long string
|
# Ropes are a data structure that represents a very long string
|
||||||
# efficiently; especially concatenation is done in O(1) instead of O(N).
|
# efficiently; especially concatenation is done in O(1) instead of O(N).
|
||||||
# Ropes make use a lazy evaluation: They are essentially concatenation
|
# Ropes make use a lazy evaluation: They are essentially concatenation
|
||||||
# trees that are only flattened when converting to a native Nimrod
|
# trees that are only flattened when converting to a native Nim
|
||||||
# string or when written to disk. The empty string is represented by a
|
# string or when written to disk. The empty string is represented by a
|
||||||
# nil pointer.
|
# nil pointer.
|
||||||
# A little picture makes everything clear:
|
# A little picture makes everything clear:
|
||||||
|
|
@ -64,7 +64,7 @@ type
|
||||||
# copy the format strings
|
# copy the format strings
|
||||||
# though it is not necessary)
|
# though it is not necessary)
|
||||||
PRope* = ref TRope
|
PRope* = ref TRope
|
||||||
TRope*{.acyclic.} = object of TObject # the empty rope is represented
|
TRope*{.acyclic.} = object of RootObj # the empty rope is represented
|
||||||
# by nil to safe space
|
# by nil to safe space
|
||||||
left*, right*: PRope
|
left*, right*: PRope
|
||||||
length*: int
|
length*: int
|
||||||
|
|
@ -216,7 +216,7 @@ proc app(a: var PRope, b: PRope) = a = con(a, b)
|
||||||
proc app(a: var PRope, b: string) = a = con(a, b)
|
proc app(a: var PRope, b: string) = a = con(a, b)
|
||||||
proc prepend(a: var PRope, b: PRope) = a = con(b, a)
|
proc prepend(a: var PRope, b: PRope) = a = con(b, a)
|
||||||
|
|
||||||
proc writeRope*(f: TFile, c: PRope) =
|
proc writeRope*(f: File, c: PRope) =
|
||||||
var stack = @[c]
|
var stack = @[c]
|
||||||
while len(stack) > 0:
|
while len(stack) > 0:
|
||||||
var it = pop(stack)
|
var it = pop(stack)
|
||||||
|
|
@ -228,7 +228,7 @@ proc writeRope*(f: TFile, c: PRope) =
|
||||||
write(f, it.data)
|
write(f, it.data)
|
||||||
|
|
||||||
proc writeRope*(head: PRope, filename: string, useWarning = false) =
|
proc writeRope*(head: PRope, filename: string, useWarning = false) =
|
||||||
var f: TFile
|
var f: File
|
||||||
if open(f, filename, fmWrite):
|
if open(f, filename, fmWrite):
|
||||||
if head != nil: writeRope(f, head)
|
if head != nil: writeRope(f, head)
|
||||||
close(f)
|
close(f)
|
||||||
|
|
@ -299,7 +299,7 @@ proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) =
|
||||||
const
|
const
|
||||||
bufSize = 1024 # 1 KB is reasonable
|
bufSize = 1024 # 1 KB is reasonable
|
||||||
|
|
||||||
proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool =
|
proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool =
|
||||||
if r.data != nil:
|
if r.data != nil:
|
||||||
if r.length > bufSize:
|
if r.length > bufSize:
|
||||||
errorHandler(rTokenTooLong, r.data)
|
errorHandler(rTokenTooLong, r.data)
|
||||||
|
|
@ -312,7 +312,7 @@ proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool =
|
||||||
if result: result = auxRopeEqualsFile(r.right, bin, buf)
|
if result: result = auxRopeEqualsFile(r.right, bin, buf)
|
||||||
|
|
||||||
proc ropeEqualsFile(r: PRope, f: string): bool =
|
proc ropeEqualsFile(r: PRope, f: string): bool =
|
||||||
var bin: TFile
|
var bin: File
|
||||||
result = open(bin, f)
|
result = open(bin, f)
|
||||||
if not result:
|
if not result:
|
||||||
return # not equal if file does not exist
|
return # not equal if file does not exist
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -15,9 +15,12 @@ import
|
||||||
magicsys, parser, nversion, nimsets, semfold, importer,
|
magicsys, parser, nversion, nimsets, semfold, importer,
|
||||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||||
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||||
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity,
|
evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
|
||||||
semparallel, lowerings
|
semparallel, lowerings
|
||||||
|
|
||||||
|
when defined(nimfix):
|
||||||
|
import nimfix.prettybase
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
|
proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.}
|
||||||
|
|
@ -37,9 +40,7 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym)
|
||||||
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
proc addParams(c: PContext, n: PNode, kind: TSymKind)
|
||||||
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
proc maybeAddResult(c: PContext, s: PSym, n: PNode)
|
||||||
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
proc instGenericContainer(c: PContext, n: PNode, header: PType): PType
|
||||||
proc tryExpr(c: PContext, n: PNode,
|
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
|
||||||
flags: TExprFlags = {}, bufferErrors = false): PNode
|
|
||||||
proc fixImmediateParams(n: PNode): PNode
|
|
||||||
proc activate(c: PContext, n: PNode)
|
proc activate(c: PContext, n: PNode)
|
||||||
proc semQuoteAst(c: PContext, n: PNode): PNode
|
proc semQuoteAst(c: PContext, n: PNode): PNode
|
||||||
proc finishMethod(c: PContext, s: PSym)
|
proc finishMethod(c: PContext, s: PSym)
|
||||||
|
|
@ -66,12 +67,25 @@ proc fitNode(c: PContext, formal: PType, arg: PNode): PNode =
|
||||||
# error correction:
|
# error correction:
|
||||||
result = copyTree(arg)
|
result = copyTree(arg)
|
||||||
result.typ = formal
|
result.typ = formal
|
||||||
|
else:
|
||||||
|
let x = result.skipConv
|
||||||
|
if x.kind == nkPar and formal.kind != tyExpr:
|
||||||
|
changeType(x, formal, check=true)
|
||||||
|
|
||||||
proc inferWithMetatype(c: PContext, formal: PType,
|
proc inferWithMetatype(c: PContext, formal: PType,
|
||||||
arg: PNode, coerceDistincts = false): PNode
|
arg: PNode, coerceDistincts = false): PNode
|
||||||
|
|
||||||
var commonTypeBegin = PType(kind: tyExpr)
|
var commonTypeBegin = PType(kind: tyExpr)
|
||||||
|
|
||||||
|
proc isEmptyContainer(t: PType): bool =
|
||||||
|
case t.kind
|
||||||
|
of tyExpr, tyNil: result = true
|
||||||
|
of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
|
||||||
|
of tySet, tySequence, tyOpenArray, tyVarargs:
|
||||||
|
result = t.sons[0].kind == tyEmpty
|
||||||
|
of tyGenericInst: result = isEmptyContainer(t.lastSon)
|
||||||
|
else: result = false
|
||||||
|
|
||||||
proc commonType*(x, y: PType): PType =
|
proc commonType*(x, y: PType): PType =
|
||||||
# new type relation that is used for array constructors,
|
# new type relation that is used for array constructors,
|
||||||
# if expressions, etc.:
|
# if expressions, etc.:
|
||||||
|
|
@ -95,6 +109,13 @@ proc commonType*(x, y: PType): PType =
|
||||||
# check for seq[empty] vs. seq[int]
|
# check for seq[empty] vs. seq[int]
|
||||||
let idx = ord(b.kind in {tyArray, tyArrayConstr})
|
let idx = ord(b.kind in {tyArray, tyArrayConstr})
|
||||||
if a.sons[idx].kind == tyEmpty: return y
|
if a.sons[idx].kind == tyEmpty: return y
|
||||||
|
elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
|
||||||
|
var nt: PType
|
||||||
|
for i in 0.. <a.len:
|
||||||
|
if isEmptyContainer(a.sons[i]) and not isEmptyContainer(b.sons[i]):
|
||||||
|
if nt.isNil: nt = copyType(a, a.owner, false)
|
||||||
|
nt.sons[i] = b.sons[i]
|
||||||
|
if not nt.isNil: result = nt
|
||||||
#elif b.sons[idx].kind == tyEmpty: return x
|
#elif b.sons[idx].kind == tyEmpty: return x
|
||||||
elif a.kind == tyRange and b.kind == tyRange:
|
elif a.kind == tyRange and b.kind == tyRange:
|
||||||
# consider: (range[0..3], range[0..4]) here. We should make that
|
# consider: (range[0..3], range[0..4]) here. We should make that
|
||||||
|
|
@ -131,17 +152,14 @@ proc commonType*(x, y: PType): PType =
|
||||||
result = newType(k, r.owner)
|
result = newType(k, r.owner)
|
||||||
result.addSonSkipIntLit(r)
|
result.addSonSkipIntLit(r)
|
||||||
|
|
||||||
proc isTopLevel(c: PContext): bool {.inline.} =
|
|
||||||
result = c.currentScope.depthLevel <= 2
|
|
||||||
|
|
||||||
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||||
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
|
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(), n.info)
|
||||||
|
|
||||||
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
|
||||||
# like newSymS, but considers gensym'ed symbols
|
# like newSymS, but considers gensym'ed symbols
|
||||||
if n.kind == nkSym:
|
if n.kind == nkSym:
|
||||||
|
# and sfGenSym in n.sym.flags:
|
||||||
result = n.sym
|
result = n.sym
|
||||||
internalAssert sfGenSym in result.flags
|
|
||||||
internalAssert result.kind == kind
|
internalAssert result.kind == kind
|
||||||
# when there is a nested proc inside a template, semtmpl
|
# when there is a nested proc inside a template, semtmpl
|
||||||
# will assign a wrong owner during the first pass over the
|
# will assign a wrong owner during the first pass over the
|
||||||
|
|
@ -308,6 +326,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
pushInfoContext(nOrig.info)
|
pushInfoContext(nOrig.info)
|
||||||
|
|
||||||
markUsed(n.info, sym)
|
markUsed(n.info, sym)
|
||||||
|
styleCheckUse(n.info, sym)
|
||||||
if sym == c.p.owner:
|
if sym == c.p.owner:
|
||||||
globalError(n.info, errRecursiveDependencyX, sym.name.s)
|
globalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||||
|
|
||||||
|
|
@ -340,7 +359,7 @@ type
|
||||||
TSemGenericFlags = set[TSemGenericFlag]
|
TSemGenericFlags = set[TSemGenericFlag]
|
||||||
|
|
||||||
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
|
proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
ctx: var TIntSet): PNode
|
ctx: var IntSet): PNode
|
||||||
|
|
||||||
include semtypes, semtempl, semgnrc, semstmts, semexprs
|
include semtypes, semtempl, semgnrc, semstmts, semexprs
|
||||||
|
|
||||||
|
|
@ -367,6 +386,8 @@ proc myOpen(module: PSym): PPassContext =
|
||||||
c.semInferredLambda = semInferredLambda
|
c.semInferredLambda = semInferredLambda
|
||||||
c.semGenerateInstance = generateInstance
|
c.semGenerateInstance = generateInstance
|
||||||
c.semTypeNode = semTypeNode
|
c.semTypeNode = semTypeNode
|
||||||
|
c.instDeepCopy = sigmatch.instDeepCopy
|
||||||
|
|
||||||
pushProcCon(c, module)
|
pushProcCon(c, module)
|
||||||
pushOwner(c.module)
|
pushOwner(c.module)
|
||||||
c.importTable = openScope(c)
|
c.importTable = openScope(c)
|
||||||
|
|
|
||||||
197
compiler/semasgn.nim
Normal file
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
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -39,7 +39,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
initialBinding: PNode,
|
initialBinding: PNode,
|
||||||
filter: TSymKinds,
|
filter: TSymKinds,
|
||||||
best, alt: var TCandidate,
|
best, alt: var TCandidate,
|
||||||
errors: var seq[string]) =
|
errors: var CandidateErrors) =
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
var sym = initOverloadIter(o, c, headSymbol)
|
var sym = initOverloadIter(o, c, headSymbol)
|
||||||
var symScope = o.lastOverloadScope
|
var symScope = o.lastOverloadScope
|
||||||
|
|
@ -58,10 +58,10 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
z.calleeSym = sym
|
z.calleeSym = sym
|
||||||
matches(c, n, orig, z)
|
matches(c, n, orig, z)
|
||||||
if errors != nil:
|
if errors != nil:
|
||||||
errors.safeAdd(getProcHeader(sym))
|
errors.safeAdd(sym)
|
||||||
if z.errors != nil:
|
if z.errors != nil:
|
||||||
for err in z.errors:
|
for err in z.errors:
|
||||||
errors[errors.len - 1].add("\n " & err)
|
errors.add(err)
|
||||||
if z.state == csMatch:
|
if z.state == csMatch:
|
||||||
# little hack so that iterators are preferred over everything else:
|
# little hack so that iterators are preferred over everything else:
|
||||||
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
if sym.kind in skIterators: inc(z.exactMatches, 200)
|
||||||
|
|
@ -74,7 +74,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||||
else: discard
|
else: discard
|
||||||
sym = nextOverloadIter(o, c, headSymbol)
|
sym = nextOverloadIter(o, c, headSymbol)
|
||||||
|
|
||||||
proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||||
# Gives a detailed error message; this is separated from semOverloadedCall,
|
# Gives a detailed error message; this is separated from semOverloadedCall,
|
||||||
# as semOverlodedCall is already pretty slow (and we need this information
|
# as semOverlodedCall is already pretty slow (and we need this information
|
||||||
# only in case of an error).
|
# only in case of an error).
|
||||||
|
|
@ -83,18 +83,38 @@ proc notFoundError*(c: PContext, n: PNode, errors: seq[string]) =
|
||||||
globalError(n.info, errTypeMismatch, "")
|
globalError(n.info, errTypeMismatch, "")
|
||||||
if errors.len == 0:
|
if errors.len == 0:
|
||||||
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
|
||||||
var result = msgKindToString(errTypeMismatch)
|
|
||||||
add(result, describeArgs(c, n, 1))
|
# to avoid confusing errors like:
|
||||||
add(result, ')')
|
# got (SslPtr, SocketHandle)
|
||||||
|
# but expected one of:
|
||||||
|
# openssl.SSL_set_fd(ssl: SslPtr, fd: SocketHandle): cint
|
||||||
|
# we do a pre-analysis. If all types produce the same string, we will add
|
||||||
|
# module information.
|
||||||
|
let proto = describeArgs(c, n, 1, preferName)
|
||||||
|
|
||||||
|
var prefer = preferName
|
||||||
|
for err in errors:
|
||||||
|
var errProto = ""
|
||||||
|
let n = err.typ.n
|
||||||
|
for i in countup(1, n.len - 1):
|
||||||
|
var p = n.sons[i]
|
||||||
|
if p.kind == nkSym:
|
||||||
|
add(errProto, typeToString(p.sym.typ, preferName))
|
||||||
|
if i != n.len-1: add(errProto, ", ")
|
||||||
|
# else: ignore internal error as we're already in error handling mode
|
||||||
|
if errProto == proto:
|
||||||
|
prefer = preferModuleInfo
|
||||||
|
break
|
||||||
|
# now use the information stored in 'prefer' to produce a nice error message:
|
||||||
|
var result = msgKindToString(errTypeMismatch)
|
||||||
|
add(result, describeArgs(c, n, 1, prefer))
|
||||||
|
add(result, ')')
|
||||||
var candidates = ""
|
var candidates = ""
|
||||||
for err in errors:
|
for err in errors:
|
||||||
add(candidates, err)
|
add(candidates, err.getProcHeader(prefer))
|
||||||
add(candidates, "\n")
|
add(candidates, "\n")
|
||||||
|
|
||||||
if candidates != "":
|
if candidates != "":
|
||||||
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
|
||||||
|
|
||||||
localError(n.info, errGenerated, result)
|
localError(n.info, errGenerated, result)
|
||||||
|
|
||||||
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
|
proc gatherUsedSyms(c: PContext, usedSyms: var seq[PNode]) =
|
||||||
|
|
@ -114,7 +134,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||||
else:
|
else:
|
||||||
initialBinding = nil
|
initialBinding = nil
|
||||||
|
|
||||||
var errors: seq[string]
|
var errors: CandidateErrors
|
||||||
var usedSyms: seq[PNode]
|
var usedSyms: seq[PNode]
|
||||||
|
|
||||||
template pickBest(headSymbol: expr) =
|
template pickBest(headSymbol: expr) =
|
||||||
|
|
@ -254,6 +274,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||||
assert x.state == csMatch
|
assert x.state == csMatch
|
||||||
var finalCallee = x.calleeSym
|
var finalCallee = x.calleeSym
|
||||||
markUsed(n.sons[0].info, finalCallee)
|
markUsed(n.sons[0].info, finalCallee)
|
||||||
|
styleCheckUse(n.sons[0].info, finalCallee)
|
||||||
if finalCallee.ast == nil:
|
if finalCallee.ast == nil:
|
||||||
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check!
|
||||||
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty:
|
||||||
|
|
@ -286,6 +307,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
initCandidate(c, m, s, n)
|
initCandidate(c, m, s, n)
|
||||||
var newInst = generateInstance(c, s, m.bindings, n.info)
|
var newInst = generateInstance(c, s, m.bindings, n.info)
|
||||||
markUsed(n.info, s)
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
result = newSymNode(newInst, n.info)
|
result = newSymNode(newInst, n.info)
|
||||||
|
|
||||||
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
|
|
@ -305,7 +327,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
result = explicitGenericSym(c, n, s)
|
result = explicitGenericSym(c, n, s)
|
||||||
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
|
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
|
||||||
# choose the generic proc with the proper number of type parameters.
|
# choose the generic proc with the proper number of type parameters.
|
||||||
# XXX I think this could be improved by reusing sigmatch.ParamTypesMatch.
|
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
|
||||||
# It's good enough for now.
|
# It's good enough for now.
|
||||||
result = newNodeI(a.kind, n.info)
|
result = newNodeI(a.kind, n.info)
|
||||||
for i in countup(0, len(a)-1):
|
for i in countup(0, len(a)-1):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -57,7 +57,7 @@ type
|
||||||
# can access private object fields
|
# can access private object fields
|
||||||
instCounter*: int # to prevent endless instantiations
|
instCounter*: int # to prevent endless instantiations
|
||||||
|
|
||||||
ambiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot
|
ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot
|
||||||
# store this info in the syms themselves!)
|
# store this info in the syms themselves!)
|
||||||
inTypeClass*: int # > 0 if we are in a user-defined type class
|
inTypeClass*: int # > 0 if we are in a user-defined type class
|
||||||
inGenericContext*: int # > 0 if we are in a generic type
|
inGenericContext*: int # > 0 if we are in a generic type
|
||||||
|
|
@ -72,8 +72,7 @@ type
|
||||||
libs*: TLinkedList # all libs used by this module
|
libs*: TLinkedList # all libs used by this module
|
||||||
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
semConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # for the pragmas
|
||||||
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semExpr*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {},
|
semTryExpr*: proc (c: PContext, n: PNode,flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
bufferErrors = false): PNode {.nimcall.}
|
|
||||||
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
|
semTryConstExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.}
|
||||||
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
semOperand*: proc (c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.nimcall.}
|
||||||
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
semConstBoolExpr*: proc (c: PContext, n: PNode): PNode {.nimcall.} # XXX bite the bullet
|
||||||
|
|
@ -83,15 +82,18 @@ type
|
||||||
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
|
semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode
|
||||||
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
|
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
|
||||||
info: TLineInfo): PSym
|
info: TLineInfo): PSym
|
||||||
includedFiles*: TIntSet # used to detect recursive include files
|
includedFiles*: IntSet # used to detect recursive include files
|
||||||
userPragmas*: TStrTable
|
userPragmas*: TStrTable
|
||||||
evalContext*: PEvalContext
|
evalContext*: PEvalContext
|
||||||
unknownIdents*: TIntSet # ids of all unknown identifiers to prevent
|
unknownIdents*: IntSet # ids of all unknown identifiers to prevent
|
||||||
# naming it multiple times
|
# naming it multiple times
|
||||||
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
|
generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile
|
||||||
lastGenericIdx*: int # used for the generics stack
|
lastGenericIdx*: int # used for the generics stack
|
||||||
hloLoopDetector*: int # used to prevent endless loops in the HLO
|
hloLoopDetector*: int # used to prevent endless loops in the HLO
|
||||||
inParallelStmt*: int
|
inParallelStmt*: int
|
||||||
|
instDeepCopy*: proc (c: PContext; dc: PSym; t: PType;
|
||||||
|
info: TLineInfo): PSym {.nimcall.}
|
||||||
|
|
||||||
|
|
||||||
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||||
result.genericSym = s
|
result.genericSym = s
|
||||||
|
|
@ -310,3 +312,8 @@ proc checkSonsLen*(n: PNode, length: int) =
|
||||||
proc checkMinSonsLen*(n: PNode, length: int) =
|
proc checkMinSonsLen*(n: PNode, length: int) =
|
||||||
if sonsLen(n) < length: illFormedAst(n)
|
if sonsLen(n) < length: illFormedAst(n)
|
||||||
|
|
||||||
|
proc isTopLevel*(c: PContext): bool {.inline.} =
|
||||||
|
result = c.currentScope.depthLevel <= 2
|
||||||
|
|
||||||
|
proc experimentalMode*(c: PContext): bool {.inline.} =
|
||||||
|
result = gExperimentalMode or sfExperimental in c.module.flags
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
proc semTemplateExpr(c: PContext, n: PNode, s: PSym,
|
||||||
flags: TExprFlags = {}): PNode =
|
flags: TExprFlags = {}): PNode =
|
||||||
markUsed(n.info, s)
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
result = evalTemplate(n, s, getCurrOwner())
|
result = evalTemplate(n, s, getCurrOwner())
|
||||||
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
|
if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags)
|
||||||
|
|
@ -79,6 +80,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
case s.kind
|
case s.kind
|
||||||
of skConst:
|
of skConst:
|
||||||
markUsed(n.info, s)
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
|
case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind
|
||||||
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||||
tyTuple, tySet, tyUInt..tyUInt64:
|
tyTuple, tySet, tyUInt..tyUInt64:
|
||||||
|
|
@ -103,6 +105,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
of skTemplate: result = semTemplateExpr(c, n, s, flags)
|
of skTemplate: result = semTemplateExpr(c, n, s, flags)
|
||||||
of skVar, skLet, skResult, skParam, skForVar:
|
of skVar, skLet, skResult, skParam, skForVar:
|
||||||
markUsed(n.info, s)
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
# if a proc accesses a global variable, it is not side effect free:
|
# if a proc accesses a global variable, it is not side effect free:
|
||||||
if sfGlobal in s.flags:
|
if sfGlobal in s.flags:
|
||||||
incl(c.p.owner.flags, sfSideEffect)
|
incl(c.p.owner.flags, sfSideEffect)
|
||||||
|
|
@ -115,6 +118,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
# var len = 0 # but won't be called
|
# var len = 0 # but won't be called
|
||||||
# genericThatUsesLen(x) # marked as taking a closure?
|
# genericThatUsesLen(x) # marked as taking a closure?
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
if s.typ.kind == tyStatic:
|
if s.typ.kind == tyStatic:
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
result.typ = s.typ
|
result.typ = s.typ
|
||||||
|
|
@ -125,12 +129,14 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
return n
|
return n
|
||||||
of skType:
|
of skType:
|
||||||
markUsed(n.info, s)
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
if s.typ.kind == tyStatic and s.typ.n != nil:
|
if s.typ.kind == tyStatic and s.typ.n != nil:
|
||||||
return s.typ.n
|
return s.typ.n
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
result.typ = makeTypeDesc(c, s.typ)
|
result.typ = makeTypeDesc(c, s.typ)
|
||||||
else:
|
else:
|
||||||
markUsed(n.info, s)
|
markUsed(n.info, s)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -259,6 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode =
|
||||||
let status = checkConvertible(c, result.typ, it.typ)
|
let status = checkConvertible(c, result.typ, it.typ)
|
||||||
if status in {convOK, convNotNeedeed}:
|
if status in {convOK, convNotNeedeed}:
|
||||||
markUsed(n.info, it.sym)
|
markUsed(n.info, it.sym)
|
||||||
|
styleCheckUse(n.info, it.sym)
|
||||||
markIndirect(c, it.sym)
|
markIndirect(c, it.sym)
|
||||||
return it
|
return it
|
||||||
localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
|
localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
|
||||||
|
|
@ -360,6 +367,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode =
|
||||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||||
t.callConv == ccClosure and
|
t.callConv == ccClosure and
|
||||||
tfIterator notin t.flags))
|
tfIterator notin t.flags))
|
||||||
|
else: discard
|
||||||
else:
|
else:
|
||||||
var t2 = n[2].typ.skipTypes({tyTypeDesc})
|
var t2 = n[2].typ.skipTypes({tyTypeDesc})
|
||||||
maybeLiftType(t2, c, n.info)
|
maybeLiftType(t2, c, n.info)
|
||||||
|
|
@ -415,34 +423,22 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode =
|
||||||
for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
|
for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i])
|
||||||
result = semExpr(c, result)
|
result = semExpr(c, result)
|
||||||
|
|
||||||
proc changeType(n: PNode, newType: PType, check: bool) =
|
proc changeType(n: PNode, newType: PType, check: bool) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkCurly, nkBracket:
|
of nkCurly, nkBracket:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
changeType(n.sons[i], elemType(newType), check)
|
changeType(n.sons[i], elemType(newType), check)
|
||||||
of nkPar:
|
of nkPar:
|
||||||
if newType.kind != tyTuple:
|
let tup = newType.skipTypes({tyGenericInst})
|
||||||
|
if tup.kind != tyTuple:
|
||||||
internalError(n.info, "changeType: no tuple type for constructor")
|
internalError(n.info, "changeType: no tuple type for constructor")
|
||||||
elif newType.n == nil: discard
|
|
||||||
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
|
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
|
||||||
var m = n.sons[i].sons[0]
|
|
||||||
if m.kind != nkSym:
|
|
||||||
internalError(m.info, "changeType(): invalid tuple constr")
|
|
||||||
return
|
|
||||||
var f = getSymFromList(newType.n, m.sym.name)
|
|
||||||
if f == nil:
|
|
||||||
internalError(m.info, "changeType(): invalid identifier")
|
|
||||||
return
|
|
||||||
changeType(n.sons[i].sons[1], f.typ, check)
|
|
||||||
else:
|
else:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var m = n.sons[i]
|
var m = n.sons[i]
|
||||||
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
|
if m.kind == nkExprColonExpr:
|
||||||
addSon(a, newSymNode(newType.n.sons[i].sym))
|
m = m.sons[1]
|
||||||
addSon(a, m)
|
n.sons[i] = m
|
||||||
changeType(m, newType.sons[i], check)
|
changeType(m, tup.sons[i], check)
|
||||||
n.sons[i] = a
|
|
||||||
of nkCharLit..nkUInt64Lit:
|
of nkCharLit..nkUInt64Lit:
|
||||||
if check:
|
if check:
|
||||||
let value = n.intVal
|
let value = n.intVal
|
||||||
|
|
@ -533,7 +529,8 @@ proc fixAbstractType(c: PContext, n: PNode) =
|
||||||
elif skipTypes(it.sons[1].typ, abstractVar).kind in
|
elif skipTypes(it.sons[1].typ, abstractVar).kind in
|
||||||
{tyNil, tyArrayConstr, tyTuple, tySet}:
|
{tyNil, tyArrayConstr, tyTuple, tySet}:
|
||||||
var s = skipTypes(it.typ, abstractVar)
|
var s = skipTypes(it.typ, abstractVar)
|
||||||
changeType(it.sons[1], s, check=true)
|
if s.kind != tyExpr:
|
||||||
|
changeType(it.sons[1], s, check=true)
|
||||||
n.sons[i] = it.sons[1]
|
n.sons[i] = it.sons[1]
|
||||||
of nkBracket:
|
of nkBracket:
|
||||||
# an implicitly constructed array (passed to an open array):
|
# an implicitly constructed array (passed to an open array):
|
||||||
|
|
@ -721,7 +718,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||||
case callee.kind
|
case callee.kind
|
||||||
of skMacro, skTemplate: discard
|
of skMacro, skTemplate: discard
|
||||||
else:
|
else:
|
||||||
if (callee.kind in skIterators) and (callee.id == c.p.owner.id):
|
if callee.kind in skIterators and callee.id == c.p.owner.id:
|
||||||
localError(n.info, errRecursiveDependencyX, callee.name.s)
|
localError(n.info, errRecursiveDependencyX, callee.name.s)
|
||||||
if sfNoSideEffect notin callee.flags:
|
if sfNoSideEffect notin callee.flags:
|
||||||
if {sfImportc, sfSideEffect} * callee.flags != {}:
|
if {sfImportc, sfSideEffect} * callee.flags != {}:
|
||||||
|
|
@ -832,45 +829,17 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if result != nil: result = afterCallActions(c, result, nOrig, flags)
|
if result != nil: result = afterCallActions(c, result, nOrig, flags)
|
||||||
else: result = errorNode(c, n)
|
else: result = errorNode(c, n)
|
||||||
|
|
||||||
proc buildStringify(c: PContext, arg: PNode): PNode =
|
|
||||||
if arg.typ != nil and
|
|
||||||
skipTypes(arg.typ, abstractInst-{tyTypeDesc}).kind == tyString:
|
|
||||||
result = arg
|
|
||||||
else:
|
|
||||||
result = newNodeI(nkCall, arg.info)
|
|
||||||
addSon(result, newIdentNode(getIdent"$", arg.info))
|
|
||||||
addSon(result, arg)
|
|
||||||
|
|
||||||
proc semEcho(c: PContext, n: PNode): PNode =
|
|
||||||
# this really is a macro
|
|
||||||
checkMinSonsLen(n, 1)
|
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
|
||||||
var arg = semExprWithType(c, n.sons[i])
|
|
||||||
arg = semExprWithType(c, buildStringify(c, arg))
|
|
||||||
n.sons[i] = arg
|
|
||||||
let t = arg.typ
|
|
||||||
if (t == nil or t.skipTypes(abstractInst).kind != tyString) and
|
|
||||||
arg.kind != nkEmpty:
|
|
||||||
localError(n.info, errGenerated,
|
|
||||||
"implicitly invoked '$' does not return string")
|
|
||||||
let t = n.sons[0].typ
|
|
||||||
if tfNoSideEffect notin t.flags: incl(c.p.owner.flags, sfSideEffect)
|
|
||||||
result = n
|
|
||||||
|
|
||||||
proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
proc buildEchoStmt(c: PContext, n: PNode): PNode =
|
||||||
# we MUST not check 'n' for semantics again here!
|
# we MUST not check 'n' for semantics again here! But for now we give up:
|
||||||
result = newNodeI(nkCall, n.info)
|
result = newNodeI(nkCall, n.info)
|
||||||
var e = strTableGet(magicsys.systemModule.tab, getIdent"echo")
|
var e = strTableGet(magicsys.systemModule.tab, getIdent"echo")
|
||||||
if e != nil:
|
if e != nil:
|
||||||
addSon(result, newSymNode(e))
|
add(result, newSymNode(e))
|
||||||
else:
|
else:
|
||||||
localError(n.info, errSystemNeeds, "echo")
|
localError(n.info, errSystemNeeds, "echo")
|
||||||
addSon(result, errorNode(c, n))
|
add(result, errorNode(c, n))
|
||||||
var arg = buildStringify(c, n)
|
add(result, n)
|
||||||
# problem is: implicit '$' is not checked for semantics yet. So we give up
|
result = semExpr(c, result)
|
||||||
# and check 'arg' for semantics again:
|
|
||||||
arg = semExpr(c, arg)
|
|
||||||
if arg != nil: addSon(result, arg)
|
|
||||||
|
|
||||||
proc semExprNoType(c: PContext, n: PNode): PNode =
|
proc semExprNoType(c: PContext, n: PNode): PNode =
|
||||||
result = semExpr(c, n, {efWantStmt})
|
result = semExpr(c, n, {efWantStmt})
|
||||||
|
|
@ -958,17 +927,18 @@ proc readTypeParameter(c: PContext, typ: PType,
|
||||||
paramName: PIdent, info: TLineInfo): PNode =
|
paramName: PIdent, info: TLineInfo): PNode =
|
||||||
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
|
let ty = if typ.kind == tyGenericInst: typ.skipGenericAlias
|
||||||
else: (internalAssert(typ.kind == tyCompositeTypeClass); typ.sons[1])
|
else: (internalAssert(typ.kind == tyCompositeTypeClass); typ.sons[1])
|
||||||
|
#debug ty
|
||||||
let tbody = ty.sons[0]
|
let tbody = ty.sons[0]
|
||||||
for s in countup(0, tbody.len-2):
|
for s in countup(0, tbody.len-2):
|
||||||
let tParam = tbody.sons[s]
|
let tParam = tbody.sons[s]
|
||||||
if tParam.sym.name == paramName:
|
if tParam.sym.name.id == paramName.id:
|
||||||
let rawTyp = ty.sons[s + 1]
|
let rawTyp = ty.sons[s + 1]
|
||||||
if rawTyp.kind == tyStatic:
|
if rawTyp.kind == tyStatic:
|
||||||
return rawTyp.n
|
return rawTyp.n
|
||||||
else:
|
else:
|
||||||
let foundTyp = makeTypeDesc(c, rawTyp)
|
let foundTyp = makeTypeDesc(c, rawTyp)
|
||||||
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
return newSymNode(copySym(tParam.sym).linkTo(foundTyp), info)
|
||||||
|
#echo "came here: returned nil"
|
||||||
|
|
||||||
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
## returns nil if it's not a built-in field access
|
## returns nil if it's not a built-in field access
|
||||||
|
|
@ -980,8 +950,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
|
|
||||||
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
||||||
if s != nil:
|
if s != nil:
|
||||||
markUsed(n.sons[1].info, s)
|
if s.kind in OverloadableSyms:
|
||||||
return semSym(c, n, s, flags)
|
result = symChoice(c, n, s, scClosed)
|
||||||
|
if result.kind == nkSym: result = semSym(c, n, s, flags)
|
||||||
|
else:
|
||||||
|
markUsed(n.sons[1].info, s)
|
||||||
|
result = semSym(c, n, s, flags)
|
||||||
|
styleCheckUse(n.sons[1].info, s)
|
||||||
|
return
|
||||||
|
|
||||||
n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
|
n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType})
|
||||||
#restoreOldStyleType(n.sons[0])
|
#restoreOldStyleType(n.sons[0])
|
||||||
|
|
@ -997,13 +973,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# look up if the identifier belongs to the enum:
|
# look up if the identifier belongs to the enum:
|
||||||
while ty != nil:
|
while ty != nil:
|
||||||
f = getSymFromList(ty.n, i)
|
f = getSymFromList(ty.n, i)
|
||||||
if f != nil: break
|
if f != nil: break
|
||||||
ty = ty.sons[0] # enum inheritance
|
ty = ty.sons[0] # enum inheritance
|
||||||
if f != nil:
|
if f != nil:
|
||||||
result = newSymNode(f)
|
result = newSymNode(f)
|
||||||
result.info = n.info
|
result.info = n.info
|
||||||
result.typ = ty
|
result.typ = ty
|
||||||
markUsed(n.info, f)
|
markUsed(n.info, f)
|
||||||
|
styleCheckUse(n.info, f)
|
||||||
return
|
return
|
||||||
of tyTypeParamsHolders:
|
of tyTypeParamsHolders:
|
||||||
return readTypeParameter(c, ty, i, n.info)
|
return readTypeParameter(c, ty, i, n.info)
|
||||||
|
|
@ -1036,12 +1013,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
if fieldVisible(c, f):
|
if fieldVisible(c, f):
|
||||||
# is the access to a public field or in the same module or in a friend?
|
# is the access to a public field or in the same module or in a friend?
|
||||||
markUsed(n.sons[1].info, f)
|
markUsed(n.sons[1].info, f)
|
||||||
|
styleCheckUse(n.sons[1].info, f)
|
||||||
n.sons[0] = makeDeref(n.sons[0])
|
n.sons[0] = makeDeref(n.sons[0])
|
||||||
n.sons[1] = newSymNode(f) # we now have the correct field
|
n.sons[1] = newSymNode(f) # we now have the correct field
|
||||||
n.typ = f.typ
|
n.typ = f.typ
|
||||||
if check == nil:
|
if check == nil:
|
||||||
result = n
|
result = n
|
||||||
else:
|
else:
|
||||||
check.sons[0] = n
|
check.sons[0] = n
|
||||||
check.typ = n.typ
|
check.typ = n.typ
|
||||||
result = check
|
result = check
|
||||||
|
|
@ -1049,6 +1027,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
f = getSymFromList(ty.n, i)
|
f = getSymFromList(ty.n, i)
|
||||||
if f != nil:
|
if f != nil:
|
||||||
markUsed(n.sons[1].info, f)
|
markUsed(n.sons[1].info, f)
|
||||||
|
styleCheckUse(n.sons[1].info, f)
|
||||||
n.sons[0] = makeDeref(n.sons[0])
|
n.sons[0] = makeDeref(n.sons[0])
|
||||||
n.sons[1] = newSymNode(f)
|
n.sons[1] = newSymNode(f)
|
||||||
n.typ = f.typ
|
n.typ = f.typ
|
||||||
|
|
@ -1260,8 +1239,8 @@ proc semAsgn(c: PContext, n: PNode): PNode =
|
||||||
proc semReturn(c: PContext, n: PNode): PNode =
|
proc semReturn(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkSonsLen(n, 1)
|
checkSonsLen(n, 1)
|
||||||
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or
|
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro,
|
||||||
c.p.owner.kind == skClosureIterator:
|
skClosureIterator}:
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
# transform ``return expr`` to ``result = expr; return``
|
# transform ``return expr`` to ``result = expr; return``
|
||||||
if c.p.resultSym != nil:
|
if c.p.resultSym != nil:
|
||||||
|
|
@ -1444,6 +1423,8 @@ proc newAnonSym(kind: TSymKind, info: TLineInfo,
|
||||||
|
|
||||||
proc semUsing(c: PContext, n: PNode): PNode =
|
proc semUsing(c: PContext, n: PNode): PNode =
|
||||||
result = newNodeI(nkEmpty, n.info)
|
result = newNodeI(nkEmpty, n.info)
|
||||||
|
if not experimentalMode(c):
|
||||||
|
localError(n.info, "use the {.experimental.} pragma to enable 'using'")
|
||||||
for e in n.sons:
|
for e in n.sons:
|
||||||
let usedSym = semExpr(c, e)
|
let usedSym = semExpr(c, e)
|
||||||
if usedSym.kind == nkSym:
|
if usedSym.kind == nkSym:
|
||||||
|
|
@ -1465,6 +1446,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
|
macroCall.sons[0] = newSymNode(expandedSym, macroCall.info)
|
||||||
markUsed(n.info, expandedSym)
|
markUsed(n.info, expandedSym)
|
||||||
|
styleCheckUse(n.info, expandedSym)
|
||||||
|
|
||||||
for i in countup(1, macroCall.len-1):
|
for i in countup(1, macroCall.len-1):
|
||||||
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
|
macroCall.sons[i] = semExprWithType(c, macroCall[i], {})
|
||||||
|
|
@ -1525,11 +1507,11 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||||
|
|
||||||
doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode
|
doBlk.sons[namePos] = newAnonSym(skTemplate, n.info).newSymNode
|
||||||
if ids.len > 0:
|
if ids.len > 0:
|
||||||
doBlk[paramsPos].sons.setLen(2)
|
doBlk.sons[paramsPos] = newNodeI(nkFormalParams, n.info)
|
||||||
doBlk[paramsPos].sons[0] = getSysSym("stmt").newSymNode # return type
|
doBlk[paramsPos].add getSysSym("stmt").newSymNode # return type
|
||||||
ids.add getSysSym("expr").newSymNode # params type
|
ids.add getSysSym("expr").newSymNode # params type
|
||||||
ids.add emptyNode # no default value
|
ids.add emptyNode # no default value
|
||||||
doBlk[paramsPos].sons[1] = newNode(nkIdentDefs, n.info, ids)
|
doBlk[paramsPos].add newNode(nkIdentDefs, n.info, ids)
|
||||||
|
|
||||||
var tmpl = semTemplateDef(c, doBlk)
|
var tmpl = semTemplateDef(c, doBlk)
|
||||||
quotes[0] = tmpl[namePos]
|
quotes[0] = tmpl[namePos]
|
||||||
|
|
@ -1538,8 +1520,7 @@ proc semQuoteAst(c: PContext, n: PNode): PNode =
|
||||||
newNode(nkCall, n.info, quotes)])
|
newNode(nkCall, n.info, quotes)])
|
||||||
result = semExpandToAst(c, result)
|
result = semExpandToAst(c, result)
|
||||||
|
|
||||||
proc tryExpr(c: PContext, n: PNode,
|
proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
flags: TExprFlags = {}, bufferErrors = false): PNode =
|
|
||||||
# watch out, hacks ahead:
|
# watch out, hacks ahead:
|
||||||
let oldErrorCount = msgs.gErrorCounter
|
let oldErrorCount = msgs.gErrorCounter
|
||||||
let oldErrorMax = msgs.gErrorMax
|
let oldErrorMax = msgs.gErrorMax
|
||||||
|
|
@ -1553,7 +1534,7 @@ proc tryExpr(c: PContext, n: PNode,
|
||||||
let oldOwnerLen = len(gOwners)
|
let oldOwnerLen = len(gOwners)
|
||||||
let oldGenerics = c.generics
|
let oldGenerics = c.generics
|
||||||
let oldErrorOutputs = errorOutputs
|
let oldErrorOutputs = errorOutputs
|
||||||
errorOutputs = if bufferErrors: {eInMemory} else: {}
|
errorOutputs = {}
|
||||||
let oldContextLen = msgs.getInfoContextLen()
|
let oldContextLen = msgs.getInfoContextLen()
|
||||||
|
|
||||||
let oldInGenericContext = c.inGenericContext
|
let oldInGenericContext = c.inGenericContext
|
||||||
|
|
@ -1638,7 +1619,6 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
of mSizeOf: result = semSizeof(c, setMs(n, s))
|
of mSizeOf: result = semSizeof(c, setMs(n, s))
|
||||||
of mIs: result = semIs(c, setMs(n, s))
|
of mIs: result = semIs(c, setMs(n, s))
|
||||||
of mOf: result = semOf(c, setMs(n, s))
|
of mOf: result = semOf(c, setMs(n, s))
|
||||||
of mEcho: result = semEcho(c, setMs(n, s))
|
|
||||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||||
of mExpandToAst: result = semExpandToAst(c, n, s, flags)
|
of mExpandToAst: result = semExpandToAst(c, n, s, flags)
|
||||||
of mQuoteAst: result = semQuoteAst(c, n)
|
of mQuoteAst: result = semQuoteAst(c, n)
|
||||||
|
|
@ -1662,6 +1642,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||||
else:
|
else:
|
||||||
result.typ = result[1].typ
|
result.typ = result[1].typ
|
||||||
result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode
|
result.add instantiateCreateFlowVarCall(c, result[1].typ, n.info).newSymNode
|
||||||
|
of mProcCall:
|
||||||
|
result = setMs(n, s)
|
||||||
|
result.sons[1] = semExpr(c, n.sons[1])
|
||||||
|
result.typ = n[1].typ
|
||||||
else: result = semDirectOp(c, n, flags)
|
else: result = semDirectOp(c, n, flags)
|
||||||
|
|
||||||
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
proc semWhen(c: PContext, n: PNode, semCheck = true): PNode =
|
||||||
|
|
@ -1821,7 +1805,7 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
addSonSkipIntLit(typ, n.sons[i].typ)
|
addSonSkipIntLit(typ, n.sons[i].typ)
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc checkInitialized(n: PNode, ids: TIntSet, info: TLineInfo) =
|
proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkRecList:
|
of nkRecList:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
|
|
@ -1902,6 +1886,7 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
||||||
addDecl(c, labl)
|
addDecl(c, labl)
|
||||||
n.sons[0] = newSymNode(labl, n.sons[0].info)
|
n.sons[0] = newSymNode(labl, n.sons[0].info)
|
||||||
suggestSym(n.sons[0].info, labl)
|
suggestSym(n.sons[0].info, labl)
|
||||||
|
styleCheckDef(labl)
|
||||||
n.sons[1] = semExpr(c, n.sons[1])
|
n.sons[1] = semExpr(c, n.sons[1])
|
||||||
n.typ = n.sons[1].typ
|
n.typ = n.sons[1].typ
|
||||||
if isEmptyType(n.typ): n.kind = nkBlockStmt
|
if isEmptyType(n.typ): n.kind = nkBlockStmt
|
||||||
|
|
@ -1909,19 +1894,6 @@ proc semBlock(c: PContext, n: PNode): PNode =
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
dec(c.p.nestedBlockCounter)
|
dec(c.p.nestedBlockCounter)
|
||||||
|
|
||||||
proc doBlockIsStmtList(n: PNode): bool =
|
|
||||||
result = n.kind == nkDo and
|
|
||||||
n[paramsPos].sonsLen == 1 and
|
|
||||||
n[paramsPos][0].kind == nkEmpty
|
|
||||||
|
|
||||||
proc fixImmediateParams(n: PNode): PNode =
|
|
||||||
# XXX: Temporary work-around until we carry out
|
|
||||||
# the planned overload resolution reforms
|
|
||||||
for i in 1 .. <safeLen(n):
|
|
||||||
if doBlockIsStmtList(n[i]):
|
|
||||||
n.sons[i] = n[i][bodyPos]
|
|
||||||
result = n
|
|
||||||
|
|
||||||
proc semExport(c: PContext, n: PNode): PNode =
|
proc semExport(c: PContext, n: PNode): PNode =
|
||||||
var x = newNodeI(n.kind, n.info)
|
var x = newNodeI(n.kind, n.info)
|
||||||
#let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
|
#let L = if n.kind == nkExportExceptStmt: L = 1 else: n.len
|
||||||
|
|
@ -1930,13 +1902,23 @@ proc semExport(c: PContext, n: PNode): PNode =
|
||||||
var o: TOverloadIter
|
var o: TOverloadIter
|
||||||
var s = initOverloadIter(o, c, a)
|
var s = initOverloadIter(o, c, a)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
localError(a.info, errGenerated, "invalid expr for 'export': " &
|
localError(a.info, errGenerated, "cannot export: " & renderTree(a))
|
||||||
renderTree(a))
|
elif s.kind == skModule:
|
||||||
while s != nil:
|
# forward everything from that module:
|
||||||
if s.kind in ExportableSymKinds+{skModule}:
|
strTableAdd(c.module.tab, s)
|
||||||
x.add(newSymNode(s, a.info))
|
x.add(newSymNode(s, a.info))
|
||||||
strTableAdd(c.module.tab, s)
|
var ti: TTabIter
|
||||||
s = nextOverloadIter(o, c, a)
|
var it = initTabIter(ti, s.tab)
|
||||||
|
while it != nil:
|
||||||
|
if it.kind in ExportableSymKinds+{skModule}:
|
||||||
|
strTableAdd(c.module.tab, it)
|
||||||
|
it = nextIter(ti, s.tab)
|
||||||
|
else:
|
||||||
|
while s != nil:
|
||||||
|
if s.kind in ExportableSymKinds+{skModule}:
|
||||||
|
x.add(newSymNode(s, a.info))
|
||||||
|
strTableAdd(c.module.tab, s)
|
||||||
|
s = nextOverloadIter(o, c, a)
|
||||||
when false:
|
when false:
|
||||||
if c.module.ast.isNil:
|
if c.module.ast.isNil:
|
||||||
c.module.ast = newNodeI(nkStmtList, n.info)
|
c.module.ast = newNodeI(nkStmtList, n.info)
|
||||||
|
|
@ -2021,22 +2003,20 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
|
let mode = if nfDotField in n.flags: {} else: {checkUndeclared}
|
||||||
var s = qualifiedLookUp(c, n.sons[0], mode)
|
var s = qualifiedLookUp(c, n.sons[0], mode)
|
||||||
if s != nil:
|
if s != nil:
|
||||||
if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
|
#if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr:
|
||||||
pretty.checkUse(n.sons[0].sons[1].info, s)
|
# pretty.checkUse(n.sons[0].sons[1].info, s)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skMacro:
|
of skMacro:
|
||||||
if sfImmediate notin s.flags:
|
if sfImmediate notin s.flags:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags)
|
||||||
else:
|
else:
|
||||||
var p = fixImmediateParams(n)
|
result = semMacroExpr(c, n, n, s, flags)
|
||||||
result = semMacroExpr(c, p, p, s, flags)
|
|
||||||
of skTemplate:
|
of skTemplate:
|
||||||
if sfImmediate notin s.flags:
|
if sfImmediate notin s.flags:
|
||||||
result = semDirectOp(c, n, flags)
|
result = semDirectOp(c, n, flags)
|
||||||
else:
|
else:
|
||||||
var p = fixImmediateParams(n)
|
result = semTemplateExpr(c, n, s, flags)
|
||||||
result = semTemplateExpr(c, p, s, flags)
|
|
||||||
of skType:
|
of skType:
|
||||||
# XXX think about this more (``set`` procs)
|
# XXX think about this more (``set`` procs)
|
||||||
if n.len == 2:
|
if n.len == 2:
|
||||||
|
|
|
||||||
163
compiler/semfields.nim
Normal file
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
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -197,18 +197,20 @@ proc getIntervalType*(m: TMagic, n: PNode): PType =
|
||||||
of mSubI, mSubI64, mSubU:
|
of mSubI, mSubI64, mSubU:
|
||||||
binaryOp(`|-|`)
|
binaryOp(`|-|`)
|
||||||
of mBitandI, mBitandI64:
|
of mBitandI, mBitandI64:
|
||||||
|
# since uint64 is still not even valid for 'range' (since it's no ordinal
|
||||||
|
# yet), we exclude it from the list (see bug #1638) for now:
|
||||||
var a = n.sons[1]
|
var a = n.sons[1]
|
||||||
var b = n.sons[2]
|
var b = n.sons[2]
|
||||||
# symmetrical:
|
# symmetrical:
|
||||||
if b.kind notin {nkIntLit..nkUInt64Lit}: swap(a, b)
|
if b.kind notin {nkIntLit..nkUInt32Lit}: swap(a, b)
|
||||||
if b.kind in {nkIntLit..nkUInt64Lit}:
|
if b.kind in {nkIntLit..nkUInt32Lit}:
|
||||||
let x = b.intVal|+|1
|
let x = b.intVal|+|1
|
||||||
if (x and -x) == x and x >= 0:
|
if (x and -x) == x and x >= 0:
|
||||||
result = makeRange(a.typ, 0, b.intVal)
|
result = makeRange(a.typ, 0, b.intVal)
|
||||||
of mModU:
|
of mModU:
|
||||||
let a = n.sons[1]
|
let a = n.sons[1]
|
||||||
let b = n.sons[2]
|
let b = n.sons[2]
|
||||||
if b.kind in {nkIntLit..nkUInt64Lit}:
|
if b.kind in {nkIntLit..nkUInt32Lit}:
|
||||||
if b.intVal >= 0:
|
if b.intVal >= 0:
|
||||||
result = makeRange(a.typ, 0, b.intVal-1)
|
result = makeRange(a.typ, 0, b.intVal-1)
|
||||||
else:
|
else:
|
||||||
|
|
@ -255,6 +257,7 @@ proc evalIs(n, a: PNode): PNode =
|
||||||
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
result = newIntNode(nkIntLit, ord(t.kind == tyProc and
|
||||||
t.callConv == ccClosure and
|
t.callConv == ccClosure and
|
||||||
tfIterator in t.flags))
|
tfIterator in t.flags))
|
||||||
|
else: discard
|
||||||
else:
|
else:
|
||||||
# XXX semexprs.isOpImpl is slightly different and requires a context. yay.
|
# XXX semexprs.isOpImpl is slightly different and requires a context. yay.
|
||||||
let t2 = n[2].typ
|
let t2 = n[2].typ
|
||||||
|
|
@ -318,8 +321,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||||
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
|
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
|
||||||
else: internalError(n.info, "constant folding for shr")
|
else: internalError(n.info, "constant folding for shr")
|
||||||
of mDivI, mDivI64: result = newIntNodeT(getInt(a) div getInt(b), n)
|
of mDivI, mDivI64:
|
||||||
of mModI, mModI64: result = newIntNodeT(getInt(a) mod getInt(b), n)
|
let y = getInt(b)
|
||||||
|
if y != 0:
|
||||||
|
result = newIntNodeT(getInt(a) div y, n)
|
||||||
|
of mModI, mModI64:
|
||||||
|
let y = getInt(b)
|
||||||
|
if y != 0:
|
||||||
|
result = newIntNodeT(getInt(a) mod y, n)
|
||||||
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
|
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
|
||||||
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
|
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
|
||||||
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
|
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
|
||||||
|
|
@ -358,8 +367,14 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||||
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
|
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
|
||||||
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
|
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
|
||||||
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
|
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
|
||||||
of mModU: result = newIntNodeT(`%%`(getInt(a), getInt(b)), n)
|
of mModU:
|
||||||
of mDivU: result = newIntNodeT(`/%`(getInt(a), getInt(b)), n)
|
let y = getInt(b)
|
||||||
|
if y != 0:
|
||||||
|
result = newIntNodeT(`%%`(getInt(a), y), n)
|
||||||
|
of mDivU:
|
||||||
|
let y = getInt(b)
|
||||||
|
if y != 0:
|
||||||
|
result = newIntNodeT(`/%`(getInt(a), y), n)
|
||||||
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
|
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
|
||||||
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
|
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
|
||||||
of mLtSet:
|
of mLtSet:
|
||||||
|
|
@ -501,7 +516,7 @@ proc foldConv*(n, a: PNode; check = false): PNode =
|
||||||
of tyInt..tyInt64:
|
of tyInt..tyInt64:
|
||||||
case skipTypes(a.typ, abstractRange).kind
|
case skipTypes(a.typ, abstractRange).kind
|
||||||
of tyFloat..tyFloat64:
|
of tyFloat..tyFloat64:
|
||||||
result = newIntNodeT(system.toInt(getFloat(a)), n)
|
result = newIntNodeT(int(getFloat(a)), n)
|
||||||
of tyChar: result = newIntNodeT(getOrdValue(a), n)
|
of tyChar: result = newIntNodeT(getOrdValue(a), n)
|
||||||
else:
|
else:
|
||||||
result = a
|
result = a
|
||||||
|
|
@ -600,10 +615,6 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
|
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
|
||||||
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
|
of mCompileDate: result = newStrNodeT(times.getDateStr(), n)
|
||||||
of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
|
of mCompileTime: result = newStrNodeT(times.getClockStr(), n)
|
||||||
of mNimrodVersion: result = newStrNodeT(VersionAsString, n)
|
|
||||||
of mNimrodMajor: result = newIntNodeT(VersionMajor, n)
|
|
||||||
of mNimrodMinor: result = newIntNodeT(VersionMinor, n)
|
|
||||||
of mNimrodPatch: result = newIntNodeT(VersionPatch, n)
|
|
||||||
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
|
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
|
||||||
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
|
of mHostOS: result = newStrNodeT(toLower(platform.OS[targetOS].name), n)
|
||||||
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)
|
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLower, n)
|
||||||
|
|
@ -683,9 +694,9 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||||
result = evalIs(n, a)
|
result = evalIs(n, a)
|
||||||
else:
|
else:
|
||||||
result = magicCall(m, n)
|
result = magicCall(m, n)
|
||||||
except EOverflow:
|
except OverflowError:
|
||||||
localError(n.info, errOverOrUnderflow)
|
localError(n.info, errOverOrUnderflow)
|
||||||
except EDivByZero:
|
except DivByZeroError:
|
||||||
localError(n.info, errConstantDivisionByZero)
|
localError(n.info, errConstantDivisionByZero)
|
||||||
of nkAddr:
|
of nkAddr:
|
||||||
var a = getConstExpr(m, n.sons[0])
|
var a = getConstExpr(m, n.sons[0])
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
# A problem is that it cannot be detected if the symbol is introduced
|
# A problem is that it cannot be detected if the symbol is introduced
|
||||||
# as in ``var x = ...`` or used because macros/templates can hide this!
|
# as in ``var x = ...`` or used because macros/templates can hide this!
|
||||||
# So we have to eval templates/macros right here so that symbol
|
# So we have to eval templates/macros right here so that symbol
|
||||||
# lookup can be accurate. XXX But this can only be done for immediate macros!
|
# lookup can be accurate.
|
||||||
|
|
||||||
# included from sem.nim
|
# included from sem.nim
|
||||||
|
|
||||||
|
|
@ -28,7 +28,7 @@ proc getIdentNode(n: PNode): PNode =
|
||||||
|
|
||||||
proc semGenericStmtScope(c: PContext, n: PNode,
|
proc semGenericStmtScope(c: PContext, n: PNode,
|
||||||
flags: TSemGenericFlags,
|
flags: TSemGenericFlags,
|
||||||
ctx: var TIntSet): PNode =
|
ctx: var IntSet): PNode =
|
||||||
openScope(c)
|
openScope(c)
|
||||||
result = semGenericStmt(c, n, flags, ctx)
|
result = semGenericStmt(c, n, flags, ctx)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
@ -37,7 +37,7 @@ template macroToExpand(s: expr): expr =
|
||||||
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
|
s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags)
|
||||||
|
|
||||||
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||||
ctx: var TIntSet): PNode =
|
ctx: var IntSet): PNode =
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
case s.kind
|
case s.kind
|
||||||
of skUnknown:
|
of skUnknown:
|
||||||
|
|
@ -47,33 +47,39 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
|
||||||
result = symChoice(c, n, s, scOpen)
|
result = symChoice(c, n, s, scOpen)
|
||||||
of skTemplate:
|
of skTemplate:
|
||||||
if macroToExpand(s):
|
if macroToExpand(s):
|
||||||
let n = fixImmediateParams(n)
|
styleCheckUse(n.info, s)
|
||||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||||
result = semGenericStmt(c, result, {}, ctx)
|
result = semGenericStmt(c, result, {}, ctx)
|
||||||
else:
|
else:
|
||||||
result = symChoice(c, n, s, scOpen)
|
result = symChoice(c, n, s, scOpen)
|
||||||
of skMacro:
|
of skMacro:
|
||||||
if macroToExpand(s):
|
if macroToExpand(s):
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||||
result = semGenericStmt(c, result, {}, ctx)
|
result = semGenericStmt(c, result, {}, ctx)
|
||||||
else:
|
else:
|
||||||
result = symChoice(c, n, s, scOpen)
|
result = symChoice(c, n, s, scOpen)
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
result = newSymNodeTypeDesc(s, n.info)
|
result = newSymNodeTypeDesc(s, n.info)
|
||||||
of skParam:
|
styleCheckUse(n.info, s)
|
||||||
|
of skParam:
|
||||||
result = n
|
result = n
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
of skType:
|
of skType:
|
||||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||||
result = newSymNodeTypeDesc(s, n.info)
|
result = newSymNodeTypeDesc(s, n.info)
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
else: result = newSymNode(s, n.info)
|
styleCheckUse(n.info, s)
|
||||||
|
else:
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
|
|
||||||
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
ctx: var TIntSet): PNode =
|
ctx: var IntSet): PNode =
|
||||||
result = n
|
result = n
|
||||||
let ident = considerQuotedIdent(n)
|
let ident = considerQuotedIdent(n)
|
||||||
var s = searchInScopes(c, ident)
|
var s = searchInScopes(c, ident).skipAlias(n)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
if ident.id notin ctx and withinMixin notin flags:
|
if ident.id notin ctx and withinMixin notin flags:
|
||||||
localError(n.info, errUndeclaredIdentifier, ident.s)
|
localError(n.info, errUndeclaredIdentifier, ident.s)
|
||||||
|
|
@ -92,7 +98,7 @@ proc newDot(n, b: PNode): PNode =
|
||||||
result.add(b)
|
result.add(b)
|
||||||
|
|
||||||
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
ctx: var TIntSet): PNode =
|
ctx: var IntSet; isMacro: var bool): PNode =
|
||||||
assert n.kind == nkDotExpr
|
assert n.kind == nkDotExpr
|
||||||
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
let luf = if withinMixin notin flags: {checkUndeclared} else: {}
|
||||||
|
|
||||||
|
|
@ -104,8 +110,9 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
result = n
|
result = n
|
||||||
let n = n[1]
|
let n = n[1]
|
||||||
let ident = considerQuotedIdent(n)
|
let ident = considerQuotedIdent(n)
|
||||||
var s = searchInScopes(c, ident)
|
var s = searchInScopes(c, ident).skipAlias(n)
|
||||||
if s != nil and s.kind in routineKinds:
|
if s != nil and s.kind in routineKinds:
|
||||||
|
isMacro = s.kind in {skTemplate, skMacro}
|
||||||
if withinBind in flags:
|
if withinBind in flags:
|
||||||
result = newDot(result, symChoice(c, n, s, scClosed))
|
result = newDot(result, symChoice(c, n, s, scClosed))
|
||||||
elif s.name.id in ctx:
|
elif s.name.id in ctx:
|
||||||
|
|
@ -117,8 +124,13 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
|
||||||
else:
|
else:
|
||||||
result = newDot(result, sym)
|
result = newDot(result, sym)
|
||||||
|
|
||||||
|
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
|
||||||
|
let s = newSymS(skUnknown, getIdentNode(n), c)
|
||||||
|
addPrelimDecl(c, s)
|
||||||
|
styleCheckDef(n.info, s, kind)
|
||||||
|
|
||||||
proc semGenericStmt(c: PContext, n: PNode,
|
proc semGenericStmt(c: PContext, n: PNode,
|
||||||
flags: TSemGenericFlags, ctx: var TIntSet): PNode =
|
flags: TSemGenericFlags, ctx: var IntSet): PNode =
|
||||||
result = n
|
result = n
|
||||||
if gCmd == cmdIdeTools: suggestStmt(c, n)
|
if gCmd == cmdIdeTools: suggestStmt(c, n)
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -129,7 +141,8 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
#var s = qualifiedLookUp(c, n, luf)
|
#var s = qualifiedLookUp(c, n, luf)
|
||||||
#if s != nil: result = semGenericStmtSymbol(c, n, s)
|
#if s != nil: result = semGenericStmtSymbol(c, n, s)
|
||||||
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
|
# XXX for example: ``result.add`` -- ``add`` needs to be looked up here...
|
||||||
result = fuzzyLookup(c, n, flags, ctx)
|
var dummy: bool
|
||||||
|
result = fuzzyLookup(c, n, flags, ctx, dummy)
|
||||||
of nkEmpty, nkSym..nkNilLit:
|
of nkEmpty, nkSym..nkNilLit:
|
||||||
# see tests/compile/tgensymgeneric.nim:
|
# see tests/compile/tgensymgeneric.nim:
|
||||||
# We need to open the gensym'ed symbol again so that the instantiation
|
# We need to open the gensym'ed symbol again so that the instantiation
|
||||||
|
|
@ -153,50 +166,61 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
|
localError(n.info, errUndeclaredIdentifier, fn.renderTree)
|
||||||
|
|
||||||
var first = 0
|
var first = 0
|
||||||
var isDefinedMagic = false
|
var mixinContext = false
|
||||||
if s != nil:
|
if s != nil:
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
isDefinedMagic = s.magic in {mDefined, mDefinedInScope, mCompiles}
|
mixinContext = s.magic in {mDefined, mDefinedInScope, mCompiles}
|
||||||
let scOption = if s.name.id in ctx: scForceOpen else: scOpen
|
let scOption = if s.name.id in ctx: scForceOpen else: scOpen
|
||||||
case s.kind
|
case s.kind
|
||||||
of skMacro:
|
of skMacro:
|
||||||
if macroToExpand(s):
|
if macroToExpand(s):
|
||||||
|
styleCheckUse(fn.info, s)
|
||||||
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
result = semMacroExpr(c, n, n, s, {efNoSemCheck})
|
||||||
result = semGenericStmt(c, result, {}, ctx)
|
result = semGenericStmt(c, result, {}, ctx)
|
||||||
else:
|
else:
|
||||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
n.sons[0] = symChoice(c, fn, s, scOption)
|
||||||
result = n
|
result = n
|
||||||
of skTemplate:
|
mixinContext = true
|
||||||
|
of skTemplate:
|
||||||
if macroToExpand(s):
|
if macroToExpand(s):
|
||||||
let n = fixImmediateParams(n)
|
styleCheckUse(fn.info, s)
|
||||||
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
result = semTemplateExpr(c, n, s, {efNoSemCheck})
|
||||||
result = semGenericStmt(c, result, {}, ctx)
|
result = semGenericStmt(c, result, {}, ctx)
|
||||||
else:
|
else:
|
||||||
n.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
n.sons[0] = symChoice(c, fn, s, scOption)
|
||||||
result = n
|
result = n
|
||||||
# BUGFIX: we must not return here, we need to do first phase of
|
# BUGFIX: we must not return here, we need to do first phase of
|
||||||
# symbol lookup ...
|
# symbol lookup. Also since templates and macros can do scope injections
|
||||||
|
# we need to put the ``c`` in ``t(c)`` in a mixin context to prevent
|
||||||
|
# the famous "undeclared identifier: it" bug:
|
||||||
|
mixinContext = true
|
||||||
of skUnknown, skParam:
|
of skUnknown, skParam:
|
||||||
# Leave it as an identifier.
|
# Leave it as an identifier.
|
||||||
discard
|
discard
|
||||||
of skProc, skMethod, skIterators, skConverter:
|
of skProc, skMethod, skIterators, skConverter:
|
||||||
result.sons[0] = symChoice(c, n.sons[0], s, scOption)
|
result.sons[0] = symChoice(c, fn, s, scOption)
|
||||||
first = 1
|
first = 1
|
||||||
of skGenericParam:
|
of skGenericParam:
|
||||||
result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info)
|
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||||
|
styleCheckUse(fn.info, s)
|
||||||
first = 1
|
first = 1
|
||||||
of skType:
|
of skType:
|
||||||
# bad hack for generics:
|
# bad hack for generics:
|
||||||
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
if (s.typ != nil) and (s.typ.kind != tyGenericParam):
|
||||||
result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info)
|
result.sons[0] = newSymNodeTypeDesc(s, fn.info)
|
||||||
|
styleCheckUse(fn.info, s)
|
||||||
first = 1
|
first = 1
|
||||||
else:
|
else:
|
||||||
result.sons[0] = newSymNode(s, n.sons[0].info)
|
result.sons[0] = newSymNode(s, fn.info)
|
||||||
|
styleCheckUse(fn.info, s)
|
||||||
first = 1
|
first = 1
|
||||||
|
elif fn.kind == nkDotExpr:
|
||||||
|
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
||||||
|
first = 1
|
||||||
# Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
# Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
||||||
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
||||||
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
||||||
let flags = if isDefinedMagic: flags+{withinMixin} else: flags
|
let flags = if mixinContext: flags+{withinMixin} else: flags
|
||||||
for i in countup(first, sonsLen(result) - 1):
|
for i in countup(first, sonsLen(result) - 1):
|
||||||
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
|
result.sons[i] = semGenericStmt(c, result.sons[i], flags, ctx)
|
||||||
of nkIfStmt:
|
of nkIfStmt:
|
||||||
|
|
@ -226,14 +250,14 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
|
n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx)
|
||||||
for i in countup(0, L - 3):
|
for i in countup(0, L - 3):
|
||||||
addPrelimDecl(c, newSymS(skUnknown, n.sons[i], c))
|
addTempDecl(c, n.sons[i], skForVar)
|
||||||
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
|
n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
of nkBlockStmt, nkBlockExpr, nkBlockType:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
addPrelimDecl(c, newSymS(skUnknown, n.sons[0], c))
|
addTempDecl(c, n.sons[0], skLabel)
|
||||||
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
of nkTryStmt:
|
of nkTryStmt:
|
||||||
|
|
@ -256,7 +280,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||||
for j in countup(0, L-3):
|
for j in countup(0, L-3):
|
||||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
addTempDecl(c, getIdentNode(a.sons[j]), skVar)
|
||||||
of nkGenericParams:
|
of nkGenericParams:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
|
|
@ -266,23 +290,23 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||||
# do not perform symbol lookup for default expressions
|
# do not perform symbol lookup for default expressions
|
||||||
for j in countup(0, L-3):
|
for j in countup(0, L-3):
|
||||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
addTempDecl(c, getIdentNode(a.sons[j]), skType)
|
||||||
of nkConstSection:
|
of nkConstSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkConstDef): illFormedAst(a)
|
if (a.kind != nkConstDef): illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
|
addTempDecl(c, getIdentNode(a.sons[0]), skConst)
|
||||||
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
|
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
|
||||||
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
|
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
|
||||||
of nkTypeSection:
|
of nkTypeSection:
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
if (a.kind != nkTypeDef): illFormedAst(a)
|
if (a.kind != nkTypeDef): illFormedAst(a)
|
||||||
checkSonsLen(a, 3)
|
checkSonsLen(a, 3)
|
||||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
|
addTempDecl(c, getIdentNode(a.sons[0]), skType)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
if a.kind == nkCommentStmt: continue
|
if a.kind == nkCommentStmt: continue
|
||||||
|
|
@ -306,9 +330,9 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
of nkIdent: a = n.sons[i]
|
of nkIdent: a = n.sons[i]
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c))
|
||||||
of nkObjectTy, nkTupleTy:
|
of nkObjectTy, nkTupleTy:
|
||||||
discard
|
discard
|
||||||
of nkFormalParams:
|
of nkFormalParams:
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
|
||||||
|
|
@ -320,17 +344,17 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||||
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
|
||||||
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
|
||||||
for j in countup(0, L-3):
|
for j in countup(0, L-3):
|
||||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
|
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
|
||||||
nkIteratorDef, nkLambdaKinds:
|
nkIteratorDef, nkLambdaKinds:
|
||||||
checkSonsLen(n, bodyPos + 1)
|
checkSonsLen(n, bodyPos + 1)
|
||||||
if n.kind notin nkLambdaKinds:
|
if n.sons[namePos].kind != nkEmpty:
|
||||||
addPrelimDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c))
|
addTempDecl(c, getIdentNode(n.sons[0]), skProc)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
|
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
|
||||||
flags, ctx)
|
flags, ctx)
|
||||||
if n.sons[paramsPos].kind != nkEmpty:
|
if n.sons[paramsPos].kind != nkEmpty:
|
||||||
if n.sons[paramsPos].sons[0].kind != nkEmpty:
|
if n.sons[paramsPos].sons[0].kind != nkEmpty:
|
||||||
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
|
addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info))
|
||||||
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
|
n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx)
|
||||||
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
|
n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -157,8 +157,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||||
#
|
#
|
||||||
# The solution would be to move this logic into semtypinst, but
|
# The solution would be to move this logic into semtypinst, but
|
||||||
# at this point semtypinst have to become part of sem, because it
|
# at this point semtypinst have to become part of sem, because it
|
||||||
# will need to use openScope, addDecl, etc
|
# will need to use openScope, addDecl, etc.
|
||||||
#
|
|
||||||
addDecl(c, prc)
|
addDecl(c, prc)
|
||||||
|
|
||||||
pushInfoContext(info)
|
pushInfoContext(info)
|
||||||
|
|
@ -223,7 +222,11 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||||
n.sons[genericParamsPos] = ast.emptyNode
|
n.sons[genericParamsPos] = ast.emptyNode
|
||||||
var oldPrc = genericCacheGet(fn, entry[])
|
var oldPrc = genericCacheGet(fn, entry[])
|
||||||
if oldPrc == nil:
|
if oldPrc == nil:
|
||||||
fn.procInstCache.safeAdd(entry)
|
# we MUST not add potentially wrong instantiations to the caching mechanism.
|
||||||
|
# This means recursive instantiations behave differently when in
|
||||||
|
# a ``compiles`` context but this is the lesser evil. See
|
||||||
|
# bug #1055 (tevilcompiles).
|
||||||
|
if c.inCompilesContext == 0: fn.procInstCache.safeAdd(entry)
|
||||||
c.generics.add(makeInstPair(fn, entry))
|
c.generics.add(makeInstPair(fn, entry))
|
||||||
if n.sons[pragmasPos].kind != nkEmpty:
|
if n.sons[pragmasPos].kind != nkEmpty:
|
||||||
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -55,7 +55,7 @@ proc annotateType*(n: PNode, t: PType) =
|
||||||
else:
|
else:
|
||||||
globalError(n.info, "() must have an object or tuple type")
|
globalError(n.info, "() must have an object or tuple type")
|
||||||
of nkBracket:
|
of nkBracket:
|
||||||
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenarray}:
|
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenArray}:
|
||||||
n.typ = t
|
n.typ = t
|
||||||
for m in n: annotateType(m, x.elemType)
|
for m in n: annotateType(m, x.elemType)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -130,4 +130,7 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||||
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
of mShallowCopy: result = semShallowCopy(c, n, flags)
|
||||||
of mNBindSym: result = semBindSym(c, n)
|
of mNBindSym: result = semBindSym(c, n)
|
||||||
of mLocals: result = semLocals(c, n)
|
of mLocals: result = semLocals(c, n)
|
||||||
|
of mProcCall:
|
||||||
|
result = n
|
||||||
|
result.typ = n[1].typ
|
||||||
else: result = n
|
else: result = n
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -258,14 +258,18 @@ proc min(a, b: PNode): PNode =
|
||||||
|
|
||||||
proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
|
proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
|
||||||
|
|
||||||
|
template pushSpawnId(c: expr, body: stmt) {.immediate, dirty.} =
|
||||||
|
inc c.spawns
|
||||||
|
let oldSpawnId = c.currentSpawnId
|
||||||
|
c.currentSpawnId = c.spawns
|
||||||
|
body
|
||||||
|
c.currentSpawnId = oldSpawnId
|
||||||
|
|
||||||
proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
|
proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
|
||||||
if op.magic == mSpawn:
|
if op.magic == mSpawn:
|
||||||
inc c.spawns
|
pushSpawnId(c):
|
||||||
let oldSpawnId = c.currentSpawnId
|
gatherArgs(c, n[1])
|
||||||
c.currentSpawnId = c.spawns
|
analyseSons(c, n)
|
||||||
gatherArgs(c, n[1])
|
|
||||||
analyseSons(c, n)
|
|
||||||
c.currentSpawnId = oldSpawnId
|
|
||||||
elif op.magic == mInc or (op.name.s == "+=" and op.fromSystem):
|
elif op.magic == mInc or (op.name.s == "+=" and op.fromSystem):
|
||||||
if n[1].isLocal:
|
if n[1].isLocal:
|
||||||
let incr = n[2].skipConv
|
let incr = n[2].skipConv
|
||||||
|
|
@ -320,9 +324,16 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
|
||||||
# since we already ensure sfAddrTaken is not in s.flags, we only need to
|
# since we already ensure sfAddrTaken is not in s.flags, we only need to
|
||||||
# prevent direct assignments to the monotonic variable:
|
# prevent direct assignments to the monotonic variable:
|
||||||
let slot = c.getSlot(n[0].sym)
|
let slot = c.getSlot(n[0].sym)
|
||||||
slot.blackListed = true
|
slot.blacklisted = true
|
||||||
invalidateFacts(c.guards, n[0])
|
invalidateFacts(c.guards, n[0])
|
||||||
analyseSons(c, n)
|
let value = n[1]
|
||||||
|
if getMagic(value) == mSpawn:
|
||||||
|
pushSpawnId(c):
|
||||||
|
gatherArgs(c, value[1])
|
||||||
|
analyseSons(c, value[1])
|
||||||
|
analyse(c, n[0])
|
||||||
|
else:
|
||||||
|
analyseSons(c, n)
|
||||||
addAsgnFact(c.guards, n[0], n[1])
|
addAsgnFact(c.guards, n[0], n[1])
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
# direct call:
|
# direct call:
|
||||||
|
|
@ -335,16 +346,21 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
|
||||||
localError(n.info, "invalid control flow for 'parallel'")
|
localError(n.info, "invalid control flow for 'parallel'")
|
||||||
# 'break' that leaves the 'parallel' section is not valid either
|
# 'break' that leaves the 'parallel' section is not valid either
|
||||||
# or maybe we should generate a 'try' XXX
|
# or maybe we should generate a 'try' XXX
|
||||||
of nkVarSection:
|
of nkVarSection, nkLetSection:
|
||||||
for it in n:
|
for it in n:
|
||||||
let value = it.lastSon
|
let value = it.lastSon
|
||||||
|
let isSpawned = getMagic(value) == mSpawn
|
||||||
|
if isSpawned:
|
||||||
|
pushSpawnId(c):
|
||||||
|
gatherArgs(c, value[1])
|
||||||
|
analyseSons(c, value[1])
|
||||||
if value.kind != nkEmpty:
|
if value.kind != nkEmpty:
|
||||||
for j in 0 .. it.len-3:
|
for j in 0 .. it.len-3:
|
||||||
if it[j].isLocal:
|
if it[j].isLocal:
|
||||||
let slot = c.getSlot(it[j].sym)
|
let slot = c.getSlot(it[j].sym)
|
||||||
if slot.lower.isNil: slot.lower = value
|
if slot.lower.isNil: slot.lower = value
|
||||||
else: internalError(it.info, "slot already has a lower bound")
|
else: internalError(it.info, "slot already has a lower bound")
|
||||||
analyse(c, value)
|
if not isSpawned: analyse(c, value)
|
||||||
of nkCaseStmt: analyseCase(c, n)
|
of nkCaseStmt: analyseCase(c, n)
|
||||||
of nkIfStmt, nkIfExpr: analyseIf(c, n)
|
of nkIfStmt, nkIfExpr: analyseIf(c, n)
|
||||||
of nkWhileStmt:
|
of nkWhileStmt:
|
||||||
|
|
@ -396,7 +412,7 @@ proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode =
|
||||||
|
|
||||||
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
|
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkVarSection:
|
of nkVarSection, nkLetSection:
|
||||||
result = nil
|
result = nil
|
||||||
for it in n:
|
for it in n:
|
||||||
let b = it.lastSon
|
let b = it.lastSon
|
||||||
|
|
@ -464,6 +480,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
|
||||||
result = newNodeI(nkStmtList, n.info)
|
result = newNodeI(nkStmtList, n.info)
|
||||||
generateAliasChecks(a, result)
|
generateAliasChecks(a, result)
|
||||||
result.add varSection
|
result.add varSection
|
||||||
result.add callCodeGenProc("openBarrier", barrier)
|
result.add callCodegenProc("openBarrier", barrier)
|
||||||
result.add transformSpawn(owner, body, barrier)
|
result.add transformSpawn(owner, body, barrier)
|
||||||
result.add callCodeGenProc("closeBarrier", barrier)
|
result.add callCodegenProc("closeBarrier", barrier)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -57,30 +57,125 @@ discard """
|
||||||
c()
|
c()
|
||||||
|
|
||||||
--> we need a stack of scopes for this analysis
|
--> we need a stack of scopes for this analysis
|
||||||
"""
|
|
||||||
|
|
||||||
const trackGlobals = false ## we don't need it for now
|
# XXX enhance the algorithm to care about 'dirty' expressions:
|
||||||
|
lock a[i].L:
|
||||||
|
inc i # mark 'i' dirty
|
||||||
|
lock a[j].L:
|
||||||
|
access a[i], a[j] # --> reject a[i]
|
||||||
|
"""
|
||||||
|
|
||||||
type
|
type
|
||||||
TEffects = object
|
TEffects = object
|
||||||
exc: PNode # stack of exceptions
|
exc: PNode # stack of exceptions
|
||||||
tags: PNode # list of tags
|
tags: PNode # list of tags
|
||||||
uses: PNode # list of used global variables
|
bottom, inTryStmt: int
|
||||||
bottom: int
|
|
||||||
owner: PSym
|
owner: PSym
|
||||||
init: seq[int] # list of initialized variables
|
init: seq[int] # list of initialized variables
|
||||||
guards: TModel # nested guards
|
guards: TModel # nested guards
|
||||||
locked: seq[PNode] # locked locations
|
locked: seq[PNode] # locked locations
|
||||||
gcUnsafe, isRecursive: bool
|
gcUnsafe, isRecursive, isToplevel: bool
|
||||||
|
maxLockLevel, currLockLevel: TLockLevel
|
||||||
PEffects = var TEffects
|
PEffects = var TEffects
|
||||||
|
|
||||||
|
proc `<`(a, b: TLockLevel): bool {.borrow.}
|
||||||
|
proc `<=`(a, b: TLockLevel): bool {.borrow.}
|
||||||
|
proc `==`(a, b: TLockLevel): bool {.borrow.}
|
||||||
|
proc max(a, b: TLockLevel): TLockLevel {.borrow.}
|
||||||
|
|
||||||
proc isLocalVar(a: PEffects, s: PSym): bool =
|
proc isLocalVar(a: PEffects, s: PSym): bool =
|
||||||
s.kind in {skVar, skResult} and sfGlobal notin s.flags and s.owner == a.owner
|
s.kind in {skVar, skResult} and sfGlobal notin s.flags and s.owner == a.owner
|
||||||
|
|
||||||
proc initVar(a: PEffects, n: PNode) =
|
proc getLockLevel(t: PType): TLockLevel =
|
||||||
|
var t = t
|
||||||
|
# tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject):
|
||||||
|
if t.kind == tyGenericInst and t.len == 3: t = t.sons[1]
|
||||||
|
if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}:
|
||||||
|
result = t.n.intVal.TLockLevel
|
||||||
|
|
||||||
|
proc lockLocations(a: PEffects; pragma: PNode) =
|
||||||
|
if pragma.kind != nkExprColonExpr:
|
||||||
|
localError(pragma.info, errGenerated, "locks pragma without argument")
|
||||||
|
return
|
||||||
|
var firstLL = TLockLevel(-1'i16)
|
||||||
|
for x in pragma[1]:
|
||||||
|
let thisLL = getLockLevel(x.typ)
|
||||||
|
if thisLL != 0.TLockLevel:
|
||||||
|
if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
|
||||||
|
localError(x.info, "invalid lock level: " & $thisLL)
|
||||||
|
elif firstLL < 0.TLockLevel: firstLL = thisLL
|
||||||
|
elif firstLL != thisLL:
|
||||||
|
localError(x.info, errGenerated,
|
||||||
|
"multi-lock requires the same static lock level for every operand")
|
||||||
|
a.maxLockLevel = max(a.maxLockLevel, firstLL)
|
||||||
|
a.locked.add x
|
||||||
|
if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
|
||||||
|
if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
|
||||||
|
localError(pragma.info, errGenerated,
|
||||||
|
"invalid nested locking")
|
||||||
|
a.currLockLevel = firstLL
|
||||||
|
|
||||||
|
proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
|
||||||
|
# check whether the corresponding lock is held:
|
||||||
|
for L in a.locked:
|
||||||
|
if L.kind == nkSym and L.sym == guard: return
|
||||||
|
# we allow accesses nevertheless in top level statements for
|
||||||
|
# easier initialization:
|
||||||
|
#if a.isTopLevel:
|
||||||
|
# message(n.info, warnUnguardedAccess, renderTree(n))
|
||||||
|
#else:
|
||||||
|
if not a.isTopLevel:
|
||||||
|
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
|
||||||
|
|
||||||
|
# 'guard*' are checks which are concerned with 'guard' annotations
|
||||||
|
# (var x{.guard: y.}: int)
|
||||||
|
proc guardDotAccess(a: PEffects; n: PNode) =
|
||||||
|
let ri = n.sons[1]
|
||||||
|
if ri.kind != nkSym or ri.sym.kind != skField: return
|
||||||
|
var g = ri.sym.guard
|
||||||
|
if g.isNil or a.isTopLevel: return
|
||||||
|
# fixup guard:
|
||||||
|
if g.kind == skUnknown:
|
||||||
|
var field: PSym = nil
|
||||||
|
var ty = n.sons[0].typ.skipTypes(abstractPtrs)
|
||||||
|
if ty.kind == tyTuple:
|
||||||
|
field = lookupInRecord(ty.n, g.name)
|
||||||
|
else:
|
||||||
|
while ty != nil and ty.kind == tyObject:
|
||||||
|
field = lookupInRecord(ty.n, g.name)
|
||||||
|
if field != nil: break
|
||||||
|
ty = ty.sons[0]
|
||||||
|
if ty == nil: break
|
||||||
|
ty = ty.skipTypes(abstractPtrs)
|
||||||
|
if field == nil:
|
||||||
|
localError(n.info, errGenerated, "invalid guard field: " & g.name.s)
|
||||||
|
return
|
||||||
|
g = field
|
||||||
|
#ri.sym.guard = field
|
||||||
|
# XXX unfortunately this is not correct for generic instantiations!
|
||||||
|
if g.kind == skField:
|
||||||
|
let dot = newNodeI(nkDotExpr, n.info, 2)
|
||||||
|
dot.sons[0] = n.sons[0]
|
||||||
|
dot.sons[1] = newSymNode(g)
|
||||||
|
dot.typ = g.typ
|
||||||
|
for L in a.locked:
|
||||||
|
#if a.guards.sameSubexprs(dot, L): return
|
||||||
|
if guards.sameTree(dot, L): return
|
||||||
|
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
|
||||||
|
else:
|
||||||
|
guardGlobal(a, n, g)
|
||||||
|
|
||||||
|
proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
|
||||||
|
template compileToCpp(a): expr =
|
||||||
|
gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
|
||||||
|
if a.inTryStmt > 0 and not compileToCpp(a):
|
||||||
|
incl(s.flags, sfVolatile)
|
||||||
|
|
||||||
|
proc initVar(a: PEffects, n: PNode; volatileCheck: bool) =
|
||||||
if n.kind != nkSym: return
|
if n.kind != nkSym: return
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
if isLocalVar(a, s):
|
if isLocalVar(a, s):
|
||||||
|
if volatileCheck: makeVolatile(a, s)
|
||||||
for x in a.init:
|
for x in a.init:
|
||||||
if x == s.id: return
|
if x == s.id: return
|
||||||
a.init.add s.id
|
a.init.add s.id
|
||||||
|
|
@ -91,14 +186,13 @@ proc initVarViaNew(a: PEffects, n: PNode) =
|
||||||
if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
|
if {tfNeedsInit, tfNotNil} * s.typ.flags <= {tfNotNil}:
|
||||||
# 'x' is not nil, but that doesn't mean its "not nil" children
|
# 'x' is not nil, but that doesn't mean its "not nil" children
|
||||||
# are initialized:
|
# are initialized:
|
||||||
initVar(a, n)
|
initVar(a, n, volatileCheck=true)
|
||||||
|
elif isLocalVar(a, s):
|
||||||
|
makeVolatile(a, s)
|
||||||
|
|
||||||
when trackGlobals:
|
proc warnAboutGcUnsafe(n: PNode) =
|
||||||
proc addUse(a: PEffects, e: PNode) =
|
#assert false
|
||||||
var aa = a.uses
|
message(n.info, warnGcUnsafe, renderTree(n))
|
||||||
for i in 0 .. <aa.len:
|
|
||||||
if aa[i].sym.id == e.sym.id: return
|
|
||||||
a.uses.add(e)
|
|
||||||
|
|
||||||
proc useVar(a: PEffects, n: PNode) =
|
proc useVar(a: PEffects, n: PNode) =
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
|
|
@ -110,12 +204,11 @@ proc useVar(a: PEffects, n: PNode) =
|
||||||
message(n.info, warnUninit, s.name.s)
|
message(n.info, warnUninit, s.name.s)
|
||||||
# prevent superfluous warnings about the same variable:
|
# prevent superfluous warnings about the same variable:
|
||||||
a.init.add s.id
|
a.init.add s.id
|
||||||
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind == skVar:
|
if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}:
|
||||||
when trackGlobals:
|
if s.guard != nil: guardGlobal(a, n, s.guard)
|
||||||
a.addUse(copyNode(n))
|
|
||||||
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
|
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
|
||||||
tfGcSafe notin s.typ.flags:
|
tfGcSafe notin s.typ.flags:
|
||||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
a.gcUnsafe = true
|
a.gcUnsafe = true
|
||||||
|
|
||||||
type
|
type
|
||||||
|
|
@ -130,20 +223,27 @@ proc addToIntersection(inter: var TIntersection, s: int) =
|
||||||
|
|
||||||
proc throws(tracked, n: PNode) =
|
proc throws(tracked, n: PNode) =
|
||||||
if n.typ == nil or n.typ.kind != tyError: tracked.add n
|
if n.typ == nil or n.typ.kind != tyError: tracked.add n
|
||||||
|
|
||||||
|
proc getEbase(): PType =
|
||||||
|
result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception"
|
||||||
|
else: sysTypeFromName"E_Base"
|
||||||
|
|
||||||
proc excType(n: PNode): PType =
|
proc excType(n: PNode): PType =
|
||||||
# reraise is like raising E_Base:
|
# reraise is like raising E_Base:
|
||||||
let t = if n.kind == nkEmpty: sysTypeFromName"E_Base" else: n.typ
|
let t = if n.kind == nkEmpty: getEbase() else: n.typ
|
||||||
result = skipTypes(t, skipPtrs)
|
result = skipTypes(t, skipPtrs)
|
||||||
|
|
||||||
proc createRaise(n: PNode): PNode =
|
proc createRaise(n: PNode): PNode =
|
||||||
result = newNode(nkType)
|
result = newNode(nkType)
|
||||||
result.typ = sysTypeFromName"E_Base"
|
result.typ = getEbase()
|
||||||
if not n.isNil: result.info = n.info
|
if not n.isNil: result.info = n.info
|
||||||
|
|
||||||
proc createTag(n: PNode): PNode =
|
proc createTag(n: PNode): PNode =
|
||||||
result = newNode(nkType)
|
result = newNode(nkType)
|
||||||
result.typ = sysTypeFromName"TEffect"
|
if getCompilerProc("RootEffect") != nil:
|
||||||
|
result.typ = sysTypeFromName"RootEffect"
|
||||||
|
else:
|
||||||
|
result.typ = sysTypeFromName"TEffect"
|
||||||
if not n.isNil: result.info = n.info
|
if not n.isNil: result.info = n.info
|
||||||
|
|
||||||
proc createAnyGlobal(n: PNode): PNode =
|
proc createAnyGlobal(n: PNode): PNode =
|
||||||
|
|
@ -179,17 +279,11 @@ proc mergeTags(a: PEffects, b, comesFrom: PNode) =
|
||||||
else:
|
else:
|
||||||
for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
|
for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
|
||||||
|
|
||||||
when trackGlobals:
|
|
||||||
proc mergeUses(a: PEffects, b, comesFrom: PNode) =
|
|
||||||
if b.isNil:
|
|
||||||
addUse(a, createAnyGlobal(comesFrom))
|
|
||||||
else:
|
|
||||||
for effect in items(b): addUse(a, effect)
|
|
||||||
|
|
||||||
proc listEffects(a: PEffects) =
|
proc listEffects(a: PEffects) =
|
||||||
for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ))
|
for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ))
|
||||||
for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
|
for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
|
||||||
for e in items(a.uses): message(e.info, hintUser, e.sym.name.s)
|
#if a.maxLockLevel != 0:
|
||||||
|
# message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
|
||||||
|
|
||||||
proc catches(tracked: PEffects, e: PType) =
|
proc catches(tracked: PEffects, e: PType) =
|
||||||
let e = skipTypes(e, skipPtrs)
|
let e = skipTypes(e, skipPtrs)
|
||||||
|
|
@ -219,7 +313,9 @@ proc trackTryStmt(tracked: PEffects, n: PNode) =
|
||||||
let oldState = tracked.init.len
|
let oldState = tracked.init.len
|
||||||
var inter: TIntersection = @[]
|
var inter: TIntersection = @[]
|
||||||
|
|
||||||
track(tracked, n.sons[0])
|
inc tracked.inTryStmt
|
||||||
|
track(tracked, n.sons[0])
|
||||||
|
dec tracked.inTryStmt
|
||||||
for i in oldState.. <tracked.init.len:
|
for i in oldState.. <tracked.init.len:
|
||||||
addToIntersection(inter, tracked.init[i])
|
addToIntersection(inter, tracked.init[i])
|
||||||
|
|
||||||
|
|
@ -274,7 +370,7 @@ proc trackPragmaStmt(tracked: PEffects, n: PNode) =
|
||||||
# list the computed effects up to here:
|
# list the computed effects up to here:
|
||||||
listEffects(tracked)
|
listEffects(tracked)
|
||||||
|
|
||||||
proc effectSpec(n: PNode, effectType = wRaises): PNode =
|
proc effectSpec(n: PNode, effectType: TSpecialWord): PNode =
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
if it.kind == nkExprColonExpr and whichPragma(it) == effectType:
|
if it.kind == nkExprColonExpr and whichPragma(it) == effectType:
|
||||||
|
|
@ -284,8 +380,7 @@ proc effectSpec(n: PNode, effectType = wRaises): PNode =
|
||||||
result.add(it.sons[1])
|
result.add(it.sons[1])
|
||||||
return
|
return
|
||||||
|
|
||||||
proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) =
|
proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int): PNode =
|
||||||
var x = x
|
|
||||||
let spec = effectSpec(x, effectType)
|
let spec = effectSpec(x, effectType)
|
||||||
if isNil(spec):
|
if isNil(spec):
|
||||||
let s = n.sons[namePos].sym
|
let s = n.sons[namePos].sym
|
||||||
|
|
@ -303,18 +398,20 @@ proc documentEffect(n, x: PNode, effectType: TSpecialWord, idx: int) =
|
||||||
# set the type so that the following analysis doesn't screw up:
|
# set the type so that the following analysis doesn't screw up:
|
||||||
effects.sons[i].typ = real[i].typ
|
effects.sons[i].typ = real[i].typ
|
||||||
|
|
||||||
var pair = newNode(nkExprColonExpr, n.info, @[
|
result = newNode(nkExprColonExpr, n.info, @[
|
||||||
newIdentNode(getIdent(specialWords[effectType]), n.info), effects])
|
newIdentNode(getIdent(specialWords[effectType]), n.info), effects])
|
||||||
|
|
||||||
if x.kind == nkEmpty:
|
|
||||||
x = newNodeI(nkPragma, n.info)
|
|
||||||
n.sons[pragmasPos] = x
|
|
||||||
x.add(pair)
|
|
||||||
|
|
||||||
proc documentRaises*(n: PNode) =
|
proc documentRaises*(n: PNode) =
|
||||||
if n.sons[namePos].kind != nkSym: return
|
if n.sons[namePos].kind != nkSym: return
|
||||||
documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects)
|
let pragmas = n.sons[pragmasPos]
|
||||||
documentEffect(n, n.sons[pragmasPos], wTags, tagEffects)
|
let p1 = documentEffect(n, pragmas, wRaises, exceptionEffects)
|
||||||
|
let p2 = documentEffect(n, pragmas, wTags, tagEffects)
|
||||||
|
|
||||||
|
if p1 != nil or p2 != nil:
|
||||||
|
if pragmas.kind == nkEmpty:
|
||||||
|
n.sons[pragmasPos] = newNodeI(nkPragma, n.info)
|
||||||
|
if p1 != nil: n.sons[pragmasPos].add p1
|
||||||
|
if p2 != nil: n.sons[pragmasPos].add p2
|
||||||
|
|
||||||
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {}
|
||||||
|
|
||||||
|
|
@ -322,6 +419,25 @@ proc importedFromC(n: PNode): bool =
|
||||||
# when imported from C, we assume GC-safety.
|
# when imported from C, we assume GC-safety.
|
||||||
result = n.kind == nkSym and sfImportc in n.sym.flags
|
result = n.kind == nkSym and sfImportc in n.sym.flags
|
||||||
|
|
||||||
|
proc getLockLevel(s: PSym): TLockLevel =
|
||||||
|
result = s.typ.lockLevel
|
||||||
|
if result == UnspecifiedLockLevel:
|
||||||
|
if {sfImportc, sfNoSideEffect} * s.flags != {} or
|
||||||
|
tfNoSideEffect in s.typ.flags:
|
||||||
|
result = 0.TLockLevel
|
||||||
|
else:
|
||||||
|
result = UnknownLockLevel
|
||||||
|
#message(s.info, warnUser, "FOR THIS " & s.name.s)
|
||||||
|
|
||||||
|
proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
|
||||||
|
if lockLevel >= tracked.currLockLevel:
|
||||||
|
# if in lock section:
|
||||||
|
if tracked.currLockLevel > 0.TLockLevel:
|
||||||
|
localError n.info, errGenerated,
|
||||||
|
"expected lock level < " & $tracked.currLockLevel &
|
||||||
|
" but got lock level " & $lockLevel
|
||||||
|
tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
|
||||||
|
|
||||||
proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||||
let pragma = s.ast.sons[pragmasPos]
|
let pragma = s.ast.sons[pragmasPos]
|
||||||
let spec = effectSpec(pragma, wRaises)
|
let spec = effectSpec(pragma, wRaises)
|
||||||
|
|
@ -331,8 +447,9 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||||
mergeTags(tracked, tagSpec, n)
|
mergeTags(tracked, tagSpec, n)
|
||||||
|
|
||||||
if notGcSafe(s.typ) and sfImportc notin s.flags:
|
if notGcSafe(s.typ) and sfImportc notin s.flags:
|
||||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
tracked.gcUnsafe = true
|
tracked.gcUnsafe = true
|
||||||
|
mergeLockLevels(tracked, n, s.getLockLevel)
|
||||||
|
|
||||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
let n = n.skipConv
|
let n = n.skipConv
|
||||||
|
|
@ -352,8 +469,22 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
|
message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
|
||||||
of impYes: discard
|
of impYes: discard
|
||||||
|
|
||||||
|
proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
|
||||||
|
addEffect(tracked, createRaise(n))
|
||||||
|
addTag(tracked, createTag(n))
|
||||||
|
let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
|
||||||
|
else: op.lockLevel
|
||||||
|
#if lockLevel == UnknownLockLevel:
|
||||||
|
# message(n.info, warnUser, "had to assume the worst here")
|
||||||
|
mergeLockLevels(tracked, n, lockLevel)
|
||||||
|
|
||||||
|
proc isOwnedProcVar(n: PNode; owner: PSym): bool =
|
||||||
|
# XXX prove the soundness of this effect system rule
|
||||||
|
result = n.kind == nkSym and n.sym.kind == skParam and owner == n.sym.owner
|
||||||
|
|
||||||
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
let op = skipConvAndClosure(n).typ
|
let a = skipConvAndClosure(n)
|
||||||
|
let op = a.typ
|
||||||
if op != nil and op.kind == tyProc and n.kind != nkNilLit:
|
if op != nil and op.kind == tyProc and n.kind != nkNilLit:
|
||||||
internalAssert op.n.sons[0].kind == nkEffectList
|
internalAssert op.n.sons[0].kind == nkEffectList
|
||||||
var effectList = op.n.sons[0]
|
var effectList = op.n.sons[0]
|
||||||
|
|
@ -365,21 +496,18 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||||
# we have no explicit effects but it's a forward declaration and so it's
|
# we have no explicit effects but it's a forward declaration and so it's
|
||||||
# stated there are no additional effects, so simply propagate them:
|
# stated there are no additional effects, so simply propagate them:
|
||||||
propagateEffects(tracked, n, n.sym)
|
propagateEffects(tracked, n, n.sym)
|
||||||
else:
|
elif not isOwnedProcVar(a, tracked.owner):
|
||||||
# we have no explicit effects so assume the worst:
|
# we have no explicit effects so assume the worst:
|
||||||
addEffect(tracked, createRaise(n))
|
assumeTheWorst(tracked, n, op)
|
||||||
addTag(tracked, createTag(n))
|
|
||||||
when trackGlobals: addUse(tracked, createAnyGlobal(n))
|
|
||||||
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
||||||
if notGcSafe(op):
|
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
|
||||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
tracked.gcUnsafe = true
|
tracked.gcUnsafe = true
|
||||||
else:
|
else:
|
||||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||||
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
|
|
||||||
if notGcSafe(op):
|
if notGcSafe(op):
|
||||||
if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n))
|
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||||
tracked.gcUnsafe = true
|
tracked.gcUnsafe = true
|
||||||
notNilCheck(tracked, n, paramType)
|
notNilCheck(tracked, n, paramType)
|
||||||
|
|
||||||
|
|
@ -494,7 +622,8 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
useVar(tracked, n)
|
useVar(tracked, n)
|
||||||
of nkRaiseStmt:
|
of nkRaiseStmt:
|
||||||
n.sons[0].info = n.info
|
n.sons[0].info = n.info
|
||||||
throws(tracked.exc, n.sons[0])
|
#throws(tracked.exc, n.sons[0])
|
||||||
|
addEffect(tracked, n.sons[0], useLineInfo=false)
|
||||||
for i in 0 .. <safeLen(n):
|
for i in 0 .. <safeLen(n):
|
||||||
track(tracked, n.sons[i])
|
track(tracked, n.sons[i])
|
||||||
of nkCallKinds:
|
of nkCallKinds:
|
||||||
|
|
@ -506,8 +635,12 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
# are indistinguishable from normal procs (both have tyProc type) and
|
# are indistinguishable from normal procs (both have tyProc type) and
|
||||||
# we can detect them only by checking for attached nkEffectList.
|
# we can detect them only by checking for attached nkEffectList.
|
||||||
if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
|
if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList:
|
||||||
if a.kind == nkSym and a.sym == tracked.owner:
|
if a.kind == nkSym:
|
||||||
tracked.isRecursive = true
|
if a.sym == tracked.owner: tracked.isRecursive = true
|
||||||
|
# even for recursive calls we need to check the lock levels (!):
|
||||||
|
mergeLockLevels(tracked, n, a.sym.getLockLevel)
|
||||||
|
else:
|
||||||
|
mergeLockLevels(tracked, n, op.lockLevel)
|
||||||
var effectList = op.n.sons[0]
|
var effectList = op.n.sons[0]
|
||||||
if a.kind == nkSym and a.sym.kind == skMethod:
|
if a.kind == nkSym and a.sym.kind == skMethod:
|
||||||
propagateEffects(tracked, n, a.sym)
|
propagateEffects(tracked, n, a.sym)
|
||||||
|
|
@ -515,18 +648,14 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
if isForwardedProc(a):
|
if isForwardedProc(a):
|
||||||
propagateEffects(tracked, n, a.sym)
|
propagateEffects(tracked, n, a.sym)
|
||||||
elif isIndirectCall(a, tracked.owner):
|
elif isIndirectCall(a, tracked.owner):
|
||||||
addEffect(tracked, createRaise(n))
|
assumeTheWorst(tracked, n, op)
|
||||||
addTag(tracked, createTag(n))
|
|
||||||
when trackGlobals: addUse(tracked, createAnyGlobal(n))
|
|
||||||
# XXX handle 'gcsafe' properly for callbacks!
|
|
||||||
else:
|
else:
|
||||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||||
when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n)
|
|
||||||
if notGcSafe(op) and not importedFromC(a):
|
if notGcSafe(op) and not importedFromC(a):
|
||||||
# and it's not a recursive call:
|
# and it's not a recursive call:
|
||||||
if not (a.kind == nkSym and a.sym == tracked.owner):
|
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||||
message(n.info, warnGcUnsafe, renderTree(n))
|
warnAboutGcUnsafe(n)
|
||||||
tracked.gcUnsafe = true
|
tracked.gcUnsafe = true
|
||||||
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
|
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
|
||||||
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
|
||||||
|
|
@ -534,6 +663,9 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
initVarViaNew(tracked, n.sons[1])
|
initVarViaNew(tracked, n.sons[1])
|
||||||
for i in 0 .. <safeLen(n):
|
for i in 0 .. <safeLen(n):
|
||||||
track(tracked, n.sons[i])
|
track(tracked, n.sons[i])
|
||||||
|
of nkDotExpr:
|
||||||
|
guardDotAccess(tracked, n)
|
||||||
|
for i in 0 .. <len(n): track(tracked, n.sons[i])
|
||||||
of nkCheckedFieldExpr:
|
of nkCheckedFieldExpr:
|
||||||
track(tracked, n.sons[0])
|
track(tracked, n.sons[0])
|
||||||
if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
|
if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
|
||||||
|
|
@ -541,19 +673,19 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
of nkPragma: trackPragmaStmt(tracked, n)
|
of nkPragma: trackPragmaStmt(tracked, n)
|
||||||
of nkAsgn, nkFastAsgn:
|
of nkAsgn, nkFastAsgn:
|
||||||
track(tracked, n.sons[1])
|
track(tracked, n.sons[1])
|
||||||
initVar(tracked, n.sons[0])
|
initVar(tracked, n.sons[0], volatileCheck=true)
|
||||||
invalidateFacts(tracked.guards, n.sons[0])
|
invalidateFacts(tracked.guards, n.sons[0])
|
||||||
track(tracked, n.sons[0])
|
track(tracked, n.sons[0])
|
||||||
addAsgnFact(tracked.guards, n.sons[0], n.sons[1])
|
addAsgnFact(tracked.guards, n.sons[0], n.sons[1])
|
||||||
notNilCheck(tracked, n.sons[1], n.sons[0].typ)
|
notNilCheck(tracked, n.sons[1], n.sons[0].typ)
|
||||||
when false: cstringCheck(tracked, n)
|
when false: cstringCheck(tracked, n)
|
||||||
of nkVarSection:
|
of nkVarSection, nkLetSection:
|
||||||
for child in n:
|
for child in n:
|
||||||
let last = lastSon(child)
|
let last = lastSon(child)
|
||||||
if child.kind == nkIdentDefs and last.kind != nkEmpty:
|
if child.kind == nkIdentDefs and last.kind != nkEmpty:
|
||||||
track(tracked, last)
|
track(tracked, last)
|
||||||
for i in 0 .. child.len-3:
|
for i in 0 .. child.len-3:
|
||||||
initVar(tracked, child.sons[i])
|
initVar(tracked, child.sons[i], volatileCheck=false)
|
||||||
addAsgnFact(tracked.guards, child.sons[i], last)
|
addAsgnFact(tracked.guards, child.sons[i], last)
|
||||||
notNilCheck(tracked, last, child.sons[i].typ)
|
notNilCheck(tracked, last, child.sons[i].typ)
|
||||||
# since 'var (a, b): T = ()' is not even allowed, there is always type
|
# since 'var (a, b): T = ()' is not even allowed, there is always type
|
||||||
|
|
@ -589,6 +721,16 @@ proc track(tracked: PEffects, n: PNode) =
|
||||||
if sfDiscriminant in x.sons[0].sym.flags:
|
if sfDiscriminant in x.sons[0].sym.flags:
|
||||||
addDiscriminantFact(tracked.guards, x)
|
addDiscriminantFact(tracked.guards, x)
|
||||||
setLen(tracked.guards, oldFacts)
|
setLen(tracked.guards, oldFacts)
|
||||||
|
of nkPragmaBlock:
|
||||||
|
let pragmaList = n.sons[0]
|
||||||
|
let oldLocked = tracked.locked.len
|
||||||
|
let oldLockLevel = tracked.currLockLevel
|
||||||
|
for i in 0 .. <pragmaList.len:
|
||||||
|
if whichPragma(pragmaList.sons[i]) == wLocks:
|
||||||
|
lockLocations(tracked, pragmaList.sons[i])
|
||||||
|
track(tracked, n.lastSon)
|
||||||
|
setLen(tracked.locked, oldLocked)
|
||||||
|
tracked.currLockLevel = oldLockLevel
|
||||||
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
|
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
|
||||||
nkMacroDef, nkTemplateDef:
|
nkMacroDef, nkTemplateDef:
|
||||||
discard
|
discard
|
||||||
|
|
@ -639,6 +781,16 @@ proc checkMethodEffects*(disp, branch: PSym) =
|
||||||
if sfThread in disp.flags and notGcSafe(branch.typ):
|
if sfThread in disp.flags and notGcSafe(branch.typ):
|
||||||
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
||||||
branch.name.s)
|
branch.name.s)
|
||||||
|
if branch.typ.lockLevel > disp.typ.lockLevel:
|
||||||
|
when true:
|
||||||
|
message(branch.info, warnLockLevel,
|
||||||
|
"base method has lock level $1, but dispatcher has $2" %
|
||||||
|
[$branch.typ.lockLevel, $disp.typ.lockLevel])
|
||||||
|
else:
|
||||||
|
# XXX make this an error after bigbreak has been released:
|
||||||
|
localError(branch.info,
|
||||||
|
"base method has lock level $1, but dispatcher has $2" %
|
||||||
|
[$branch.typ.lockLevel, $disp.typ.lockLevel])
|
||||||
|
|
||||||
proc setEffectsForProcType*(t: PType, n: PNode) =
|
proc setEffectsForProcType*(t: PType, n: PNode) =
|
||||||
var effects = t.n.sons[0]
|
var effects = t.n.sons[0]
|
||||||
|
|
@ -659,14 +811,13 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
||||||
newSeq(effects.sons, effectListLen)
|
newSeq(effects.sons, effectListLen)
|
||||||
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
|
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
|
||||||
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
|
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
|
||||||
effects.sons[usesEffects] = newNodeI(nkArgList, s.info)
|
|
||||||
|
|
||||||
t.exc = effects.sons[exceptionEffects]
|
t.exc = effects.sons[exceptionEffects]
|
||||||
t.tags = effects.sons[tagEffects]
|
t.tags = effects.sons[tagEffects]
|
||||||
t.uses = effects.sons[usesEffects]
|
|
||||||
t.owner = s
|
t.owner = s
|
||||||
t.init = @[]
|
t.init = @[]
|
||||||
t.guards = @[]
|
t.guards = @[]
|
||||||
|
t.locked = @[]
|
||||||
|
|
||||||
proc trackProc*(s: PSym, body: PNode) =
|
proc trackProc*(s: PSym, body: PNode) =
|
||||||
var effects = s.typ.n.sons[0]
|
var effects = s.typ.n.sons[0]
|
||||||
|
|
@ -700,9 +851,17 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||||
|
|
||||||
if optThreadAnalysis in gGlobalOptions:
|
if optThreadAnalysis in gGlobalOptions:
|
||||||
if sfThread in s.flags and t.gcUnsafe:
|
if sfThread in s.flags and t.gcUnsafe:
|
||||||
#localError(s.info, warnGcUnsafe2, s.name.s)
|
if optThreads in gGlobalOptions:
|
||||||
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||||
|
else:
|
||||||
|
localError(s.info, warnGcUnsafe2, s.name.s)
|
||||||
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
|
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
|
||||||
|
if s.typ.lockLevel == UnspecifiedLockLevel:
|
||||||
|
s.typ.lockLevel = t.maxLockLevel
|
||||||
|
elif t.maxLockLevel > s.typ.lockLevel:
|
||||||
|
localError(s.info,
|
||||||
|
"declared lock level is $1, but real lock level is $2" %
|
||||||
|
[$s.typ.lockLevel, $t.maxLockLevel])
|
||||||
|
|
||||||
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||||
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
|
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
|
||||||
|
|
@ -711,5 +870,5 @@ proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||||
var effects = newNode(nkEffectList, n.info)
|
var effects = newNode(nkEffectList, n.info)
|
||||||
var t: TEffects
|
var t: TEffects
|
||||||
initEffects(effects, module, t)
|
initEffects(effects, module, t)
|
||||||
|
t.isToplevel = true
|
||||||
track(t, n)
|
track(t, n)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -29,17 +29,18 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
|
||||||
of nkIdent: s = lookUp(c, n.sons[0])
|
of nkIdent: s = lookUp(c, n.sons[0])
|
||||||
of nkSym: s = n.sons[0].sym
|
of nkSym: s = n.sons[0].sym
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
if s.kind == skLabel and s.owner.id == c.p.owner.id:
|
||||||
var x = newSymNode(s)
|
var x = newSymNode(s)
|
||||||
x.info = n.info
|
x.info = n.info
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
n.sons[0] = x
|
n.sons[0] = x
|
||||||
suggestSym(x.info, s)
|
suggestSym(x.info, s)
|
||||||
|
styleCheckUse(x.info, s)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errInvalidControlFlowX, s.name.s)
|
localError(n.info, errInvalidControlFlowX, s.name.s)
|
||||||
else:
|
else:
|
||||||
localError(n.info, errGenerated, "'continue' cannot have a label")
|
localError(n.info, errGenerated, "'continue' cannot have a label")
|
||||||
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0):
|
||||||
localError(n.info, errInvalidControlFlowX,
|
localError(n.info, errInvalidControlFlowX,
|
||||||
renderTree(n, {renderNoComments}))
|
renderTree(n, {renderNoComments}))
|
||||||
|
|
||||||
|
|
@ -198,11 +199,12 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
var covered: BiggestInt = 0
|
var covered: BiggestInt = 0
|
||||||
var typ = commonTypeBegin
|
var typ = commonTypeBegin
|
||||||
var hasElse = false
|
var hasElse = false
|
||||||
|
var notOrdinal = false
|
||||||
case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
|
case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind
|
||||||
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
|
of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool:
|
||||||
chckCovered = true
|
chckCovered = true
|
||||||
of tyFloat..tyFloat128, tyString, tyError:
|
of tyFloat..tyFloat128, tyString, tyError:
|
||||||
discard
|
notOrdinal = true
|
||||||
else:
|
else:
|
||||||
localError(n.info, errSelectorMustBeOfCertainTypes)
|
localError(n.info, errSelectorMustBeOfCertainTypes)
|
||||||
return
|
return
|
||||||
|
|
@ -232,6 +234,9 @@ proc semCase(c: PContext, n: PNode): PNode =
|
||||||
hasElse = true
|
hasElse = true
|
||||||
else:
|
else:
|
||||||
illFormedAst(x)
|
illFormedAst(x)
|
||||||
|
if notOrdinal and not hasElse:
|
||||||
|
message(n.info, warnDeprecated,
|
||||||
|
"use 'else: discard'; non-ordinal case without 'else'")
|
||||||
if chckCovered:
|
if chckCovered:
|
||||||
if covered == toCover(n.sons[0].typ):
|
if covered == toCover(n.sons[0].typ):
|
||||||
hasElse = true
|
hasElse = true
|
||||||
|
|
@ -258,12 +263,13 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
n.sons[0] = semExprBranchScope(c, n.sons[0])
|
n.sons[0] = semExprBranchScope(c, n.sons[0])
|
||||||
typ = commonType(typ, n.sons[0].typ)
|
typ = commonType(typ, n.sons[0].typ)
|
||||||
var check = initIntSet()
|
var check = initIntSet()
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
var last = sonsLen(n) - 1
|
||||||
|
for i in countup(1, last):
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
checkMinSonsLen(a, 1)
|
checkMinSonsLen(a, 1)
|
||||||
var length = sonsLen(a)
|
var length = sonsLen(a)
|
||||||
if a.kind == nkExceptBranch:
|
if a.kind == nkExceptBranch:
|
||||||
# XXX what does this do? so that ``except [a, b, c]`` is supported?
|
# so that ``except [a, b, c]`` is supported:
|
||||||
if length == 2 and a.sons[0].kind == nkBracket:
|
if length == 2 and a.sons[0].kind == nkBracket:
|
||||||
a.sons[0..0] = a.sons[0].sons
|
a.sons[0..0] = a.sons[0].sons
|
||||||
length = a.sonsLen
|
length = a.sonsLen
|
||||||
|
|
@ -277,11 +283,12 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
a.sons[j].typ = typ
|
a.sons[j].typ = typ
|
||||||
if containsOrIncl(check, typ.id):
|
if containsOrIncl(check, typ.id):
|
||||||
localError(a.sons[j].info, errExceptionAlreadyHandled)
|
localError(a.sons[j].info, errExceptionAlreadyHandled)
|
||||||
elif a.kind != nkFinally:
|
elif a.kind != nkFinally:
|
||||||
illFormedAst(n)
|
illFormedAst(n)
|
||||||
# last child of an nkExcept/nkFinally branch is a statement:
|
# last child of an nkExcept/nkFinally branch is a statement:
|
||||||
a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
|
a.sons[length-1] = semExprBranchScope(c, a.sons[length-1])
|
||||||
typ = commonType(typ, a.sons[length-1].typ)
|
if a.kind != nkFinally: typ = commonType(typ, a.sons[length-1].typ)
|
||||||
|
else: dec last
|
||||||
dec c.p.inTryStmt
|
dec c.p.inTryStmt
|
||||||
if isEmptyType(typ) or typ.kind == tyNil:
|
if isEmptyType(typ) or typ.kind == tyNil:
|
||||||
discardCheck(c, n.sons[0])
|
discardCheck(c, n.sons[0])
|
||||||
|
|
@ -289,13 +296,14 @@ proc semTry(c: PContext, n: PNode): PNode =
|
||||||
if typ == enforceVoidContext:
|
if typ == enforceVoidContext:
|
||||||
result.typ = enforceVoidContext
|
result.typ = enforceVoidContext
|
||||||
else:
|
else:
|
||||||
|
if n.lastSon.kind == nkFinally: discardCheck(c, n.lastSon.lastSon)
|
||||||
n.sons[0] = fitNode(c, typ, n.sons[0])
|
n.sons[0] = fitNode(c, typ, n.sons[0])
|
||||||
for i in 1..n.len-1:
|
for i in 1..last:
|
||||||
var it = n.sons[i]
|
var it = n.sons[i]
|
||||||
let j = it.len-1
|
let j = it.len-1
|
||||||
it.sons[j] = fitNode(c, typ, it.sons[j])
|
it.sons[j] = fitNode(c, typ, it.sons[j])
|
||||||
result.typ = typ
|
result.typ = typ
|
||||||
|
|
||||||
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode =
|
||||||
result = fitNode(c, typ, n)
|
result = fitNode(c, typ, n)
|
||||||
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
if result.kind in {nkHiddenStdConv, nkHiddenSubConv}:
|
||||||
|
|
@ -323,6 +331,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
|
||||||
else:
|
else:
|
||||||
result = semIdentWithPragma(c, kind, n, {})
|
result = semIdentWithPragma(c, kind, n, {})
|
||||||
suggestSym(n.info, result)
|
suggestSym(n.info, result)
|
||||||
|
styleCheckDef(result)
|
||||||
|
|
||||||
proc checkNilable(v: PSym) =
|
proc checkNilable(v: PSym) =
|
||||||
if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}:
|
if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}:
|
||||||
|
|
@ -350,9 +359,15 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||||
var def: PNode
|
var def: PNode
|
||||||
if a.sons[length-1].kind != nkEmpty:
|
if a.sons[length-1].kind != nkEmpty:
|
||||||
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
|
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
|
||||||
# BUGFIX: ``fitNode`` is needed here!
|
if typ != nil:
|
||||||
# check type compability between def.typ and typ:
|
if typ.isMetaType:
|
||||||
if typ != nil: def = fitNode(c, typ, def)
|
def = inferWithMetatype(c, typ, def)
|
||||||
|
typ = def.typ
|
||||||
|
else:
|
||||||
|
# BUGFIX: ``fitNode`` is needed here!
|
||||||
|
# check type compability between def.typ and typ
|
||||||
|
def = fitNode(c, typ, def)
|
||||||
|
#changeType(def.skipConv, typ, check=true)
|
||||||
else:
|
else:
|
||||||
typ = skipIntLit(def.typ)
|
typ = skipIntLit(def.typ)
|
||||||
if typ.kind in {tySequence, tyArray, tySet} and
|
if typ.kind in {tySequence, tyArray, tySet} and
|
||||||
|
|
@ -441,7 +456,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
if typ == nil:
|
if typ == nil:
|
||||||
localError(a.sons[2].info, errConstExprExpected)
|
localError(a.sons[2].info, errConstExprExpected)
|
||||||
continue
|
continue
|
||||||
if not typeAllowed(typ, skConst):
|
if not typeAllowed(typ, skConst) and def.kind != nkNilLit:
|
||||||
localError(a.info, errXisNoType, typeToString(typ))
|
localError(a.info, errXisNoType, typeToString(typ))
|
||||||
continue
|
continue
|
||||||
v.typ = typ
|
v.typ = typ
|
||||||
|
|
@ -454,153 +469,7 @@ proc semConst(c: PContext, n: PNode): PNode =
|
||||||
addSon(b, copyTree(def))
|
addSon(b, copyTree(def))
|
||||||
addSon(result, b)
|
addSon(result, b)
|
||||||
|
|
||||||
type
|
include semfields
|
||||||
TFieldInstCtx = object # either 'tup[i]' or 'field' is valid
|
|
||||||
tupleType: PType # if != nil we're traversing a tuple
|
|
||||||
tupleIndex: int
|
|
||||||
field: PSym
|
|
||||||
replaceByFieldName: bool
|
|
||||||
|
|
||||||
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
|
||||||
case n.kind
|
|
||||||
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
|
|
||||||
of nkIdent:
|
|
||||||
result = n
|
|
||||||
var L = sonsLen(forLoop)
|
|
||||||
if c.replaceByFieldName:
|
|
||||||
if n.ident.id == forLoop[0].ident.id:
|
|
||||||
let fieldName = if c.tupleType.isNil: c.field.name.s
|
|
||||||
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
|
|
||||||
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
|
|
||||||
result = newStrNode(nkStrLit, fieldName)
|
|
||||||
return
|
|
||||||
# other fields:
|
|
||||||
for i in ord(c.replaceByFieldName)..L-3:
|
|
||||||
if n.ident.id == forLoop[i].ident.id:
|
|
||||||
var call = forLoop.sons[L-2]
|
|
||||||
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
|
|
||||||
if c.field.isNil:
|
|
||||||
result = newNodeI(nkBracketExpr, n.info)
|
|
||||||
result.add(tupl)
|
|
||||||
result.add(newIntNode(nkIntLit, c.tupleIndex))
|
|
||||||
else:
|
|
||||||
result = newNodeI(nkDotExpr, n.info)
|
|
||||||
result.add(tupl)
|
|
||||||
result.add(newSymNode(c.field, n.info))
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if n.kind == nkContinueStmt:
|
|
||||||
localError(n.info, errGenerated,
|
|
||||||
"'continue' not supported in a 'fields' loop")
|
|
||||||
result = copyNode(n)
|
|
||||||
newSons(result, sonsLen(n))
|
|
||||||
for i in countup(0, sonsLen(n)-1):
|
|
||||||
result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop)
|
|
||||||
|
|
||||||
type
|
|
||||||
TFieldsCtx = object
|
|
||||||
c: PContext
|
|
||||||
m: TMagic
|
|
||||||
|
|
||||||
proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
|
|
||||||
case typ.kind
|
|
||||||
of nkSym:
|
|
||||||
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid
|
|
||||||
fc.field = typ.sym
|
|
||||||
fc.replaceByFieldName = c.m == mFieldPairs
|
|
||||||
openScope(c.c)
|
|
||||||
inc c.c.inUnrolledContext
|
|
||||||
let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
|
|
||||||
father.add(semStmt(c.c, body))
|
|
||||||
dec c.c.inUnrolledContext
|
|
||||||
closeScope(c.c)
|
|
||||||
of nkNilLit: discard
|
|
||||||
of nkRecCase:
|
|
||||||
let L = forLoop.len
|
|
||||||
let call = forLoop.sons[L-2]
|
|
||||||
if call.len > 2:
|
|
||||||
localError(forLoop.info, errGenerated,
|
|
||||||
"parallel 'fields' iterator does not work for 'case' objects")
|
|
||||||
return
|
|
||||||
# iterate over the selector:
|
|
||||||
semForObjectFields(c, typ[0], forLoop, father)
|
|
||||||
# we need to generate a case statement:
|
|
||||||
var caseStmt = newNodeI(nkCaseStmt, forLoop.info)
|
|
||||||
# generate selector:
|
|
||||||
var access = newNodeI(nkDotExpr, forLoop.info, 2)
|
|
||||||
access.sons[0] = call.sons[1]
|
|
||||||
access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info)
|
|
||||||
caseStmt.add(semExprWithType(c.c, access))
|
|
||||||
# copy the branches over, but replace the fields with the for loop body:
|
|
||||||
for i in 1 .. <typ.len:
|
|
||||||
var branch = copyTree(typ[i])
|
|
||||||
let L = branch.len
|
|
||||||
branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info)
|
|
||||||
semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1])
|
|
||||||
caseStmt.add(branch)
|
|
||||||
father.add(caseStmt)
|
|
||||||
of nkRecList:
|
|
||||||
for t in items(typ): semForObjectFields(c, t, forLoop, father)
|
|
||||||
else:
|
|
||||||
illFormedAst(typ)
|
|
||||||
|
|
||||||
proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
|
||||||
# so that 'break' etc. work as expected, we produce
|
|
||||||
# a 'while true: stmt; break' loop ...
|
|
||||||
result = newNodeI(nkWhileStmt, n.info, 2)
|
|
||||||
var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
|
|
||||||
if trueSymbol == nil:
|
|
||||||
localError(n.info, errSystemNeeds, "true")
|
|
||||||
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info)
|
|
||||||
trueSymbol.typ = getSysType(tyBool)
|
|
||||||
|
|
||||||
result.sons[0] = newSymNode(trueSymbol, n.info)
|
|
||||||
var stmts = newNodeI(nkStmtList, n.info)
|
|
||||||
result.sons[1] = stmts
|
|
||||||
|
|
||||||
var length = sonsLen(n)
|
|
||||||
var call = n.sons[length-2]
|
|
||||||
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
|
|
||||||
localError(n.info, errWrongNumberOfVariables)
|
|
||||||
return result
|
|
||||||
|
|
||||||
var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc})
|
|
||||||
if tupleTypeA.kind notin {tyTuple, tyObject}:
|
|
||||||
localError(n.info, errGenerated, "no object or tuple type")
|
|
||||||
return result
|
|
||||||
for i in 1..call.len-1:
|
|
||||||
var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc})
|
|
||||||
if not sameType(tupleTypeA, tupleTypeB):
|
|
||||||
typeMismatch(call.sons[i], tupleTypeA, tupleTypeB)
|
|
||||||
|
|
||||||
inc(c.p.nestedLoopCounter)
|
|
||||||
if tupleTypeA.kind == tyTuple:
|
|
||||||
var loopBody = n.sons[length-1]
|
|
||||||
for i in 0..sonsLen(tupleTypeA)-1:
|
|
||||||
openScope(c)
|
|
||||||
var fc: TFieldInstCtx
|
|
||||||
fc.tupleType = tupleTypeA
|
|
||||||
fc.tupleIndex = i
|
|
||||||
fc.replaceByFieldName = m == mFieldPairs
|
|
||||||
var body = instFieldLoopBody(fc, loopBody, n)
|
|
||||||
inc c.inUnrolledContext
|
|
||||||
stmts.add(semStmt(c, body))
|
|
||||||
dec c.inUnrolledContext
|
|
||||||
closeScope(c)
|
|
||||||
else:
|
|
||||||
var fc: TFieldsCtx
|
|
||||||
fc.m = m
|
|
||||||
fc.c = c
|
|
||||||
semForObjectFields(fc, tupleTypeA.n, n, stmts)
|
|
||||||
dec(c.p.nestedLoopCounter)
|
|
||||||
# for TR macros this 'while true: ...; break' loop is pretty bad, so
|
|
||||||
# we avoid it now if we can:
|
|
||||||
if hasSonWith(stmts, nkBreakStmt):
|
|
||||||
var b = newNodeI(nkBreakStmt, n.info)
|
|
||||||
b.add(ast.emptyNode)
|
|
||||||
stmts.add(b)
|
|
||||||
else:
|
|
||||||
result = stmts
|
|
||||||
|
|
||||||
proc addForVarDecl(c: PContext, v: PSym) =
|
proc addForVarDecl(c: PContext, v: PSym) =
|
||||||
if warnShadowIdent in gNotes:
|
if warnShadowIdent in gNotes:
|
||||||
|
|
@ -614,6 +483,7 @@ proc addForVarDecl(c: PContext, v: PSym) =
|
||||||
proc symForVar(c: PContext, n: PNode): PSym =
|
proc symForVar(c: PContext, n: PNode): PSym =
|
||||||
let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
|
let m = if n.kind == nkPragmaExpr: n.sons[0] else: n
|
||||||
result = newSymG(skForVar, m, c)
|
result = newSymG(skForVar, m, c)
|
||||||
|
styleCheckDef(result)
|
||||||
|
|
||||||
proc semForVars(c: PContext, n: PNode): PNode =
|
proc semForVars(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -906,7 +776,7 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
|
||||||
if it.kind == nkExprColonExpr:
|
if it.kind == nkExprColonExpr:
|
||||||
# pass pragma argument to the macro too:
|
# pass pragma argument to the macro too:
|
||||||
x.add(it.sons[1])
|
x.add(it.sons[1])
|
||||||
x.add(newProcNode(nkDo, prc.info, prc))
|
x.add(prc)
|
||||||
# recursion assures that this works for multiple macro annotations too:
|
# recursion assures that this works for multiple macro annotations too:
|
||||||
return semStmt(c, x)
|
return semStmt(c, x)
|
||||||
|
|
||||||
|
|
@ -934,6 +804,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
gp = newNodeI(nkGenericParams, n.info)
|
gp = newNodeI(nkGenericParams, n.info)
|
||||||
|
|
||||||
if n.sons[paramsPos].kind != nkEmpty:
|
if n.sons[paramsPos].kind != nkEmpty:
|
||||||
|
#if n.kind == nkDo and not experimentalMode(c):
|
||||||
|
# localError(n.sons[paramsPos].info,
|
||||||
|
# "use the {.experimental.} pragma to enable 'do' with parameters")
|
||||||
semParamList(c, n.sons[paramsPos], gp, s)
|
semParamList(c, n.sons[paramsPos], gp, s)
|
||||||
# paramsTypeCheck(c, s.typ)
|
# paramsTypeCheck(c, s.typ)
|
||||||
if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
|
if sonsLen(gp) > 0 and n.sons[genericParamsPos].kind == nkEmpty:
|
||||||
|
|
@ -1014,14 +887,21 @@ proc maybeAddResult(c: PContext, s: PSym, n: PNode) =
|
||||||
|
|
||||||
proc semOverride(c: PContext, s: PSym, n: PNode) =
|
proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
case s.name.s.normalize
|
case s.name.s.normalize
|
||||||
of "destroy": doDestructorStuff(c, s, n)
|
of "destroy":
|
||||||
|
doDestructorStuff(c, s, n)
|
||||||
|
if not experimentalMode(c):
|
||||||
|
localError n.info, "use the {.experimental.} pragma to enable destructors"
|
||||||
of "deepcopy":
|
of "deepcopy":
|
||||||
if s.typ.len == 2 and
|
if s.typ.len == 2 and
|
||||||
s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
|
s.typ.sons[1].skipTypes(abstractInst).kind in {tyRef, tyPtr} and
|
||||||
sameType(s.typ.sons[1], s.typ.sons[0]):
|
sameType(s.typ.sons[1], s.typ.sons[0]):
|
||||||
# Note: we store the deepCopy in the base of the pointer to mitigate
|
# Note: we store the deepCopy in the base of the pointer to mitigate
|
||||||
# the problem that pointers are structural types:
|
# the problem that pointers are structural types:
|
||||||
let t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
|
var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
|
||||||
|
while true:
|
||||||
|
if t.kind == tyGenericBody: t = t.lastSon
|
||||||
|
elif t.kind == tyGenericInvokation: t = t.sons[0]
|
||||||
|
else: break
|
||||||
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
||||||
if t.deepCopy.isNil: t.deepCopy = s
|
if t.deepCopy.isNil: t.deepCopy = s
|
||||||
else:
|
else:
|
||||||
|
|
@ -1036,6 +916,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||||
of "=": discard
|
of "=": discard
|
||||||
else: localError(n.info, errGenerated,
|
else: localError(n.info, errGenerated,
|
||||||
"'destroy' or 'deepCopy' expected for 'override'")
|
"'destroy' or 'deepCopy' expected for 'override'")
|
||||||
|
incl(s.flags, sfUsed)
|
||||||
|
|
||||||
type
|
type
|
||||||
TProcCompilationSteps = enum
|
TProcCompilationSteps = enum
|
||||||
|
|
@ -1128,7 +1009,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||||
pragma(c, s, n.sons[pragmasPos], validPragmas)
|
pragma(c, s, n.sons[pragmasPos], validPragmas)
|
||||||
else:
|
else:
|
||||||
implicitPragmas(c, s, n, validPragmas)
|
implicitPragmas(c, s, n, validPragmas)
|
||||||
else:
|
else:
|
||||||
if n.sons[pragmasPos].kind != nkEmpty:
|
if n.sons[pragmasPos].kind != nkEmpty:
|
||||||
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
|
localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProc)
|
||||||
if sfForward notin proto.flags:
|
if sfForward notin proto.flags:
|
||||||
|
|
@ -1292,9 +1173,14 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
let pragmaList = n.sons[0]
|
let pragmaList = n.sons[0]
|
||||||
pragma(c, nil, pragmaList, exprPragmas)
|
pragma(c, nil, pragmaList, exprPragmas)
|
||||||
result = semExpr(c, n.sons[1])
|
result = semExpr(c, n.sons[1])
|
||||||
|
n.sons[1] = result
|
||||||
for i in 0 .. <pragmaList.len:
|
for i in 0 .. <pragmaList.len:
|
||||||
if whichPragma(pragmaList.sons[i]) == wLine:
|
case whichPragma(pragmaList.sons[i])
|
||||||
setLine(result, pragmaList.sons[i].info)
|
of wLine: setLine(result, pragmaList.sons[i].info)
|
||||||
|
of wLocks:
|
||||||
|
result = n
|
||||||
|
result.typ = n.sons[1].typ
|
||||||
|
else: discard
|
||||||
|
|
||||||
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
let a = semStmt(c, n.sons[0])
|
let a = semStmt(c, n.sons[0])
|
||||||
|
|
@ -1340,8 +1226,9 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# nkNilLit, nkEmpty}:
|
# nkNilLit, nkEmpty}:
|
||||||
# dec last
|
# dec last
|
||||||
for i in countup(0, length - 1):
|
for i in countup(0, length - 1):
|
||||||
case n.sons[i].kind
|
let k = n.sons[i].kind
|
||||||
of nkFinally, nkExceptBranch:
|
case k
|
||||||
|
of nkFinally, nkExceptBranch, nkDefer:
|
||||||
# stand-alone finally and except blocks are
|
# stand-alone finally and except blocks are
|
||||||
# transformed into regular try blocks:
|
# transformed into regular try blocks:
|
||||||
#
|
#
|
||||||
|
|
@ -1350,14 +1237,27 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
# ... | ...
|
# ... | ...
|
||||||
# | finally:
|
# | finally:
|
||||||
# | fclose(f)
|
# | fclose(f)
|
||||||
|
var deferPart: PNode
|
||||||
|
if k == nkDefer:
|
||||||
|
deferPart = newNodeI(nkFinally, n.sons[i].info)
|
||||||
|
deferPart.add n.sons[i].sons[0]
|
||||||
|
elif k == nkFinally:
|
||||||
|
message(n.info, warnDeprecated,
|
||||||
|
"use 'defer'; standalone 'finally'")
|
||||||
|
deferPart = n.sons[i]
|
||||||
|
else:
|
||||||
|
message(n.info, warnDeprecated,
|
||||||
|
"use an explicit 'try'; standalone 'except'")
|
||||||
|
deferPart = n.sons[i]
|
||||||
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
|
var tryStmt = newNodeI(nkTryStmt, n.sons[i].info)
|
||||||
var body = newNodeI(nkStmtList, n.sons[i].info)
|
var body = newNodeI(nkStmtList, n.sons[i].info)
|
||||||
if i < n.sonsLen - 1:
|
if i < n.sonsLen - 1:
|
||||||
body.sons = n.sons[(i+1)..(-1)]
|
body.sons = n.sons[(i+1)..(-1)]
|
||||||
tryStmt.addSon(body)
|
tryStmt.addSon(body)
|
||||||
tryStmt.addSon(n.sons[i])
|
tryStmt.addSon(deferPart)
|
||||||
n.sons[i] = semTry(c, tryStmt)
|
n.sons[i] = semTry(c, tryStmt)
|
||||||
n.sons.setLen(i+1)
|
n.sons.setLen(i+1)
|
||||||
|
n.typ = n.sons[i].typ
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
n.sons[i] = semExpr(c, n.sons[i])
|
n.sons[i] = semExpr(c, n.sons[i])
|
||||||
|
|
@ -1393,11 +1293,16 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||||
else: discard
|
else: discard
|
||||||
if result.len == 1:
|
if result.len == 1:
|
||||||
result = result.sons[0]
|
result = result.sons[0]
|
||||||
|
when defined(nimfix):
|
||||||
|
if result.kind == nkCommentStmt and not result.comment.isNil and
|
||||||
|
not (result.comment[0] == '#' and result.comment[1] == '#'):
|
||||||
|
# it is an old-style comment statement: we replace it with 'discard ""':
|
||||||
|
prettybase.replaceComment(result.info)
|
||||||
when false:
|
when false:
|
||||||
# a statement list (s; e) has the type 'e':
|
# a statement list (s; e) has the type 'e':
|
||||||
if result.kind == nkStmtList and result.len > 0:
|
if result.kind == nkStmtList and result.len > 0:
|
||||||
var lastStmt = lastSon(result)
|
var lastStmt = lastSon(result)
|
||||||
if lastStmt.kind != nkNilLit and not ImplicitlyDiscardable(lastStmt):
|
if lastStmt.kind != nkNilLit and not implicitlyDiscardable(lastStmt):
|
||||||
result.typ = lastStmt.typ
|
result.typ = lastStmt.typ
|
||||||
#localError(lastStmt.info, errGenerated,
|
#localError(lastStmt.info, errGenerated,
|
||||||
# "Last expression must be explicitly returned if it " &
|
# "Last expression must be explicitly returned if it " &
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -63,7 +63,8 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
||||||
else:
|
else:
|
||||||
# semantic checking requires a type; ``fitNode`` deals with it
|
# semantic checking requires a type; ``fitNode`` deals with it
|
||||||
# appropriately
|
# appropriately
|
||||||
let kind = if r == scClosed: nkClosedSymChoice else: nkOpenSymChoice
|
let kind = if r == scClosed or n.kind == nkDotExpr: nkClosedSymChoice
|
||||||
|
else: nkOpenSymChoice
|
||||||
result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
|
result = newNodeIT(kind, n.info, newTypeS(tyNone, c))
|
||||||
a = initOverloadIter(o, c, n)
|
a = initOverloadIter(o, c, n)
|
||||||
while a != nil:
|
while a != nil:
|
||||||
|
|
@ -71,7 +72,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
|
||||||
addSon(result, newSymNode(a, n.info))
|
addSon(result, newSymNode(a, n.info))
|
||||||
a = nextOverloadIter(o, c, n)
|
a = nextOverloadIter(o, c, n)
|
||||||
|
|
||||||
proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
|
||||||
for i in 0 .. < n.len:
|
for i in 0 .. < n.len:
|
||||||
var a = n.sons[i]
|
var a = n.sons[i]
|
||||||
# If 'a' is an overloaded symbol, we used to use the first symbol
|
# If 'a' is an overloaded symbol, we used to use the first symbol
|
||||||
|
|
@ -91,7 +92,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
|
||||||
illFormedAst(a)
|
illFormedAst(a)
|
||||||
result = newNodeI(nkEmpty, n.info)
|
result = newNodeI(nkEmpty, n.info)
|
||||||
|
|
||||||
proc semMixinStmt(c: PContext, n: PNode, toMixin: var TIntSet): PNode =
|
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
|
||||||
for i in 0 .. < n.len:
|
for i in 0 .. < n.len:
|
||||||
toMixin.incl(considerQuotedIdent(n.sons[i]).id)
|
toMixin.incl(considerQuotedIdent(n.sons[i]).id)
|
||||||
result = newNodeI(nkEmpty, n.info)
|
result = newNodeI(nkEmpty, n.info)
|
||||||
|
|
@ -106,7 +107,7 @@ proc replaceIdentBySym(n: var PNode, s: PNode) =
|
||||||
type
|
type
|
||||||
TemplCtx {.pure, final.} = object
|
TemplCtx {.pure, final.} = object
|
||||||
c: PContext
|
c: PContext
|
||||||
toBind, toMixin, toInject: TIntSet
|
toBind, toMixin, toInject: IntSet
|
||||||
owner: PSym
|
owner: PSym
|
||||||
|
|
||||||
proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
|
proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
|
||||||
|
|
@ -146,6 +147,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
|
||||||
if s.owner == c.owner and s.kind == skParam:
|
if s.owner == c.owner and s.kind == skParam:
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
else:
|
else:
|
||||||
for i in 0 .. <n.safeLen:
|
for i in 0 .. <n.safeLen:
|
||||||
result.sons[i] = onlyReplaceParams(c, n.sons[i])
|
result.sons[i] = onlyReplaceParams(c, n.sons[i])
|
||||||
|
|
@ -183,12 +185,15 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
|
||||||
if not isTemplParam(c, ident):
|
if not isTemplParam(c, ident):
|
||||||
let local = newGenSym(k, ident, c)
|
let local = newGenSym(k, ident, c)
|
||||||
addPrelimDecl(c.c, local)
|
addPrelimDecl(c.c, local)
|
||||||
|
styleCheckDef(n.info, local)
|
||||||
replaceIdentBySym(n, newSymNode(local, n.info))
|
replaceIdentBySym(n, newSymNode(local, n.info))
|
||||||
else:
|
else:
|
||||||
replaceIdentBySym(n, ident)
|
replaceIdentBySym(n, ident)
|
||||||
|
|
||||||
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
|
# we do not call styleCheckUse here, as the identifier is not really
|
||||||
|
# resolved here. We will fixup the used identifiers later.
|
||||||
case s.kind
|
case s.kind
|
||||||
of skUnknown:
|
of skUnknown:
|
||||||
# Introduced in this pass! Leave it as an identifier.
|
# Introduced in this pass! Leave it as an identifier.
|
||||||
|
|
@ -204,7 +209,8 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
|
||||||
result = newSymNodeTypeDesc(s, n.info)
|
result = newSymNodeTypeDesc(s, n.info)
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
else: result = newSymNode(s, n.info)
|
else:
|
||||||
|
result = newSymNode(s, n.info)
|
||||||
|
|
||||||
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
|
|
@ -214,6 +220,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
|
||||||
if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
|
if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags):
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
else:
|
else:
|
||||||
for i in countup(0, safeLen(n) - 1):
|
for i in countup(0, safeLen(n) - 1):
|
||||||
result.sons[i] = semRoutineInTemplName(c, n.sons[i])
|
result.sons[i] = semRoutineInTemplName(c, n.sons[i])
|
||||||
|
|
@ -228,6 +235,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
|
||||||
var s = newGenSym(k, ident, c)
|
var s = newGenSym(k, ident, c)
|
||||||
s.ast = n
|
s.ast = n
|
||||||
addPrelimDecl(c.c, s)
|
addPrelimDecl(c.c, s)
|
||||||
|
styleCheckDef(n.info, s)
|
||||||
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
|
n.sons[namePos] = newSymNode(s, n.sons[namePos].info)
|
||||||
else:
|
else:
|
||||||
n.sons[namePos] = ident
|
n.sons[namePos] = ident
|
||||||
|
|
@ -261,6 +269,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
if s.owner == c.owner and s.kind == skParam:
|
if s.owner == c.owner and s.kind == skParam:
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
elif contains(c.toBind, s.id):
|
elif contains(c.toBind, s.id):
|
||||||
result = symChoice(c.c, n, s, scClosed)
|
result = symChoice(c.c, n, s, scClosed)
|
||||||
elif contains(c.toMixin, s.name.id):
|
elif contains(c.toMixin, s.name.id):
|
||||||
|
|
@ -270,6 +279,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
# var yz: T
|
# var yz: T
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
result = newSymNode(s, n.info)
|
result = newSymNode(s, n.info)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
else:
|
else:
|
||||||
result = semTemplSymbol(c.c, n, s)
|
result = semTemplSymbol(c.c, n, s)
|
||||||
of nkBind:
|
of nkBind:
|
||||||
|
|
@ -322,6 +332,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
# labels are always 'gensym'ed:
|
# labels are always 'gensym'ed:
|
||||||
let s = newGenSym(skLabel, n.sons[0], c)
|
let s = newGenSym(skLabel, n.sons[0], c)
|
||||||
addPrelimDecl(c.c, s)
|
addPrelimDecl(c.c, s)
|
||||||
|
styleCheckDef(s)
|
||||||
n.sons[0] = newSymNode(s, n.sons[0].info)
|
n.sons[0] = newSymNode(s, n.sons[0].info)
|
||||||
n.sons[1] = semTemplBody(c, n.sons[1])
|
n.sons[1] = semTemplBody(c, n.sons[1])
|
||||||
closeScope(c)
|
closeScope(c)
|
||||||
|
|
@ -456,6 +467,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||||
incl(s.flags, sfGlobal)
|
incl(s.flags, sfGlobal)
|
||||||
else:
|
else:
|
||||||
s = semIdentVis(c, skTemplate, n.sons[0], {})
|
s = semIdentVis(c, skTemplate, n.sons[0], {})
|
||||||
|
styleCheckDef(s)
|
||||||
# check parameter list:
|
# check parameter list:
|
||||||
s.scope = c.currentScope
|
s.scope = c.currentScope
|
||||||
pushOwner(s)
|
pushOwner(s)
|
||||||
|
|
@ -527,6 +539,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
|
||||||
# semtypes.addParamOrResult). Within the pattern we have to ensure
|
# semtypes.addParamOrResult). Within the pattern we have to ensure
|
||||||
# to use the param with the proper type though:
|
# to use the param with the proper type though:
|
||||||
incl(s.flags, sfUsed)
|
incl(s.flags, sfUsed)
|
||||||
|
styleCheckUse(n.info, s)
|
||||||
let x = c.owner.typ.n.sons[s.position+1].sym
|
let x = c.owner.typ.n.sons[s.position+1].sym
|
||||||
assert x.name == s.name
|
assert x.name == s.name
|
||||||
result = newSymNode(x, n.info)
|
result = newSymNode(x, n.info)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -82,6 +82,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||||
incl(e.flags, sfExported)
|
incl(e.flags, sfExported)
|
||||||
if not isPure: strTableAdd(c.module.tab, e)
|
if not isPure: strTableAdd(c.module.tab, e)
|
||||||
addSon(result.n, newSymNode(e))
|
addSon(result.n, newSymNode(e))
|
||||||
|
styleCheckDef(e)
|
||||||
if sfGenSym notin e.flags and not isPure: addDecl(c, e)
|
if sfGenSym notin e.flags and not isPure: addDecl(c, e)
|
||||||
inc(counter)
|
inc(counter)
|
||||||
if not hasNull: incl(result.flags, tfNeedsInit)
|
if not hasNull: incl(result.flags, tfNeedsInit)
|
||||||
|
|
@ -92,7 +93,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
|
||||||
var base = semTypeNode(c, n.sons[1], nil)
|
var base = semTypeNode(c, n.sons[1], nil)
|
||||||
addSonSkipIntLit(result, base)
|
addSonSkipIntLit(result, base)
|
||||||
if base.kind == tyGenericInst: base = lastSon(base)
|
if base.kind == tyGenericInst: base = lastSon(base)
|
||||||
if base.kind != tyGenericParam:
|
if base.kind != tyGenericParam:
|
||||||
if not isOrdinalType(base):
|
if not isOrdinalType(base):
|
||||||
localError(n.info, errOrdinalTypeExpected)
|
localError(n.info, errOrdinalTypeExpected)
|
||||||
elif lengthOrd(base) > MaxSetElements:
|
elif lengthOrd(base) > MaxSetElements:
|
||||||
|
|
@ -169,9 +170,10 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||||
range[1] = semExprWithType(c, n[2], {efDetermineType})
|
range[1] = semExprWithType(c, n[2], {efDetermineType})
|
||||||
|
|
||||||
var rangeT: array[2, PType]
|
var rangeT: array[2, PType]
|
||||||
for i in 0..1: rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
|
for i in 0..1:
|
||||||
|
rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
|
||||||
|
|
||||||
if not sameType(rangeT[0], rangeT[1]):
|
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
|
||||||
localError(n.info, errPureTypeMismatch)
|
localError(n.info, errPureTypeMismatch)
|
||||||
elif not rangeT[0].isOrdinalType:
|
elif not rangeT[0].isOrdinalType:
|
||||||
localError(n.info, errOrdinalTypeExpected)
|
localError(n.info, errOrdinalTypeExpected)
|
||||||
|
|
@ -279,9 +281,15 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||||
if n.kind == nkSym:
|
if n.kind == nkSym:
|
||||||
result = n.sym
|
result = n.sym
|
||||||
else:
|
else:
|
||||||
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
when defined(nimfix):
|
||||||
|
result = pickSym(c, n, skType)
|
||||||
|
if result.isNil:
|
||||||
|
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
||||||
|
else:
|
||||||
|
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
|
||||||
if result != nil:
|
if result != nil:
|
||||||
markUsed(n.info, result)
|
markUsed(n.info, result)
|
||||||
|
styleCheckUse(n.info, result)
|
||||||
if result.kind == skParam and result.typ.kind == tyTypeDesc:
|
if result.kind == skParam and result.typ.kind == tyTypeDesc:
|
||||||
# This is a typedesc param. is it already bound?
|
# This is a typedesc param. is it already bound?
|
||||||
# it's not bound when it's used multiple times in the
|
# it's not bound when it's used multiple times in the
|
||||||
|
|
@ -358,7 +366,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||||
else:
|
else:
|
||||||
addSon(result.n, newSymNode(field))
|
addSon(result.n, newSymNode(field))
|
||||||
addSonSkipIntLit(result, typ)
|
addSonSkipIntLit(result, typ)
|
||||||
if gCmd == cmdPretty: checkDef(a.sons[j], field)
|
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
|
||||||
|
|
||||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym =
|
allowed: TSymFlags): PSym =
|
||||||
|
|
@ -378,13 +386,13 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||||
else:
|
else:
|
||||||
result = newSymG(kind, n, c)
|
result = newSymG(kind, n, c)
|
||||||
|
|
||||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
allowed: TSymFlags): PSym =
|
allowed: TSymFlags): PSym =
|
||||||
if n.kind == nkPragmaExpr:
|
if n.kind == nkPragmaExpr:
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
result = semIdentVis(c, kind, n.sons[0], allowed)
|
result = semIdentVis(c, kind, n.sons[0], allowed)
|
||||||
case kind
|
case kind
|
||||||
of skType:
|
of skType:
|
||||||
# process pragmas later, because result.typ has not been set yet
|
# process pragmas later, because result.typ has not been set yet
|
||||||
discard
|
discard
|
||||||
of skField: pragma(c, result, n.sons[1], fieldPragmas)
|
of skField: pragma(c, result, n.sons[1], fieldPragmas)
|
||||||
|
|
@ -394,8 +402,8 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||||
else: discard
|
else: discard
|
||||||
else:
|
else:
|
||||||
result = semIdentVis(c, kind, n, allowed)
|
result = semIdentVis(c, kind, n, allowed)
|
||||||
if gCmd == cmdPretty: checkDef(n, result)
|
if gCmd == cmdPretty: styleCheckDef(n.info, result)
|
||||||
|
|
||||||
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
|
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
|
||||||
let ex = t[branchIndex][currentEx].skipConv
|
let ex = t[branchIndex][currentEx].skipConv
|
||||||
for i in countup(1, branchIndex):
|
for i in countup(1, branchIndex):
|
||||||
|
|
@ -461,9 +469,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||||
swap(branch.sons[L-2], branch.sons[L-1])
|
swap(branch.sons[L-2], branch.sons[L-1])
|
||||||
checkForOverlap(c, t, i, branchIndex)
|
checkForOverlap(c, t, i, branchIndex)
|
||||||
|
|
||||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
father: PNode, rectype: PType)
|
father: PNode, rectype: PType)
|
||||||
proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
father: PNode, rectype: PType) =
|
father: PNode, rectype: PType) =
|
||||||
var a = copyNode(n)
|
var a = copyNode(n)
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
|
|
@ -498,7 +506,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
||||||
localError(a.info, errNotAllCasesCovered)
|
localError(a.info, errNotAllCasesCovered)
|
||||||
addSon(father, a)
|
addSon(father, a)
|
||||||
|
|
||||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||||
father: PNode, rectype: PType) =
|
father: PNode, rectype: PType) =
|
||||||
if n == nil: return
|
if n == nil: return
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -524,7 +532,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
if c.inGenericContext > 0:
|
if c.inGenericContext > 0:
|
||||||
# use a new check intset here for each branch:
|
# use a new check intset here for each branch:
|
||||||
var newCheck: TIntSet
|
var newCheck: IntSet
|
||||||
assign(newCheck, check)
|
assign(newCheck, check)
|
||||||
var newPos = pos
|
var newPos = pos
|
||||||
var newf = newNodeI(nkRecList, n.info)
|
var newf = newNodeI(nkRecList, n.info)
|
||||||
|
|
@ -574,11 +582,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int,
|
||||||
localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
|
localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
|
||||||
if a.kind == nkEmpty: addSon(father, newSymNode(f))
|
if a.kind == nkEmpty: addSon(father, newSymNode(f))
|
||||||
else: addSon(a, newSymNode(f))
|
else: addSon(a, newSymNode(f))
|
||||||
|
styleCheckDef(f)
|
||||||
if a.kind != nkEmpty: addSon(father, a)
|
if a.kind != nkEmpty: addSon(father, a)
|
||||||
of nkEmpty: discard
|
of nkEmpty: discard
|
||||||
else: illFormedAst(n)
|
else: illFormedAst(n)
|
||||||
|
|
||||||
proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int,
|
proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||||
n: PNode) =
|
n: PNode) =
|
||||||
case n.kind
|
case n.kind
|
||||||
of nkRecCase:
|
of nkRecCase:
|
||||||
|
|
@ -597,7 +606,7 @@ proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int,
|
||||||
inc(pos)
|
inc(pos)
|
||||||
else: internalError(n.info, "addInheritedFieldsAux()")
|
else: internalError(n.info, "addInheritedFieldsAux()")
|
||||||
|
|
||||||
proc addInheritedFields(c: PContext, check: var TIntSet, pos: var int,
|
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||||
obj: PType) =
|
obj: PType) =
|
||||||
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
|
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
|
||||||
addInheritedFields(c, check, pos, obj.sons[0])
|
addInheritedFields(c, check, pos, obj.sons[0])
|
||||||
|
|
@ -814,10 +823,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
for i in 1 .. <paramType.sonsLen:
|
for i in 1 .. <paramType.sonsLen:
|
||||||
let lifted = liftingWalk(paramType.sons[i])
|
let lifted = liftingWalk(paramType.sons[i])
|
||||||
if lifted != nil: paramType.sons[i] = lifted
|
if lifted != nil: paramType.sons[i] = lifted
|
||||||
|
when false:
|
||||||
let expanded = instGenericContainer(c, info, paramType,
|
let expanded = instGenericContainer(c, info, paramType,
|
||||||
allowMetaTypes = true)
|
allowMetaTypes = true)
|
||||||
result = liftingWalk(expanded, true)
|
result = liftingWalk(expanded, true)
|
||||||
|
|
||||||
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
||||||
|
|
@ -828,6 +837,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||||
|
|
||||||
of tyGenericParam:
|
of tyGenericParam:
|
||||||
markUsed(info, paramType.sym)
|
markUsed(info, paramType.sym)
|
||||||
|
styleCheckUse(info, paramType.sym)
|
||||||
if tfWildcard in paramType.flags:
|
if tfWildcard in paramType.flags:
|
||||||
paramType.flags.excl tfWildcard
|
paramType.flags.excl tfWildcard
|
||||||
paramType.sym.kind = skType
|
paramType.sym.kind = skType
|
||||||
|
|
@ -844,10 +854,12 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
|
||||||
result = semTypeNode(c, n, nil)
|
result = semTypeNode(c, n, nil)
|
||||||
|
|
||||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
prev: PType, kind: TSymKind): PType =
|
prev: PType, kind: TSymKind; isType=false): PType =
|
||||||
|
# for historical reasons (code grows) this is invoked for parameter
|
||||||
|
# lists too and then 'isType' is false.
|
||||||
var
|
var
|
||||||
res: PNode
|
res: PNode
|
||||||
cl: TIntSet
|
cl: IntSet
|
||||||
checkMinSonsLen(n, 1)
|
checkMinSonsLen(n, 1)
|
||||||
result = newOrPrevType(tyProc, prev, c)
|
result = newOrPrevType(tyProc, prev, c)
|
||||||
result.callConv = lastOptionEntry(c).defaultCC
|
result.callConv = lastOptionEntry(c).defaultCC
|
||||||
|
|
@ -893,7 +905,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
||||||
if not containsGenericType(typ):
|
if not containsGenericType(typ):
|
||||||
def = fitNode(c, typ, def)
|
def = fitNode(c, typ, def)
|
||||||
if not (hasType or hasDefault):
|
if not hasType and not hasDefault:
|
||||||
|
if isType: localError(a.info, "':' expected")
|
||||||
let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
|
let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
|
||||||
typ = newTypeS(tdef, c)
|
typ = newTypeS(tdef, c)
|
||||||
|
|
||||||
|
|
@ -913,29 +926,32 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||||
addSon(result.n, newSymNode(arg))
|
addSon(result.n, newSymNode(arg))
|
||||||
rawAddSon(result, finalType)
|
rawAddSon(result, finalType)
|
||||||
addParamOrResult(c, arg, kind)
|
addParamOrResult(c, arg, kind)
|
||||||
if gCmd == cmdPretty: checkDef(a.sons[j], arg)
|
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, arg)
|
||||||
|
|
||||||
var r: PType
|
var r: PType
|
||||||
if n.sons[0].kind != nkEmpty:
|
if n.sons[0].kind != nkEmpty:
|
||||||
r = semTypeNode(c, n.sons[0], nil)
|
r = semTypeNode(c, n.sons[0], nil)
|
||||||
elif kind == skIterator:
|
elif kind == skIterator:
|
||||||
|
# XXX This is special magic we should likely get rid of
|
||||||
r = newTypeS(tyAnything, c)
|
r = newTypeS(tyAnything, c)
|
||||||
|
|
||||||
if r != nil:
|
if r != nil:
|
||||||
# turn explicit 'void' return type into 'nil' because the rest of the
|
# turn explicit 'void' return type into 'nil' because the rest of the
|
||||||
# compiler only checks for 'nil':
|
# compiler only checks for 'nil':
|
||||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||||
if r.sym == nil or sfAnon notin r.sym.flags:
|
# 'auto' as a return type does not imply a generic:
|
||||||
let lifted = liftParamType(c, kind, genericParams, r, "result",
|
if r.kind != tyExpr:
|
||||||
n.sons[0].info)
|
if r.sym == nil or sfAnon notin r.sym.flags:
|
||||||
if lifted != nil: r = lifted
|
let lifted = liftParamType(c, kind, genericParams, r, "result",
|
||||||
r.flags.incl tfRetType
|
n.sons[0].info)
|
||||||
r = skipIntLit(r)
|
if lifted != nil: r = lifted
|
||||||
if kind == skIterator:
|
r.flags.incl tfRetType
|
||||||
# see tchainediterators
|
r = skipIntLit(r)
|
||||||
# in cases like iterator foo(it: iterator): type(it)
|
if kind == skIterator:
|
||||||
# we don't need to change the return type to iter[T]
|
# see tchainediterators
|
||||||
if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
|
# in cases like iterator foo(it: iterator): type(it)
|
||||||
|
# we don't need to change the return type to iter[T]
|
||||||
|
if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
|
||||||
result.sons[0] = r
|
result.sons[0] = r
|
||||||
res.typ = r
|
res.typ = r
|
||||||
|
|
||||||
|
|
@ -1059,7 +1075,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
|
||||||
prev: PType, kind: TSymKind): PType =
|
prev: PType, kind: TSymKind): PType =
|
||||||
checkSonsLen(n, 2)
|
checkSonsLen(n, 2)
|
||||||
openScope(c)
|
openScope(c)
|
||||||
result = semProcTypeNode(c, n.sons[0], nil, prev, kind)
|
result = semProcTypeNode(c, n.sons[0], nil, prev, kind, isType=true)
|
||||||
# dummy symbol for `pragma`:
|
# dummy symbol for `pragma`:
|
||||||
var s = newSymS(kind, newIdentNode(getIdent("dummy"), n.info), c)
|
var s = newSymS(kind, newIdentNode(getIdent("dummy"), n.info), c)
|
||||||
s.typ = result
|
s.typ = result
|
||||||
|
|
@ -1188,6 +1204,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
assignType(prev, t)
|
assignType(prev, t)
|
||||||
result = prev
|
result = prev
|
||||||
markUsed(n.info, n.sym)
|
markUsed(n.info, n.sym)
|
||||||
|
styleCheckUse(n.info, n.sym)
|
||||||
else:
|
else:
|
||||||
if n.sym.kind != skError: localError(n.info, errTypeExpected)
|
if n.sym.kind != skError: localError(n.info, errTypeExpected)
|
||||||
result = newOrPrevType(tyError, prev, c)
|
result = newOrPrevType(tyError, prev, c)
|
||||||
|
|
@ -1234,7 +1251,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
|
|
||||||
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
||||||
m.typ.kind = kind
|
m.typ.kind = kind
|
||||||
m.typ.align = size
|
m.typ.align = size.int16
|
||||||
m.typ.size = size
|
m.typ.size = size
|
||||||
|
|
||||||
proc processMagicType(c: PContext, m: PSym) =
|
proc processMagicType(c: PContext, m: PSym) =
|
||||||
|
|
@ -1332,6 +1349,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||||
if def.typ.kind != tyTypeDesc:
|
if def.typ.kind != tyTypeDesc:
|
||||||
typ = newTypeWithSons(c, tyStatic, @[def.typ])
|
typ = newTypeWithSons(c, tyStatic, @[def.typ])
|
||||||
else:
|
else:
|
||||||
|
# the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]``
|
||||||
|
# from manyloc/named_argument_bug/triengine:
|
||||||
|
def.typ = def.typ.skipTypes({tyTypeDesc})
|
||||||
if not containsGenericType(def.typ):
|
if not containsGenericType(def.typ):
|
||||||
def = fitNode(c, typ, def)
|
def = fitNode(c, typ, def)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -216,7 +216,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym =
|
||||||
result.typ = replaceTypeVarsT(cl, s.typ)
|
result.typ = replaceTypeVarsT(cl, s.typ)
|
||||||
result.ast = replaceTypeVarsN(cl, s.ast)
|
result.ast = replaceTypeVarsN(cl, s.ast)
|
||||||
|
|
||||||
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||||
result = PType(idTableGet(cl.typeMap, t))
|
result = PType(idTableGet(cl.typeMap, t))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
if cl.allowMetaTypes or tfRetType in t.flags: return
|
if cl.allowMetaTypes or tfRetType in t.flags: return
|
||||||
|
|
@ -291,16 +291,24 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||||
|
|
||||||
var newbody = replaceTypeVarsT(cl, lastSon(body))
|
var newbody = replaceTypeVarsT(cl, lastSon(body))
|
||||||
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
newbody.flags = newbody.flags + (t.flags + body.flags - tfInstClearedFlags)
|
||||||
result.flags = result.flags + newbody.flags
|
result.flags = result.flags + newbody.flags - tfInstClearedFlags
|
||||||
newbody.callConv = body.callConv
|
# This is actually wrong: tgeneric_closure fails with this line:
|
||||||
|
#newbody.callConv = body.callConv
|
||||||
# This type may be a generic alias and we want to resolve it here.
|
# This type may be a generic alias and we want to resolve it here.
|
||||||
# One step is enough, because the recursive nature of
|
# One step is enough, because the recursive nature of
|
||||||
# handleGenericInvokation will handle the alias-to-alias-to-alias case
|
# handleGenericInvokation will handle the alias-to-alias-to-alias case
|
||||||
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
||||||
rawAddSon(result, newbody)
|
rawAddSon(result, newbody)
|
||||||
checkPartialConstructedType(cl.info, newbody)
|
checkPartialConstructedType(cl.info, newbody)
|
||||||
|
let dc = newbody.deepCopy
|
||||||
|
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
|
||||||
|
# 'deepCopy' needs to be instantiated for
|
||||||
|
# generics *when the type is constructed*:
|
||||||
|
newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info)
|
||||||
|
|
||||||
proc eraseVoidParams*(t: PType) =
|
proc eraseVoidParams*(t: PType) =
|
||||||
|
# transform '(): void' into '()' because old parts of the compiler really
|
||||||
|
# don't deal with '(): void':
|
||||||
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
|
if t.sons[0] != nil and t.sons[0].kind == tyEmpty:
|
||||||
t.sons[0] = nil
|
t.sons[0] = nil
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -25,39 +25,17 @@ var
|
||||||
lastCaasCmd* = ""
|
lastCaasCmd* = ""
|
||||||
# in caas mode, the list of defines and options will be given at start-up?
|
# in caas mode, the list of defines and options will be given at start-up?
|
||||||
# it's enough to check that the previous compilation command is the same?
|
# it's enough to check that the previous compilation command is the same?
|
||||||
arguments* = ""
|
|
||||||
# the arguments to be passed to the program that
|
|
||||||
# should be run
|
|
||||||
|
|
||||||
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||||
var p = parseopt.initOptParser(cmd)
|
var p = parseopt.initOptParser(cmd)
|
||||||
var argsCount = 0
|
var argsCount = 0
|
||||||
while true:
|
while true:
|
||||||
parseopt.next(p)
|
parseopt.next(p)
|
||||||
case p.kind
|
case p.kind
|
||||||
of cmdEnd: break
|
of cmdEnd: break
|
||||||
of cmdLongoption, cmdShortOption:
|
of cmdLongoption, cmdShortOption: processSwitch(pass, p)
|
||||||
# hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off")
|
|
||||||
# we fix this here
|
|
||||||
var bracketLe = strutils.find(p.key, '[')
|
|
||||||
if bracketLe >= 0:
|
|
||||||
var key = substr(p.key, 0, bracketLe - 1)
|
|
||||||
var val = substr(p.key, bracketLe + 1) & ':' & p.val
|
|
||||||
processSwitch(key, val, pass, gCmdLineInfo)
|
|
||||||
else:
|
|
||||||
processSwitch(p.key, p.val, pass, gCmdLineInfo)
|
|
||||||
of cmdArgument:
|
of cmdArgument:
|
||||||
if argsCount == 0:
|
if processArgument(pass, p, argsCount): break
|
||||||
options.command = p.key
|
|
||||||
else:
|
|
||||||
if pass == passCmd1: options.commandArgs.add p.key
|
|
||||||
if argsCount == 1:
|
|
||||||
# support UNIX style filenames anywhere for portable build scripts:
|
|
||||||
options.gProjectName = unixToNativePath(p.key)
|
|
||||||
arguments = cmdLineRest(p)
|
|
||||||
break
|
|
||||||
inc argsCount
|
|
||||||
|
|
||||||
if pass == passCmd2:
|
if pass == passCmd2:
|
||||||
if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run":
|
if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run":
|
||||||
rawMessage(errArgsNeedRunOption, [])
|
rawMessage(errArgsNeedRunOption, [])
|
||||||
|
|
@ -84,9 +62,9 @@ proc serve*(action: proc (){.nimcall.}) =
|
||||||
of "tcp", "":
|
of "tcp", "":
|
||||||
when useCaas:
|
when useCaas:
|
||||||
var server = socket()
|
var server = socket()
|
||||||
if server == invalidSocket: osError(osLastError())
|
if server == invalidSocket: raiseOSError(osLastError())
|
||||||
let p = getConfigVar("server.port")
|
let p = getConfigVar("server.port")
|
||||||
let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort
|
let port = if p.len > 0: parseInt(p).Port else: 6000.Port
|
||||||
server.bindAddr(port, getConfigVar("server.address"))
|
server.bindAddr(port, getConfigVar("server.address"))
|
||||||
var inp = "".TaintedString
|
var inp = "".TaintedString
|
||||||
server.listen()
|
server.listen()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -12,7 +12,8 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst,
|
||||||
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees
|
magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees,
|
||||||
|
nimfix.pretty
|
||||||
|
|
||||||
when not defined(noDocgen):
|
when not defined(noDocgen):
|
||||||
import docgen
|
import docgen
|
||||||
|
|
@ -21,7 +22,8 @@ type
|
||||||
TCandidateState* = enum
|
TCandidateState* = enum
|
||||||
csEmpty, csMatch, csNoMatch
|
csEmpty, csMatch, csNoMatch
|
||||||
|
|
||||||
TCandidate* {.final.} = object
|
CandidateErrors* = seq[PSym]
|
||||||
|
TCandidate* = object
|
||||||
c*: PContext
|
c*: PContext
|
||||||
exactMatches*: int # also misused to prefer iters over procs
|
exactMatches*: int # also misused to prefer iters over procs
|
||||||
genericMatches: int # also misused to prefer constraints
|
genericMatches: int # also misused to prefer constraints
|
||||||
|
|
@ -44,7 +46,7 @@ type
|
||||||
# a distrinct type
|
# a distrinct type
|
||||||
typedescMatched: bool
|
typedescMatched: bool
|
||||||
inheritancePenalty: int # to prefer closest father object type
|
inheritancePenalty: int # to prefer closest father object type
|
||||||
errors*: seq[string] # additional clarifications to be displayed to the
|
errors*: CandidateErrors # additional clarifications to be displayed to the
|
||||||
# user if overload resolution fails
|
# user if overload resolution fails
|
||||||
|
|
||||||
TTypeRelation* = enum # order is important!
|
TTypeRelation* = enum # order is important!
|
||||||
|
|
@ -201,16 +203,17 @@ proc writeMatches*(c: TCandidate) =
|
||||||
writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
writeln(stdout, "intconv matches: " & $c.intConvMatches)
|
||||||
writeln(stdout, "generic matches: " & $c.genericMatches)
|
writeln(stdout, "generic matches: " & $c.genericMatches)
|
||||||
|
|
||||||
proc argTypeToString(arg: PNode): string =
|
proc argTypeToString(arg: PNode; prefer: TPreferedDesc): string =
|
||||||
if arg.kind in nkSymChoices:
|
if arg.kind in nkSymChoices:
|
||||||
result = typeToString(arg[0].typ)
|
result = typeToString(arg[0].typ, prefer)
|
||||||
for i in 1 .. <arg.len:
|
for i in 1 .. <arg.len:
|
||||||
result.add(" | ")
|
result.add(" | ")
|
||||||
result.add typeToString(arg[i].typ)
|
result.add typeToString(arg[i].typ, prefer)
|
||||||
else:
|
else:
|
||||||
result = arg.typ.typeToString
|
result = arg.typ.typeToString(prefer)
|
||||||
|
|
||||||
proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
proc describeArgs*(c: PContext, n: PNode, startIdx = 1;
|
||||||
|
prefer: TPreferedDesc = preferName): string =
|
||||||
result = ""
|
result = ""
|
||||||
for i in countup(startIdx, n.len - 1):
|
for i in countup(startIdx, n.len - 1):
|
||||||
var arg = n.sons[i]
|
var arg = n.sons[i]
|
||||||
|
|
@ -226,7 +229,7 @@ proc describeArgs*(c: PContext, n: PNode, startIdx = 1): string =
|
||||||
arg = c.semOperand(c, n.sons[i])
|
arg = c.semOperand(c, n.sons[i])
|
||||||
n.sons[i] = arg
|
n.sons[i] = arg
|
||||||
if arg.typ.kind == tyError: return
|
if arg.typ.kind == tyError: return
|
||||||
add(result, argTypeToString(arg))
|
add(result, argTypeToString(arg, prefer))
|
||||||
if i != sonsLen(n) - 1: add(result, ", ")
|
if i != sonsLen(n) - 1: add(result, ", ")
|
||||||
|
|
||||||
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
proc typeRel*(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation
|
||||||
|
|
@ -239,6 +242,9 @@ proc concreteType(c: TCandidate, t: PType): PType =
|
||||||
addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type?
|
addSonSkipIntLit(result, t.sons[1]) # XXX: semantic checking for the type?
|
||||||
of tyNil:
|
of tyNil:
|
||||||
result = nil # what should it be?
|
result = nil # what should it be?
|
||||||
|
of tySequence, tySet:
|
||||||
|
if t.sons[0].kind == tyEmpty: result = nil
|
||||||
|
else: result = t
|
||||||
of tyGenericParam, tyAnything:
|
of tyGenericParam, tyAnything:
|
||||||
result = t
|
result = t
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -343,7 +349,7 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||||
var y = a.n.sons[i].sym
|
var y = a.n.sons[i].sym
|
||||||
if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype:
|
if f.kind == tyObject and typeRel(c, x.typ, y.typ) < isSubtype:
|
||||||
return isNone
|
return isNone
|
||||||
if x.name.id != y.name.id: return isNone
|
if x.name.id != y.name.id and f.kind != tyTuple: return isNone
|
||||||
|
|
||||||
proc allowsNil(f: PType): TTypeRelation {.inline.} =
|
proc allowsNil(f: PType): TTypeRelation {.inline.} =
|
||||||
result = if tfNotNil notin f.flags: isSubtype else: isNone
|
result = if tfNotNil notin f.flags: isSubtype else: isNone
|
||||||
|
|
@ -479,8 +485,8 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||||
dummyParam.typ = dummyType
|
dummyParam.typ = dummyType
|
||||||
addDecl(c, dummyParam)
|
addDecl(c, dummyParam)
|
||||||
|
|
||||||
var checkedBody = c.semTryExpr(c, body.n[3].copyTree, bufferErrors = false)
|
var checkedBody = c.semTryExpr(c, body.n[3].copyTree)
|
||||||
m.errors = bufferedMsgs
|
#m.errors = bufferedMsgs
|
||||||
clearBufferedMsgs()
|
clearBufferedMsgs()
|
||||||
if checkedBody == nil: return isNone
|
if checkedBody == nil: return isNone
|
||||||
|
|
||||||
|
|
@ -930,6 +936,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||||
else:
|
else:
|
||||||
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
if f.sonsLen > 0 and f.sons[0].kind != tyNone:
|
||||||
result = typeRel(c, f.lastSon, a)
|
result = typeRel(c, f.lastSon, a)
|
||||||
|
if doBind and result notin {isNone, isGeneric}:
|
||||||
|
let concrete = concreteType(c, a)
|
||||||
|
if concrete == nil: return isNone
|
||||||
|
put(c.bindings, f, concrete)
|
||||||
else:
|
else:
|
||||||
result = isGeneric
|
result = isGeneric
|
||||||
|
|
||||||
|
|
@ -1073,6 +1083,11 @@ proc localConvMatch(c: PContext, m: var TCandidate, f, a: PType,
|
||||||
arg: PNode): PNode =
|
arg: PNode): PNode =
|
||||||
# arg.typ can be nil in 'suggest':
|
# arg.typ can be nil in 'suggest':
|
||||||
if isNil(arg.typ): return nil
|
if isNil(arg.typ): return nil
|
||||||
|
|
||||||
|
# sem'checking for 'echo' needs to be re-entrant:
|
||||||
|
# XXX we will revisit this issue after 0.10.2 is released
|
||||||
|
if f == arg.typ and arg.kind == nkHiddenStdConv: return arg
|
||||||
|
|
||||||
var call = newNodeI(nkCall, arg.info)
|
var call = newNodeI(nkCall, arg.info)
|
||||||
call.add(f.n.copyTree)
|
call.add(f.n.copyTree)
|
||||||
call.add(arg.copyTree)
|
call.add(arg.copyTree)
|
||||||
|
|
@ -1143,8 +1158,8 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||||
of isEqual: inc(m.exactMatches)
|
of isEqual: inc(m.exactMatches)
|
||||||
of isNone: discard
|
of isNone: discard
|
||||||
|
|
||||||
if f.kind == tyStmt and argOrig.kind == nkDo:
|
if f.kind == tyStmt:
|
||||||
return argOrig[bodyPos]
|
return arg
|
||||||
elif f.kind == tyTypeDesc:
|
elif f.kind == tyTypeDesc:
|
||||||
return arg
|
return arg
|
||||||
elif f.kind == tyStatic:
|
elif f.kind == tyStatic:
|
||||||
|
|
@ -1272,6 +1287,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
|
||||||
else:
|
else:
|
||||||
# only one valid interpretation found:
|
# only one valid interpretation found:
|
||||||
markUsed(arg.info, arg.sons[best].sym)
|
markUsed(arg.info, arg.sons[best].sym)
|
||||||
|
styleCheckUse(arg.info, arg.sons[best].sym)
|
||||||
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
|
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
|
||||||
argOrig)
|
argOrig)
|
||||||
|
|
||||||
|
|
@ -1319,7 +1335,7 @@ proc incrIndexType(t: PType) =
|
||||||
inc t.sons[0].n.sons[1].intVal
|
inc t.sons[0].n.sons[1].intVal
|
||||||
|
|
||||||
proc matchesAux(c: PContext, n, nOrig: PNode,
|
proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||||
m: var TCandidate, marker: var TIntSet) =
|
m: var TCandidate, marker: var IntSet) =
|
||||||
template checkConstraint(n: expr) {.immediate, dirty.} =
|
template checkConstraint(n: expr) {.immediate, dirty.} =
|
||||||
if not formal.constraint.isNil:
|
if not formal.constraint.isNil:
|
||||||
if matchNodeKinds(formal.constraint, n):
|
if matchNodeKinds(formal.constraint, n):
|
||||||
|
|
@ -1480,8 +1496,23 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool =
|
||||||
# instantiate generic converters for that
|
# instantiate generic converters for that
|
||||||
result = res != nil
|
result = res != nil
|
||||||
|
|
||||||
|
proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {.
|
||||||
|
procvar.} =
|
||||||
|
var m: TCandidate
|
||||||
|
initCandidate(c, m, dc.typ)
|
||||||
|
var f = dc.typ.sons[1]
|
||||||
|
if f.kind in {tyRef, tyPtr}: f = f.lastSon
|
||||||
|
if typeRel(m, f, t) == isNone:
|
||||||
|
localError(info, errGenerated, "cannot instantiate 'deepCopy'")
|
||||||
|
else:
|
||||||
|
result = c.semGenerateInstance(c, dc, m.bindings, info)
|
||||||
|
assert sfFromGeneric in result.flags
|
||||||
|
|
||||||
include suggest
|
include suggest
|
||||||
|
|
||||||
|
when not declared(tests):
|
||||||
|
template tests(s: stmt) {.immediate.} = discard
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
|
var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2013 Andreas Rumpf
|
# (c) Copyright 2013 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
# included from sigmatch.nim
|
# included from sigmatch.nim
|
||||||
|
|
||||||
import algorithm, sequtils, pretty
|
import algorithm, sequtils
|
||||||
|
|
||||||
const
|
const
|
||||||
sep = '\t'
|
sep = '\t'
|
||||||
|
|
@ -331,7 +331,6 @@ proc markUsed(info: TLineInfo; s: PSym) =
|
||||||
if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
|
if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s)
|
||||||
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
|
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
|
||||||
suggestSym(info, s)
|
suggestSym(info, s)
|
||||||
if gCmd == cmdPretty: checkUse(info, s)
|
|
||||||
|
|
||||||
proc useSym*(sym: PSym): PNode =
|
proc useSym*(sym: PSym): PNode =
|
||||||
result = newSymNode(sym)
|
result = newSymNode(sym)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -44,7 +44,7 @@ proc parseTopLevelStmt*(p: var TParsers): PNode
|
||||||
proc parseFile(fileIdx: int32): PNode =
|
proc parseFile(fileIdx: int32): PNode =
|
||||||
var
|
var
|
||||||
p: TParsers
|
p: TParsers
|
||||||
f: TFile
|
f: File
|
||||||
let filename = fileIdx.toFullPath
|
let filename = fileIdx.toFullPath
|
||||||
if not open(f, filename):
|
if not open(f, filename):
|
||||||
rawMessage(errCannotOpenFile, filename)
|
rawMessage(errCannotOpenFile, filename)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2014 Andreas Rumpf
|
# (c) Copyright 2014 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -582,7 +582,7 @@ proc getMergeOp(n: PNode): PSym =
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
proc flattenTreeAux(d, a: PNode, op: PSym) =
|
||||||
var op2 = getMergeOp(a)
|
let op2 = getMergeOp(a)
|
||||||
if op2 != nil and
|
if op2 != nil and
|
||||||
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
|
(op2.id == op.id or op.magic != mNone and op2.magic == op.magic):
|
||||||
for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
|
for i in countup(1, sonsLen(a)-1): flattenTreeAux(d, a.sons[i], op)
|
||||||
|
|
@ -590,7 +590,7 @@ proc flattenTreeAux(d, a: PNode, op: PSym) =
|
||||||
addSon(d, copyTree(a))
|
addSon(d, copyTree(a))
|
||||||
|
|
||||||
proc flattenTree(root: PNode): PNode =
|
proc flattenTree(root: PNode): PNode =
|
||||||
var op = getMergeOp(root)
|
let op = getMergeOp(root)
|
||||||
if op != nil:
|
if op != nil:
|
||||||
result = copyNode(root)
|
result = copyNode(root)
|
||||||
addSon(result, copyTree(root.sons[0]))
|
addSon(result, copyTree(root.sons[0]))
|
||||||
|
|
@ -600,8 +600,9 @@ proc flattenTree(root: PNode): PNode =
|
||||||
|
|
||||||
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||||
var n = flattenTree(n)
|
var n = flattenTree(n)
|
||||||
var op = getMergeOp(n)
|
let op = getMergeOp(n)
|
||||||
if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
|
let magic = getMagic(n)
|
||||||
|
if op != nil and op.magic != mNone and n.len >= 3:
|
||||||
result = newTransNode(nkCall, n, 0)
|
result = newTransNode(nkCall, n, 0)
|
||||||
add(result, transform(c, n.sons[0]))
|
add(result, transform(c, n.sons[0]))
|
||||||
var j = 1
|
var j = 1
|
||||||
|
|
@ -616,9 +617,12 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||||
inc(j)
|
inc(j)
|
||||||
add(result, a.PTransNode)
|
add(result, a.PTransNode)
|
||||||
if len(result) == 2: result = result[1]
|
if len(result) == 2: result = result[1]
|
||||||
elif getMagic(n) == mNBindSym:
|
elif magic == mNBindSym:
|
||||||
# for bindSym(myconst) we MUST NOT perform constant folding:
|
# for bindSym(myconst) we MUST NOT perform constant folding:
|
||||||
result = n.PTransNode
|
result = n.PTransNode
|
||||||
|
elif magic == mProcCall:
|
||||||
|
# but do not change to its dispatcher:
|
||||||
|
result = transformSons(c, n[1])
|
||||||
else:
|
else:
|
||||||
let s = transformSons(c, n).PNode
|
let s = transformSons(c, n).PNode
|
||||||
# bugfix: check after 'transformSons' if it's still a method call:
|
# bugfix: check after 'transformSons' if it's still a method call:
|
||||||
|
|
@ -785,8 +789,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
||||||
# result = lambdalifting.liftIterator(prc, result)
|
# result = lambdalifting.liftIterator(prc, result)
|
||||||
incl(result.flags, nfTransf)
|
incl(result.flags, nfTransf)
|
||||||
when useEffectSystem: trackProc(prc, result)
|
when useEffectSystem: trackProc(prc, result)
|
||||||
if prc.name.s == "testbody":
|
#if prc.name.s == "testbody":
|
||||||
echo renderTree(result)
|
# echo renderTree(result)
|
||||||
|
|
||||||
proc transformStmt*(module: PSym, n: PNode): PNode =
|
proc transformStmt*(module: PSym, n: PNode): PNode =
|
||||||
if nfTransf in n.flags:
|
if nfTransf in n.flags:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
@ -117,7 +117,9 @@ proc isDeepConstExpr*(n: PNode): bool =
|
||||||
of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
|
of nkCurly, nkBracket, nkPar, nkObjConstr, nkClosure:
|
||||||
for i in 0 .. <n.len:
|
for i in 0 .. <n.len:
|
||||||
if not isDeepConstExpr(n.sons[i]): return false
|
if not isDeepConstExpr(n.sons[i]): return false
|
||||||
result = true
|
# XXX once constant objects are supported by the codegen this needs to be
|
||||||
|
# weakened:
|
||||||
|
result = n.typ.isNil or n.typ.skipTypes({tyGenericInst, tyDistinct}).kind != tyObject
|
||||||
else: discard
|
else: discard
|
||||||
|
|
||||||
proc flattenTreeAux(d, a: PNode, op: TMagic) =
|
proc flattenTreeAux(d, a: PNode, op: TMagic) =
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# The Nimrod Compiler
|
# The Nim Compiler
|
||||||
# (c) Copyright 2012 Andreas Rumpf
|
# (c) Copyright 2012 Andreas Rumpf
|
||||||
#
|
#
|
||||||
# See the file "copying.txt", included in this
|
# See the file "copying.txt", included in this
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue