mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-07 04:14:19 +00:00
Merge branch 'devel' into warning-for-result
This commit is contained in:
299
compiler/ast.nim
299
compiler/ast.nim
@@ -314,7 +314,7 @@ type
|
||||
# XXX put this into an include file to avoid this issue!
|
||||
tyNone, tyBool, tyChar,
|
||||
tyEmpty, tyArrayConstr, tyNil, tyExpr, tyStmt, tyTypeDesc,
|
||||
tyGenericInvokation, # ``T[a, b]`` for types to invoke
|
||||
tyGenericInvocation, # ``T[a, b]`` for types to invoke
|
||||
tyGenericBody, # ``T[a, b, body]`` last parameter is the body
|
||||
tyGenericInst, # ``T[a, b, realInstance]`` instantiated generic type
|
||||
# realInstance will be a concrete type like tyObject
|
||||
@@ -377,7 +377,7 @@ type
|
||||
|
||||
tyFromExpr #\
|
||||
# This is a type representing an expression that depends
|
||||
# on generic parameters (the exprsesion is stored in t.n)
|
||||
# on generic parameters (the expression is stored in t.n)
|
||||
# It will be converted to a real type only during generic
|
||||
# instantiation and prior to this it has the potential to
|
||||
# be any type.
|
||||
@@ -459,7 +459,7 @@ type
|
||||
|
||||
tfNeedsInit, # type constains a "not nil" constraint somewhere or some
|
||||
# other type so that it requires inititalization
|
||||
tfHasShared, # type constains a "shared" constraint modifier somewhere
|
||||
tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode
|
||||
tfHasMeta, # type contains "wildcard" sub-types such as generic params
|
||||
# or other type classes
|
||||
tfHasGCedMem, # type contains GC'ed memory
|
||||
@@ -522,7 +522,7 @@ const
|
||||
skError* = skUnknown
|
||||
|
||||
# type flags that are essential for type equality:
|
||||
eqTypeFlags* = {tfIterator, tfShared, tfNotNil}
|
||||
eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
|
||||
|
||||
type
|
||||
TMagic* = enum # symbols that require compiler magic:
|
||||
@@ -655,7 +655,6 @@ type
|
||||
locGlobalVar, # location is a global variable
|
||||
locParam, # location is a parameter
|
||||
locField, # location is a record field
|
||||
locArrayElem, # location is an array element
|
||||
locExpr, # "location" is really an expression
|
||||
locProc, # location is a proc (an address of a procedure)
|
||||
locData, # location is a constant
|
||||
@@ -669,14 +668,15 @@ type
|
||||
lfDynamicLib, # link symbol to dynamic library
|
||||
lfExportLib, # export symbol for dynamic library generation
|
||||
lfHeader, # include header file for symbol
|
||||
lfImportCompilerProc # ``importc`` of a compilerproc
|
||||
lfImportCompilerProc, # ``importc`` of a compilerproc
|
||||
lfSingleUse # no location yet and will only be used once
|
||||
TStorageLoc* = enum
|
||||
OnUnknown, # location is unknown (stack, heap or static)
|
||||
OnStack, # location is on hardware stack
|
||||
OnHeap # location is on heap or global
|
||||
# (reference counting needed)
|
||||
TLocFlags* = set[TLocFlag]
|
||||
TLoc*{.final.} = object
|
||||
TLoc* = object
|
||||
k*: TLocKind # kind of location
|
||||
s*: TStorageLoc
|
||||
flags*: TLocFlags # location's flags
|
||||
@@ -859,7 +859,7 @@ const
|
||||
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
|
||||
skConverter, skModule, skTemplate, skMacro}
|
||||
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody,
|
||||
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
|
||||
tyGenericParam}
|
||||
|
||||
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
|
||||
@@ -918,50 +918,6 @@ const
|
||||
# only used when 'gCmd == cmdPretty': Indicates that the symbol has been
|
||||
# imported via 'importc: "fullname"' and no format string.
|
||||
|
||||
# creator procs:
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
info: TLineInfo): PSym
|
||||
proc newType*(kind: TTypeKind, owner: PSym): PType
|
||||
proc newNode*(kind: TNodeKind): PNode
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode
|
||||
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode
|
||||
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode
|
||||
proc newStrNode*(kind: TNodeKind, strVal: string): PNode
|
||||
proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode
|
||||
proc newSymNode*(sym: PSym): PNode
|
||||
proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode
|
||||
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode
|
||||
proc initStrTable*(x: var TStrTable)
|
||||
proc initTable*(x: var TTable)
|
||||
proc initIdTable*(x: var TIdTable)
|
||||
proc initObjectSet*(x: var TObjectSet)
|
||||
proc initIdNodeTable*(x: var TIdNodeTable)
|
||||
proc initNodeTable*(x: var TNodeTable)
|
||||
|
||||
# copy procs:
|
||||
proc copyType*(t: PType, owner: PSym, keepId: bool): PType
|
||||
proc copySym*(s: PSym, keepId: bool = false): PSym
|
||||
proc assignType*(dest, src: PType)
|
||||
proc copyStrTable*(dest: var TStrTable, src: TStrTable)
|
||||
proc copyTable*(dest: var TTable, src: TTable)
|
||||
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet)
|
||||
proc copyIdTable*(dest: var TIdTable, src: TIdTable)
|
||||
proc sonsLen*(n: PNode): int {.inline.}
|
||||
proc sonsLen*(n: PType): int {.inline.}
|
||||
proc lastSon*(n: PNode): PNode {.inline.}
|
||||
proc lastSon*(n: PType): PType {.inline.}
|
||||
proc newSons*(father: PNode, length: int)
|
||||
proc newSons*(father: PType, length: int)
|
||||
proc addSon*(father, son: PNode)
|
||||
proc delSon*(father: PNode, idx: int)
|
||||
proc hasSonWith*(n: PNode, kind: TNodeKind): bool
|
||||
proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool
|
||||
proc replaceSons*(n: PNode, oldKind, newKind: TNodeKind)
|
||||
proc copyNode*(src: PNode): PNode
|
||||
# does not copy its sons!
|
||||
proc copyTree*(src: PNode): PNode
|
||||
# does copy its sons!
|
||||
|
||||
proc isCallExpr*(n: PNode): bool =
|
||||
result = n.kind in nkCallKinds
|
||||
|
||||
@@ -988,7 +944,61 @@ proc `[]`*(n: PNode, i: int): PNode {.inline.} =
|
||||
template `{}`*(n: PNode, i: int): expr = n[i -| n]
|
||||
template `{}=`*(n: PNode, i: int, s: PNode): stmt =
|
||||
n.sons[i -| n] = s
|
||||
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
var gNodeId: int
|
||||
|
||||
proc newNode*(kind: TNodeKind): PNode =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
#result.info = UnknownLineInfo() inlined:
|
||||
result.info.fileIndex = int32(- 1)
|
||||
result.info.col = int16(- 1)
|
||||
result.info.line = int16(- 1)
|
||||
when defined(useNodeIds):
|
||||
result.id = gNodeId
|
||||
if result.id == nodeIdToDebug:
|
||||
echo "KIND ", result.kind
|
||||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
result = newNode(kind)
|
||||
result.intVal = intVal
|
||||
|
||||
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
|
||||
result = newIntNode(kind, intVal)
|
||||
result.typ = typ
|
||||
|
||||
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
|
||||
result = newNode(kind)
|
||||
result.floatVal = floatVal
|
||||
|
||||
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
|
||||
result = newNode(kind)
|
||||
result.strVal = strVal
|
||||
|
||||
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
info: TLineInfo): PSym =
|
||||
# generates a symbol and initializes the hash field too
|
||||
new(result)
|
||||
result.name = name
|
||||
result.kind = symKind
|
||||
result.flags = {}
|
||||
result.info = info
|
||||
result.options = gOptions
|
||||
result.owner = owner
|
||||
result.offset = - 1
|
||||
result.id = getID()
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
# MessageOut(name.s & " has id: " & toString(result.id))
|
||||
|
||||
var emptyNode* = newNode(nkEmpty)
|
||||
# There is a single empty node that is shared! Do not overwrite it!
|
||||
|
||||
@@ -1031,80 +1041,43 @@ const # for all kind of hash tables:
|
||||
GrowthFactor* = 2 # must be power of 2, > 0
|
||||
StartSize* = 8 # must be power of 2, > 0
|
||||
|
||||
proc copyStrTable(dest: var TStrTable, src: TStrTable) =
|
||||
proc copyStrTable*(dest: var TStrTable, src: TStrTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyIdTable(dest: var TIdTable, src: TIdTable) =
|
||||
proc copyIdTable*(dest: var TIdTable, src: TIdTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
newSeq(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyTable(dest: var TTable, src: TTable) =
|
||||
proc copyTable*(dest: var TTable, src: TTable) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc copyObjectSet(dest: var TObjectSet, src: TObjectSet) =
|
||||
proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) =
|
||||
dest.counter = src.counter
|
||||
if isNil(src.data): return
|
||||
setLen(dest.data, len(src.data))
|
||||
for i in countup(0, high(src.data)): dest.data[i] = src.data[i]
|
||||
|
||||
proc discardSons(father: PNode) =
|
||||
proc discardSons*(father: PNode) =
|
||||
father.sons = nil
|
||||
|
||||
when defined(useNodeIds):
|
||||
const nodeIdToDebug* = -1 # 884953 # 612794
|
||||
#612840 # 612905 # 614635 # 614637 # 614641
|
||||
# 423408
|
||||
#429107 # 430443 # 441048 # 441090 # 441153
|
||||
var gNodeId: int
|
||||
|
||||
proc newNode(kind: TNodeKind): PNode =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
#result.info = UnknownLineInfo() inlined:
|
||||
result.info.fileIndex = int32(- 1)
|
||||
result.info.col = int16(- 1)
|
||||
result.info.line = int16(- 1)
|
||||
when defined(useNodeIds):
|
||||
result.id = gNodeId
|
||||
if result.id == nodeIdToDebug:
|
||||
echo "KIND ", result.kind
|
||||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newIntNode(kind: TNodeKind, intVal: BiggestInt): PNode =
|
||||
result = newNode(kind)
|
||||
result.intVal = intVal
|
||||
|
||||
proc newIntTypeNode(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
|
||||
result = newIntNode(kind, intVal)
|
||||
result.typ = typ
|
||||
|
||||
proc newFloatNode(kind: TNodeKind, floatVal: BiggestFloat): PNode =
|
||||
result = newNode(kind)
|
||||
result.floatVal = floatVal
|
||||
|
||||
proc newStrNode(kind: TNodeKind, strVal: string): PNode =
|
||||
result = newNode(kind)
|
||||
result.strVal = strVal
|
||||
|
||||
proc withInfo*(n: PNode, info: TLineInfo): PNode =
|
||||
n.info = info
|
||||
return n
|
||||
|
||||
proc newIdentNode(ident: PIdent, info: TLineInfo): PNode =
|
||||
proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
|
||||
result = newNode(nkIdent)
|
||||
result.ident = ident
|
||||
result.info = info
|
||||
|
||||
proc newSymNode(sym: PSym): PNode =
|
||||
proc newSymNode*(sym: PSym): PNode =
|
||||
result = newNode(nkSym)
|
||||
result.sym = sym
|
||||
result.typ = sym.typ
|
||||
@@ -1116,7 +1089,7 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
|
||||
result.typ = sym.typ
|
||||
result.info = info
|
||||
|
||||
proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode =
|
||||
proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode =
|
||||
new(result)
|
||||
result.kind = kind
|
||||
result.info = info
|
||||
@@ -1155,11 +1128,16 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
|
||||
writeStackTrace()
|
||||
inc gNodeId
|
||||
|
||||
proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
|
||||
proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
|
||||
result = newNode(kind)
|
||||
result.info = info
|
||||
result.typ = typ
|
||||
|
||||
proc addSon*(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
var emptyParams = newNode(nkFormalParams)
|
||||
emptyParams.addSon(emptyNode)
|
||||
|
||||
@@ -1181,7 +1159,7 @@ proc `$`*(x: TLockLevel): string =
|
||||
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)
|
||||
result.kind = kind
|
||||
result.owner = owner
|
||||
@@ -1201,8 +1179,38 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
|
||||
if a.t == nil: a.t = b.t
|
||||
if a.r == nil: a.r = b.r
|
||||
#if a.a == 0: a.a = b.a
|
||||
|
||||
proc newSons*(father: PNode, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc newSons*(father: PType, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc sonsLen*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc len*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc assignType(dest, src: PType) =
|
||||
proc sonsLen*(n: PNode): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc lastSon*(n: PNode): PNode =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc lastSon*(n: PType): PType =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc assignType*(dest, src: PType) =
|
||||
dest.kind = src.kind
|
||||
dest.flags = src.flags
|
||||
dest.callConv = src.callConv
|
||||
@@ -1223,7 +1231,7 @@ proc assignType(dest, src: PType) =
|
||||
newSons(dest, sonsLen(src))
|
||||
for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i]
|
||||
|
||||
proc copyType(t: PType, owner: PSym, keepId: bool): PType =
|
||||
proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
|
||||
result = newType(t.kind, owner)
|
||||
assignType(result, t)
|
||||
if keepId:
|
||||
@@ -1232,7 +1240,7 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType =
|
||||
when debugIds: registerId(result)
|
||||
result.sym = t.sym # backend-info should not be copied
|
||||
|
||||
proc copySym(s: PSym, keepId: bool = false): PSym =
|
||||
proc copySym*(s: PSym, keepId: bool = false): PSym =
|
||||
result = newSym(s.kind, s.name, s.owner, s.info)
|
||||
#result.ast = nil # BUGFIX; was: s.ast which made problems
|
||||
result.typ = s.typ
|
||||
@@ -1266,24 +1274,7 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
|
||||
# XXX once usedGenerics is used, ensure module aliases keep working!
|
||||
assert s.usedGenerics == nil
|
||||
|
||||
proc newSym(symKind: TSymKind, name: PIdent, owner: PSym,
|
||||
info: TLineInfo): PSym =
|
||||
# generates a symbol and initializes the hash field too
|
||||
new(result)
|
||||
result.name = name
|
||||
result.kind = symKind
|
||||
result.flags = {}
|
||||
result.info = info
|
||||
result.options = gOptions
|
||||
result.owner = owner
|
||||
result.offset = - 1
|
||||
result.id = getID()
|
||||
when debugIds:
|
||||
registerId(result)
|
||||
#if result.id < 2000:
|
||||
# MessageOut(name.s & " has id: " & toString(result.id))
|
||||
|
||||
proc initStrTable(x: var TStrTable) =
|
||||
proc initStrTable*(x: var TStrTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
@@ -1294,46 +1285,28 @@ proc initTable(x: var TTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdTable(x: var TIdTable) =
|
||||
proc initIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initObjectSet(x: var TObjectSet) =
|
||||
proc resetIdTable*(x: var TIdTable) =
|
||||
x.counter = 0
|
||||
# clear and set to old initial size:
|
||||
setLen(x.data, 0)
|
||||
setLen(x.data, StartSize)
|
||||
|
||||
proc initObjectSet*(x: var TObjectSet) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initIdNodeTable(x: var TIdNodeTable) =
|
||||
proc initIdNodeTable*(x: var TIdNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc initNodeTable(x: var TNodeTable) =
|
||||
proc initNodeTable*(x: var TNodeTable) =
|
||||
x.counter = 0
|
||||
newSeq(x.data, StartSize)
|
||||
|
||||
proc sonsLen(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc len*(n: PType): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc newSons(father: PType, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc sonsLen(n: PNode): int =
|
||||
if isNil(n.sons): result = 0
|
||||
else: result = len(n.sons)
|
||||
|
||||
proc newSons(father: PNode, length: int) =
|
||||
if isNil(father.sons):
|
||||
newSeq(father.sons, length)
|
||||
else:
|
||||
setLen(father.sons, length)
|
||||
|
||||
proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
|
||||
## Used throughout the compiler code to test whether a type tree contains or
|
||||
## doesn't contain a specific type/types - it is often the case that only the
|
||||
@@ -1348,9 +1321,9 @@ proc isGCedMem*(t: PType): bool {.inline.} =
|
||||
|
||||
proc propagateToOwner*(owner, elem: PType) =
|
||||
const HaveTheirOwnEmpty = {tySequence, tySet}
|
||||
owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta})
|
||||
owner.flags = owner.flags + (elem.flags * {tfHasMeta})
|
||||
if tfNotNil in elem.flags:
|
||||
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}:
|
||||
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
|
||||
owner.flags.incl tfNotNil
|
||||
elif owner.kind notin HaveTheirOwnEmpty:
|
||||
owner.flags.incl tfNeedsInit
|
||||
@@ -1359,9 +1332,6 @@ proc propagateToOwner*(owner, elem: PType) =
|
||||
if owner.kind in HaveTheirOwnEmpty: discard
|
||||
else: owner.flags.incl tfNeedsInit
|
||||
|
||||
if tfShared in elem.flags:
|
||||
owner.flags.incl tfHasShared
|
||||
|
||||
if elem.isMetaType:
|
||||
owner.flags.incl tfHasMeta
|
||||
|
||||
@@ -1374,22 +1344,17 @@ proc rawAddSon*(father, son: PType) =
|
||||
add(father.sons, son)
|
||||
if not son.isNil: propagateToOwner(father, son)
|
||||
|
||||
proc addSon(father, son: PNode) =
|
||||
assert son != nil
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
proc addSonNilAllowed*(father, son: PNode) =
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
add(father.sons, son)
|
||||
|
||||
proc delSon(father: PNode, idx: int) =
|
||||
proc delSon*(father: PNode, idx: int) =
|
||||
if isNil(father.sons): return
|
||||
var length = sonsLen(father)
|
||||
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
|
||||
setLen(father.sons, length - 1)
|
||||
|
||||
proc copyNode(src: PNode): PNode =
|
||||
proc copyNode*(src: PNode): PNode =
|
||||
# does not copy its sons!
|
||||
if src == nil:
|
||||
return nil
|
||||
@@ -1426,7 +1391,7 @@ proc shallowCopy*(src: PNode): PNode =
|
||||
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
|
||||
else: newSeq(result.sons, sonsLen(src))
|
||||
|
||||
proc copyTree(src: PNode): PNode =
|
||||
proc copyTree*(src: PNode): PNode =
|
||||
# copy a whole syntax tree; performs deep copying
|
||||
if src == nil:
|
||||
return nil
|
||||
@@ -1447,14 +1412,8 @@ proc copyTree(src: PNode): PNode =
|
||||
newSeq(result.sons, sonsLen(src))
|
||||
for i in countup(0, sonsLen(src) - 1):
|
||||
result.sons[i] = copyTree(src.sons[i])
|
||||
|
||||
proc lastSon(n: PNode): PNode =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc lastSon(n: PType): PType =
|
||||
result = n.sons[sonsLen(n) - 1]
|
||||
|
||||
proc hasSonWith(n: PNode, kind: TNodeKind): bool =
|
||||
proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind == kind:
|
||||
return true
|
||||
@@ -1476,7 +1435,7 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.kind in kinds or containsNode(n.sons[i], kinds): return true
|
||||
|
||||
proc hasSubnodeWith(n: PNode, kind: TNodeKind): bool =
|
||||
proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
|
||||
case n.kind
|
||||
of nkEmpty..nkNilLit: result = n.kind == kind
|
||||
else:
|
||||
|
||||
@@ -130,8 +130,8 @@ proc skipConvAndClosure*(n: PNode): PNode =
|
||||
proc sameValue*(a, b: PNode): bool =
|
||||
result = false
|
||||
case a.kind
|
||||
of nkCharLit..nkInt64Lit:
|
||||
if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
@@ -145,13 +145,13 @@ proc leValue*(a, b: PNode): bool =
|
||||
# a <= b?
|
||||
result = false
|
||||
case a.kind
|
||||
of nkCharLit..nkInt64Lit:
|
||||
if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
of nkCharLit..nkUInt32Lit:
|
||||
if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal
|
||||
else:
|
||||
else:
|
||||
# don't raise an internal error for 'nimrod check':
|
||||
#InternalError(a.info, "leValue")
|
||||
discard
|
||||
@@ -387,6 +387,9 @@ proc debugType(n: PType, maxRecDepth=100): PRope =
|
||||
if n.sym != nil:
|
||||
app(result, " ")
|
||||
app(result, n.sym.name.s)
|
||||
if n.kind in IntegralTypes and n.n != nil:
|
||||
app(result, ", node: ")
|
||||
app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true))
|
||||
if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
|
||||
app(result, "(")
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
@@ -445,21 +448,21 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
|
||||
|
||||
proc debug(n: PSym) =
|
||||
if n == nil:
|
||||
writeln(stdout, "null")
|
||||
msgWriteln("null")
|
||||
elif n.kind == skUnknown:
|
||||
writeln(stdout, "skUnknown")
|
||||
msgWriteln("skUnknown")
|
||||
else:
|
||||
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1)))
|
||||
writeln(stdout, "$1_$2: $3, $4, $5, $6" % [
|
||||
msgWriteln("$1_$2: $3, $4, $5, $6" % [
|
||||
n.name.s, $n.id, flagsToStr(n.flags).ropeToStr,
|
||||
flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr,
|
||||
$n.kind])
|
||||
|
||||
proc debug(n: PType) =
|
||||
writeln(stdout, ropeToStr(debugType(n)))
|
||||
msgWriteln(ropeToStr(debugType(n)))
|
||||
|
||||
proc debug(n: PNode) =
|
||||
writeln(stdout, ropeToStr(debugTree(n, 0, 100)))
|
||||
msgWriteln(ropeToStr(debugTree(n, 0, 100)))
|
||||
|
||||
const
|
||||
EmptySeq = @[]
|
||||
@@ -678,9 +681,8 @@ proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
|
||||
else: result = nextIdentIter(ti, tab)
|
||||
|
||||
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
|
||||
var h, start: THash
|
||||
h = ti.h and high(tab.data)
|
||||
start = h
|
||||
var h = ti.h and high(tab.data)
|
||||
var start = h
|
||||
result = tab.data[h]
|
||||
while result != nil:
|
||||
if result.name.id == ti.name.id: break
|
||||
|
||||
@@ -119,8 +119,8 @@ proc hashType(c: var MD5Context, t: PType) =
|
||||
c.hashSym(t.sym)
|
||||
|
||||
case t.kind
|
||||
of tyGenericBody, tyGenericInst, tyGenericInvokation:
|
||||
for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
|
||||
of tyGenericBody, tyGenericInst, tyGenericInvocation:
|
||||
for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)):
|
||||
c.hashType t.sons[i]
|
||||
of tyUserTypeClass:
|
||||
internalAssert t.sym != nil and t.sym.owner != nil
|
||||
|
||||
@@ -45,12 +45,20 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
else:
|
||||
app(pl, ~")")
|
||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.t, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if p.module.compileToCpp and lfSingleUse in d.flags:
|
||||
# do not generate spurious temporaries for C++! For C we're better off
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
# is free to emit expressions multiple times!
|
||||
d.k = locCall
|
||||
d.r = pl
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.t, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
app(pl, ~");$n")
|
||||
line(p, cpsStmts, pl)
|
||||
@@ -90,7 +98,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
|
||||
of tyOpenArray, tyVarargs, tyArray, tyArrayConstr:
|
||||
"($1)+($2), ($3)-($2)+1"
|
||||
of tyString, tySequence:
|
||||
if skipTypes(n.typ, abstractInst).kind == tyVar:
|
||||
if skipTypes(n.typ, abstractInst).kind == tyVar and
|
||||
not compileToCpp(p.module):
|
||||
"(*$1)->data+($2), ($3)-($2)+1"
|
||||
else:
|
||||
"$1->data+($2), ($3)-($2)+1"
|
||||
@@ -102,7 +111,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = ropef("$1, $1Len0", [rdLoc(a)])
|
||||
of tyString, tySequence:
|
||||
if skipTypes(n.typ, abstractInst).kind == tyVar:
|
||||
if skipTypes(n.typ, abstractInst).kind == tyVar and
|
||||
not compileToCpp(p.module):
|
||||
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
|
||||
else:
|
||||
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
|
||||
@@ -114,8 +124,8 @@ proc genArgStringToCString(p: BProc, n: PNode): PRope {.inline.} =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
result = ropef("$1->data", [a.rdLoc])
|
||||
|
||||
proc genArg(p: BProc, n: PNode, param: PSym): PRope =
|
||||
|
||||
proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope =
|
||||
var a: TLoc
|
||||
if n.kind == nkStringToCString:
|
||||
result = genArgStringToCString(p, n)
|
||||
@@ -125,8 +135,20 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope =
|
||||
elif ccgIntroducedPtr(param):
|
||||
initLocExpr(p, n, a)
|
||||
result = addrLoc(a)
|
||||
elif p.module.compileToCpp and param.typ.kind == tyVar and
|
||||
n.kind == nkHiddenAddr:
|
||||
initLocExprSingleUse(p, n.sons[0], a)
|
||||
# if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still
|
||||
# means '*T'. See posix.nim for lots of examples that do that in the wild.
|
||||
let callee = call.sons[0]
|
||||
if callee.kind == nkSym and
|
||||
{sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and
|
||||
{lfHeader, lfNoDecl} * callee.sym.loc.flags != {}:
|
||||
result = addrLoc(a)
|
||||
else:
|
||||
result = rdLoc(a)
|
||||
else:
|
||||
initLocExpr(p, n, a)
|
||||
initLocExprSingleUse(p, n, a)
|
||||
result = rdLoc(a)
|
||||
|
||||
proc genArgNoParam(p: BProc, n: PNode): PRope =
|
||||
@@ -134,7 +156,7 @@ proc genArgNoParam(p: BProc, n: PNode): PRope =
|
||||
if n.kind == nkStringToCString:
|
||||
result = genArgStringToCString(p, n)
|
||||
else:
|
||||
initLocExpr(p, n, a)
|
||||
initLocExprSingleUse(p, n, a)
|
||||
result = rdLoc(a)
|
||||
|
||||
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
@@ -152,7 +174,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
if params != nil: app(params, ~", ")
|
||||
if i < sonsLen(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym))
|
||||
app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
|
||||
else:
|
||||
app(params, genArgNoParam(p, ri.sons[i]))
|
||||
fixupCall(p, le, ri, d, op.r, params)
|
||||
@@ -178,7 +200,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
if i < sonsLen(typ):
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym))
|
||||
app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri))
|
||||
else:
|
||||
app(pl, genArgNoParam(p, ri.sons[i]))
|
||||
if i < length - 1: app(pl, ~", ")
|
||||
@@ -274,26 +296,28 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
|
||||
assert(typ.n.sons[i].kind == nkSym)
|
||||
# if the parameter is lying (tyVar) and thus we required an additional deref,
|
||||
# skip the deref:
|
||||
var ri = ri[i]
|
||||
while ri.kind == nkObjDownConv: ri = ri[0]
|
||||
if typ.sons[i].kind == tyVar:
|
||||
let x = if ri[i].kind == nkHiddenAddr: ri[i][0] else: ri[i]
|
||||
if x.kind in {nkHiddenDeref, nkDerefExpr}:
|
||||
result = genArgNoParam(p, x[0])
|
||||
result.app("->")
|
||||
elif x.typ.kind in {tyVar, tyPtr}:
|
||||
let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
|
||||
if x.typ.kind == tyPtr:
|
||||
result = genArgNoParam(p, x)
|
||||
result.app("->")
|
||||
elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
|
||||
result = genArgNoParam(p, x[0])
|
||||
result.app("->")
|
||||
else:
|
||||
result = genArgNoParam(p, x)
|
||||
result.app(".")
|
||||
elif typ.sons[i].kind == tyPtr:
|
||||
if ri.sons[i].kind in {nkAddr, nkHiddenAddr}:
|
||||
result = genArgNoParam(p, ri.sons[i][0])
|
||||
if ri.kind in {nkAddr, nkHiddenAddr}:
|
||||
result = genArgNoParam(p, ri[0])
|
||||
result.app(".")
|
||||
else:
|
||||
result = genArgNoParam(p, ri.sons[i])
|
||||
result = genArgNoParam(p, ri)
|
||||
result.app("->")
|
||||
else:
|
||||
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
|
||||
result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
|
||||
result.app(".")
|
||||
|
||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
||||
@@ -367,12 +391,20 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
# simpler version of 'fixupCall' that works with the pl+params combination:
|
||||
var typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||
if typ.sons[0] != nil:
|
||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.t, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
if p.module.compileToCpp and lfSingleUse in d.flags:
|
||||
# do not generate spurious temporaries for C++! For C we're better off
|
||||
# with them to prevent undefined behaviour and because the codegen
|
||||
# is free to emit expressions multiple times!
|
||||
d.k = locCall
|
||||
d.r = pl
|
||||
excl d.flags, lfSingleUse
|
||||
else:
|
||||
if d.k == locNone: getTemp(p, typ.sons[0], d)
|
||||
assert(d.t != nil) # generate an assignment to d:
|
||||
var list: TLoc
|
||||
initLoc(list, locCall, d.t, OnUnknown)
|
||||
list.r = pl
|
||||
genAssignment(p, d, list, {}) # no need for deep copying
|
||||
else:
|
||||
app(pl, ~";$n")
|
||||
line(p, cpsStmts, pl)
|
||||
@@ -398,15 +430,27 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
assert(typ.kind == tyProc)
|
||||
var length = sonsLen(ri)
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
|
||||
if length > 1:
|
||||
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym))
|
||||
app(pl, ~" ")
|
||||
app(pl, op.r)
|
||||
if length > 2:
|
||||
app(pl, ~": ")
|
||||
app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym))
|
||||
for i in countup(3, length-1):
|
||||
|
||||
# don't call 'ropeToStr' here for efficiency:
|
||||
let pat = ri.sons[0].sym.loc.r.data
|
||||
internalAssert pat != nil
|
||||
var start = 3
|
||||
if ' ' in pat:
|
||||
start = 1
|
||||
app(pl, op.r)
|
||||
if length > 1:
|
||||
app(pl, ~": ")
|
||||
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
|
||||
start = 2
|
||||
else:
|
||||
if length > 1:
|
||||
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri))
|
||||
app(pl, ~" ")
|
||||
app(pl, op.r)
|
||||
if length > 2:
|
||||
app(pl, ~": ")
|
||||
app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri))
|
||||
for i in countup(start, length-1):
|
||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||
if i >= sonsLen(typ):
|
||||
internalError(ri.info, "varargs for objective C method?")
|
||||
@@ -415,7 +459,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||
app(pl, ~" ")
|
||||
app(pl, param.name.s)
|
||||
app(pl, ~": ")
|
||||
app(pl, genArg(p, ri.sons[i], param))
|
||||
app(pl, genArg(p, ri.sons[i], param, ri))
|
||||
if typ.sons[0] != nil:
|
||||
if isInvalidReturnType(typ.sons[0]):
|
||||
if sonsLen(ri) > 1: app(pl, ~" ")
|
||||
|
||||
@@ -56,11 +56,6 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
|
||||
case skipTypes(ty, abstractVarRange).kind
|
||||
of tyChar, tyNil:
|
||||
result = intLiteral(n.intVal)
|
||||
of tyInt:
|
||||
if n.intVal >= low(int32) and n.intVal <= high(int32):
|
||||
result = int32Literal(int32(n.intVal))
|
||||
else:
|
||||
result = intLiteral(n.intVal)
|
||||
of tyBool:
|
||||
if n.intVal != 0: result = ~"NIM_TRUE"
|
||||
else: result = ~"NIM_FALSE"
|
||||
@@ -83,11 +78,13 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
|
||||
else:
|
||||
result = toRope("NIM_NIL")
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if skipTypes(ty, abstractVarRange).kind == tyString:
|
||||
if n.strVal.isNil:
|
||||
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
|
||||
elif skipTypes(ty, abstractVarRange).kind == tyString:
|
||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||
if id == gBackendId:
|
||||
# string literal not found in the cache:
|
||||
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
|
||||
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
|
||||
[getStrLit(p.module, n.strVal)])
|
||||
else:
|
||||
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [toRope(id)])
|
||||
@@ -156,7 +153,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
|
||||
of skVar, skForVar, skResult, skLet:
|
||||
if sfGlobal in n.sym.flags: result = OnHeap
|
||||
else: result = OnStack
|
||||
of skConst:
|
||||
of skConst:
|
||||
if sfGlobal in n.sym.flags: result = OnHeap
|
||||
else: result = OnUnknown
|
||||
else: result = OnUnknown
|
||||
@@ -234,7 +231,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
for i in 0 .. <t.len:
|
||||
let t = t.sons[i]
|
||||
let field = ropef("Field$1", i.toRope)
|
||||
genAssignment(p, optAsgnLoc(dest, t, field),
|
||||
genAssignment(p, optAsgnLoc(dest, t, field),
|
||||
optAsgnLoc(src, t, field), newflags)
|
||||
|
||||
proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
|
||||
@@ -250,20 +247,20 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
|
||||
case t.kind
|
||||
of nkSym:
|
||||
let field = t.sym
|
||||
genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
|
||||
genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r),
|
||||
optAsgnLoc(src, field.typ, field.loc.r), newflags)
|
||||
of nkRecList:
|
||||
for child in items(t): genOptAsgnObject(p, dest, src, newflags, child)
|
||||
else: discard
|
||||
|
||||
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
# Consider:
|
||||
# Consider:
|
||||
# type TMyFastString {.shallow.} = string
|
||||
# Due to the implementation of pragmas this would end up to set the
|
||||
# tfShallow flag for the built-in string type too! So we check only
|
||||
# here for this flag, where it is reasonably safe to do so
|
||||
# (for objects, etc.):
|
||||
if needToCopy notin flags or
|
||||
if needToCopy notin flags or
|
||||
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
|
||||
if dest.s == OnStack or not usesNativeGC():
|
||||
useStringh(p.module)
|
||||
@@ -508,7 +505,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
var storage: PRope
|
||||
var size = getSize(t)
|
||||
if size < platform.intSize:
|
||||
storage = toRope("NI")
|
||||
storage = toRope("NI")
|
||||
else:
|
||||
storage = getTypeDesc(p.module, t)
|
||||
var tmp = getTempName()
|
||||
@@ -545,7 +542,7 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
"(($4)($1) - ($4)($2))", # SubF64
|
||||
"(($4)($1) * ($4)($2))", # MulF64
|
||||
"(($4)($1) / ($4)($2))", # DivF64
|
||||
|
||||
|
||||
"($4)((NU$3)($1) >> (NU$3)($2))", # ShrI
|
||||
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
|
||||
"($4)($1 & $2)", # BitandI
|
||||
@@ -615,7 +612,7 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
if a.t.callConv == ccClosure:
|
||||
putIntoDest(p, d, e.typ,
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropef("($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)", [
|
||||
rdLoc(a), rdLoc(b)]))
|
||||
else:
|
||||
@@ -662,9 +659,14 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
|
||||
getSimpleTypeDesc(p.module, e.typ)]))
|
||||
|
||||
proc isCppRef(p: BProc; typ: PType): bool {.inline.} =
|
||||
result = p.module.compileToCpp and
|
||||
skipTypes(typ, abstractInst).kind == tyVar and
|
||||
tfVarIsPtr notin skipTypes(typ, abstractInst).flags
|
||||
|
||||
proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||
let mt = mapType(e.sons[0].typ)
|
||||
if mt in {ctArray, ctPtrToArray} and not enforceDeref:
|
||||
if (mt in {ctArray, ctPtrToArray} and not enforceDeref):
|
||||
# XXX the amount of hacks for C's arrays is incredible, maybe we should
|
||||
# simply wrap them in a struct? --> Losing auto vectorization then?
|
||||
#if e[0].kind != nkBracketExpr:
|
||||
@@ -672,12 +674,17 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||
expr(p, e.sons[0], d)
|
||||
else:
|
||||
var a: TLoc
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
case skipTypes(a.t, abstractInst).kind
|
||||
initLocExprSingleUse(p, e.sons[0], a)
|
||||
let typ = skipTypes(a.t, abstractInst)
|
||||
case typ.kind
|
||||
of tyRef:
|
||||
d.s = OnHeap
|
||||
of tyVar:
|
||||
d.s = OnUnknown
|
||||
if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
|
||||
e.kind == nkHiddenDeref:
|
||||
putIntoDest(p, d, e.typ, rdLoc(a))
|
||||
return
|
||||
of tyPtr:
|
||||
d.s = OnUnknown # BUGFIX!
|
||||
else: internalError(e.info, "genDeref " & $a.t.kind)
|
||||
@@ -698,7 +705,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
putIntoDest(p, d, e.typ, con("&", a.r))
|
||||
#Message(e.info, warnUser, "HERE NEW &")
|
||||
elif mapType(e.sons[0].typ) == ctArray:
|
||||
elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
|
||||
expr(p, e.sons[0], d)
|
||||
else:
|
||||
var a: TLoc
|
||||
@@ -709,7 +716,7 @@ template inheritLocation(d: var TLoc, a: TLoc) =
|
||||
if d.k == locNone: d.s = a.s
|
||||
if d.heapRoot == nil:
|
||||
d.heapRoot = if a.heapRoot != nil: a.heapRoot else: a.r
|
||||
|
||||
|
||||
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
|
||||
@@ -916,6 +923,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
L: TLabel
|
||||
tmp: TLoc
|
||||
getTemp(p, e.typ, tmp) # force it into a temp!
|
||||
inc p.splitDecls
|
||||
expr(p, e.sons[1], tmp)
|
||||
L = getLabel(p)
|
||||
if m == mOr:
|
||||
@@ -928,6 +936,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
d = tmp
|
||||
else:
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
dec p.splitDecls
|
||||
|
||||
proc genEcho(p: BProc, n: PNode) =
|
||||
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||
@@ -938,7 +947,7 @@ proc genEcho(p: BProc, n: PNode) =
|
||||
var a: TLoc
|
||||
for i in countup(0, n.len-1):
|
||||
initLocExpr(p, n.sons[i], a)
|
||||
appf(args, ", ($1)->data", [rdLoc(a)])
|
||||
appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
|
||||
linefmt(p, cpsStmts, "printf($1$2);$n",
|
||||
makeCString(repeatStr(n.len, "%s") & tnl), args)
|
||||
|
||||
@@ -1047,7 +1056,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
|
||||
gcUsage(e)
|
||||
|
||||
proc genReset(p: BProc, n: PNode) =
|
||||
proc genReset(p: BProc, n: PNode) =
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[1], a)
|
||||
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
||||
@@ -1106,14 +1115,14 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) =
|
||||
else:
|
||||
call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args)
|
||||
genAssignment(p, dest, call, {needToKeepAlive})
|
||||
|
||||
|
||||
proc genNewSeq(p: BProc, e: PNode) =
|
||||
var a, b: TLoc
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
genNewSeqAux(p, a, b.rdLoc)
|
||||
gcUsage(e)
|
||||
|
||||
|
||||
proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
var tmp: TLoc
|
||||
var t = e.typ.skipTypes(abstractInst)
|
||||
@@ -1154,7 +1163,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
d = tmp
|
||||
else:
|
||||
genAssignment(p, d, tmp, {})
|
||||
|
||||
|
||||
proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
|
||||
var arr: TLoc
|
||||
if d.k == locNone:
|
||||
@@ -1178,7 +1187,7 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
|
||||
getTemp(p, t.typ, d)
|
||||
# generate call to newSeq before adding the elements per hand:
|
||||
var L = int(lengthOrd(t.sons[1].typ))
|
||||
|
||||
|
||||
genNewSeqAux(p, d, intLiteral(L))
|
||||
initLocExpr(p, t.sons[1], a)
|
||||
for i in countup(0, L - 1):
|
||||
@@ -1188,7 +1197,7 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
|
||||
initLoc(arr, locExpr, elemType(skipTypes(t.sons[1].typ, abstractInst)), a.s)
|
||||
arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i))
|
||||
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
|
||||
|
||||
|
||||
proc genNewFinalize(p: BProc, e: PNode) =
|
||||
var
|
||||
a, b, f: TLoc
|
||||
@@ -1236,14 +1245,15 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||
var t = skipTypes(a.t, abstractInst)
|
||||
while t.kind in {tyVar, tyPtr, tyRef}:
|
||||
if t.kind != tyVar: nilCheck = r
|
||||
r = rfmt(nil, "(*$1)", r)
|
||||
if t.kind != tyVar or not p.module.compileToCpp:
|
||||
r = rfmt(nil, "(*$1)", r)
|
||||
t = skipTypes(t.lastSon, typedescInst)
|
||||
if not p.module.compileToCpp:
|
||||
while t.kind == tyObject and t.sons[0] != nil:
|
||||
app(r, ~".Sup")
|
||||
t = skipTypes(t.sons[0], typedescInst)
|
||||
if isObjLackingTypeField(t):
|
||||
globalError(x.info, errGenerated,
|
||||
globalError(x.info, errGenerated,
|
||||
"no 'of' operator available for pure objects")
|
||||
if nilCheck != nil:
|
||||
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
|
||||
@@ -1260,7 +1270,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
var t = skipTypes(e.sons[1].typ, abstractVarRange)
|
||||
case t.kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
putIntoDest(p, d, e.typ,
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]))
|
||||
of tyFloat..tyFloat128:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]))
|
||||
@@ -1283,13 +1293,13 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
of tyOpenArray, tyVarargs:
|
||||
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
|
||||
of tyString, tySequence:
|
||||
putIntoDest(p, b, e.typ,
|
||||
putIntoDest(p, b, e.typ,
|
||||
ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)]))
|
||||
of tyArray, tyArrayConstr:
|
||||
putIntoDest(p, b, e.typ,
|
||||
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
|
||||
else: internalError(e.sons[0].info, "genRepr()")
|
||||
putIntoDest(p, d, e.typ,
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
|
||||
genTypeInfo(p.module, elemType(t))]))
|
||||
of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil,
|
||||
@@ -1375,7 +1385,7 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
|
||||
genAssignment(p, b, tmp, {})
|
||||
|
||||
proc rdSetElemLoc(a: TLoc, setType: PType): PRope =
|
||||
# read a location of an set element; it may need a substraction operation
|
||||
# read a location of an set element; it may need a subtraction operation
|
||||
# before the set operation
|
||||
result = rdCharLoc(a)
|
||||
assert(setType.kind == tySet)
|
||||
@@ -1418,7 +1428,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
|
||||
# do not emit the set, but generate a bunch of comparisons; and if we do
|
||||
# so, we skip the unnecessary range check: This is a semantical extension
|
||||
# that code now relies on. :-/ XXX
|
||||
let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}:
|
||||
let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}:
|
||||
e.sons[2].sons[0]
|
||||
else:
|
||||
e.sons[2]
|
||||
@@ -1503,7 +1513,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
if d.k == locNone: getTemp(p, a.t, d)
|
||||
lineF(p, cpsStmts,
|
||||
"for ($1 = 0; $1 < $2; $1++) $n" &
|
||||
"for ($1 = 0; $1 < $2; $1++) $n" &
|
||||
" $3[$1] = $4[$1] $6 $5[$1];$n", [
|
||||
rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b),
|
||||
toRope(lookupOpr[op])])
|
||||
@@ -1534,7 +1544,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
|
||||
proc genCast(p: BProc, e: PNode, d: var TLoc) =
|
||||
const floatTypes = {tyFloat..tyFloat128}
|
||||
let
|
||||
let
|
||||
destt = skipTypes(e.typ, abstractRange)
|
||||
srct = skipTypes(e.sons[1].typ, abstractRange)
|
||||
if destt.kind in floatTypes or srct.kind in floatTypes:
|
||||
@@ -1641,7 +1651,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mRepr: genRepr(p, e, d)
|
||||
of mGetTypeInfo: genGetTypeInfo(p, e, d)
|
||||
of mSwap: genSwap(p, e, d)
|
||||
of mUnaryLt:
|
||||
of mUnaryLt:
|
||||
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
|
||||
else: unaryExpr(p, e, d, "#subInt($1, 1)")
|
||||
of mPred:
|
||||
@@ -1815,10 +1825,10 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
proc isConstClosure(n: PNode): bool {.inline.} =
|
||||
result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and
|
||||
n.sons[1].kind == nkNilLit
|
||||
|
||||
|
||||
proc genClosure(p: BProc, n: PNode, d: var TLoc) =
|
||||
assert n.kind == nkClosure
|
||||
|
||||
|
||||
if isConstClosure(n):
|
||||
inc(p.labels)
|
||||
var tmp = con("LOC", toRope(p.labels))
|
||||
@@ -1863,7 +1873,8 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
|
||||
var t = skipTypes(a.t, abstractInst)
|
||||
while t.kind in {tyVar, tyPtr, tyRef}:
|
||||
if t.kind != tyVar: nilCheck = r
|
||||
r = ropef("(*$1)", [r])
|
||||
if t.kind != tyVar or not p.module.compileToCpp:
|
||||
r = ropef("(*$1)", [r])
|
||||
t = skipTypes(t.lastSon, abstractInst)
|
||||
if not p.module.compileToCpp:
|
||||
while t.kind == tyObject and t.sons[0] != nil:
|
||||
@@ -1904,7 +1915,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
|
||||
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:
|
||||
# (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}:
|
||||
@@ -1921,13 +1932,13 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
|
||||
discard getTypeDesc(p.module, t) # so that any fields are initialized
|
||||
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
|
||||
var tmp = con("TMP", toRope(id))
|
||||
|
||||
|
||||
if id == gBackendId:
|
||||
# expression not found in the cache:
|
||||
inc(gBackendId)
|
||||
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
|
||||
|
||||
|
||||
if d.k == locNone:
|
||||
fillLoc(d, locData, t, tmp, OnHeap)
|
||||
else:
|
||||
@@ -1968,7 +1979,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
|
||||
if sfThread in sym.flags:
|
||||
accessThreadLocalVar(p, sym)
|
||||
if emulatedThreadVars():
|
||||
if emulatedThreadVars():
|
||||
putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r))
|
||||
else:
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
@@ -1985,7 +1996,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
#echo "FAILED FOR PRCO ", p.prc.name.s
|
||||
#debug p.prc.typ.n
|
||||
#echo renderTree(p.prc.ast, {renderIds})
|
||||
internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
|
||||
internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
|
||||
of nkNilLit:
|
||||
@@ -2073,8 +2084,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
genAsgn(p, n, fastAsgn=p.prc != nil)
|
||||
of nkDiscardStmt:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
var a: TLoc
|
||||
genLineDir(p, n)
|
||||
var a: TLoc
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
of nkAsmStmt: genAsmStmt(p, n)
|
||||
of nkTryStmt:
|
||||
@@ -2085,29 +2096,25 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
# we have to emit the type information for object types here to support
|
||||
# separate compilation:
|
||||
genTypeSection(p.module, n)
|
||||
of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef:
|
||||
of nkCommentStmt, nkIteratorDef, nkIncludeStmt,
|
||||
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
|
||||
nkFromStmt, nkTemplateDef, nkMacroDef:
|
||||
discard
|
||||
of nkPragma: genPragma(p, n)
|
||||
of nkPragmaBlock: expr(p, n.lastSon, d)
|
||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||
if (n.sons[genericParamsPos].kind == nkEmpty):
|
||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||
if n.sons[genericParamsPos].kind == nkEmpty:
|
||||
var prc = n.sons[namePos].sym
|
||||
# due to a bug/limitation in the lambda lifting, unused inner procs
|
||||
# are not transformed correctly. We work around this issue (#411) here
|
||||
# by ensuring it's no inner proc (owner is a module):
|
||||
#
|
||||
# We also check whether the proc captures its environment here to
|
||||
# prevent issue #1642.
|
||||
if prc.skipGenericOwner.kind == skModule and
|
||||
tfCapturesEnv in prc.typ.flags:
|
||||
if prc.skipGenericOwner.kind == skModule:
|
||||
if (optDeadCodeElim notin gGlobalOptions and
|
||||
sfDeadCodeElim notin getModule(prc).flags) or
|
||||
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
|
||||
(sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
|
||||
(prc.kind == skMethod):
|
||||
# we have not only the header:
|
||||
(prc.kind == skMethod):
|
||||
# we have not only the header:
|
||||
if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags:
|
||||
genProc(p.module, prc)
|
||||
of nkParForStmt: genParForStmt(p, n)
|
||||
@@ -2130,7 +2137,7 @@ proc genConstSimpleList(p: BProc, n: PNode): PRope =
|
||||
|
||||
proc genConstSeq(p: BProc, n: PNode, t: PType): PRope =
|
||||
var data = ropef("{{$1, $1}", n.len.toRope)
|
||||
if n.len > 0:
|
||||
if n.len > 0:
|
||||
# array part needs extra curlies:
|
||||
data.app(", {")
|
||||
for i in countup(0, n.len - 1):
|
||||
@@ -2138,14 +2145,14 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): PRope =
|
||||
data.app genConstExpr(p, n.sons[i])
|
||||
data.app("}")
|
||||
data.app("}")
|
||||
|
||||
|
||||
inc(gBackendId)
|
||||
result = con("CNSTSEQ", gBackendId.toRope)
|
||||
|
||||
|
||||
appcg(p.module, cfsData,
|
||||
"NIM_CONST struct {$n" &
|
||||
"NIM_CONST struct {$n" &
|
||||
" #TGenericSeq Sup;$n" &
|
||||
" $1 data[$2];$n" &
|
||||
" $1 data[$2];$n" &
|
||||
"} $3 = $4;$n", [
|
||||
getTypeDesc(p.module, t.sons[0]), n.len.toRope, result, data])
|
||||
|
||||
@@ -2159,7 +2166,7 @@ proc genConstExpr(p: BProc, n: PNode): PRope =
|
||||
var cs: TBitSet
|
||||
toBitSet(n, cs)
|
||||
result = genRawSetData(cs, int(getSize(n.typ)))
|
||||
of nkBracket, nkPar, nkClosure:
|
||||
of nkBracket, nkPar, nkClosure, nkObjConstr:
|
||||
var t = skipTypes(n.typ, abstractInst)
|
||||
if t.kind == tySequence:
|
||||
result = genConstSeq(p, n, t)
|
||||
|
||||
@@ -223,7 +223,7 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
|
||||
of "typeInfo": readIntSet(L, m.typeInfoMarker)
|
||||
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
|
||||
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0
|
||||
else: internalError("ccgmerge: unkown key: " & k)
|
||||
else: internalError("ccgmerge: unknown key: " & k)
|
||||
|
||||
when not defined(nimhygiene):
|
||||
{.pragma: inject.}
|
||||
|
||||
@@ -48,7 +48,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
return
|
||||
genLineDir(p, n)
|
||||
initLocExpr(p, n.sons[L-1], tup)
|
||||
var t = tup.t
|
||||
var t = tup.t.getUniqueType
|
||||
for i in countup(0, L-3):
|
||||
var v = n.sons[i].sym
|
||||
if sfCompileTime in v.flags: continue
|
||||
@@ -202,8 +202,20 @@ proc genSingleVar(p: BProc, a: PNode) =
|
||||
genVarPrototypeAux(generatedHeader, v)
|
||||
registerGcRoot(p, v)
|
||||
else:
|
||||
let imm = isAssignedImmediately(a.sons[2])
|
||||
if imm and p.module.compileToCpp and p.splitDecls == 0 and
|
||||
not containsHiddenPointer(v.typ):
|
||||
# C++ really doesn't like things like 'Foo f; f = x' as that invokes a
|
||||
# parameterless constructor followed by an assignment operator. So we
|
||||
# generate better code here:
|
||||
genLineDir(p, a)
|
||||
let decl = localVarDecl(p, v)
|
||||
var tmp: TLoc
|
||||
initLocExprSingleUse(p, a.sons[2], tmp)
|
||||
lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc)
|
||||
return
|
||||
assignLocalVar(p, v)
|
||||
initLocalVar(p, v, isAssignedImmediately(a.sons[2]))
|
||||
initLocalVar(p, v, imm)
|
||||
|
||||
if a.sons[2].kind != nkEmpty:
|
||||
genLineDir(targetProc, a)
|
||||
@@ -242,16 +254,7 @@ proc genConstStmt(p: BProc, t: PNode) =
|
||||
elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
|
||||
c.ast.len != 0:
|
||||
if not emitLazily(c): requestConstImpl(p, c)
|
||||
when false:
|
||||
# generate the data:
|
||||
fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown)
|
||||
if sfImportc in c.flags:
|
||||
appf(p.module.s[cfsData], "extern NIM_CONST $1 $2;$n",
|
||||
[getTypeDesc(p.module, c.typ), c.loc.r])
|
||||
else:
|
||||
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
|
||||
[getTypeDesc(p.module, c.typ), c.loc.r, genConstExpr(p, c.ast)])
|
||||
|
||||
|
||||
proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
#
|
||||
# { if (!expr1) goto L1;
|
||||
@@ -275,17 +278,22 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
let it = n.sons[i]
|
||||
if it.len == 2:
|
||||
when newScopeForIf: startBlock(p)
|
||||
initLocExpr(p, it.sons[0], a)
|
||||
initLocExprSingleUse(p, it.sons[0], a)
|
||||
lelse = getLabel(p)
|
||||
inc(p.labels)
|
||||
lineFF(p, cpsStmts, "if (!$1) goto $2;$n",
|
||||
"br i1 $1, label %LOC$3, label %$2$nLOC$3: $n",
|
||||
[rdLoc(a), lelse, toRope(p.labels)])
|
||||
lineF(p, cpsStmts, "if (!$1) goto $2;$n",
|
||||
[rdLoc(a), lelse])
|
||||
when not newScopeForIf: startBlock(p)
|
||||
expr(p, it.sons[1], d)
|
||||
if p.module.compileToCpp:
|
||||
# avoid "jump to label crosses initialization" error:
|
||||
app(p.s(cpsStmts), "{")
|
||||
expr(p, it.sons[1], d)
|
||||
app(p.s(cpsStmts), "}")
|
||||
else:
|
||||
expr(p, it.sons[1], d)
|
||||
endBlock(p)
|
||||
if sonsLen(n) > 1:
|
||||
lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [lend])
|
||||
lineF(p, cpsStmts, "goto $1;$n", [lend])
|
||||
fixLabel(p, lelse)
|
||||
elif it.len == 1:
|
||||
startBlock(p)
|
||||
@@ -344,7 +352,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
||||
# consume it before we return.
|
||||
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint)
|
||||
lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
|
||||
lineF(p, cpsStmts, "goto BeforeRet;$n", [])
|
||||
|
||||
proc genComputedGoto(p: BProc; n: PNode) =
|
||||
# first pass: Generate array of computed labels:
|
||||
|
||||
@@ -27,17 +27,7 @@ proc isKeyword(w: PIdent): bool =
|
||||
|
||||
proc mangleName(s: PSym): PRope =
|
||||
result = s.loc.r
|
||||
if result == nil:
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
case s.kind
|
||||
of skProc, skMethod, skConverter, skConst, skIterators:
|
||||
result = ~"@"
|
||||
of skVar, skForVar, skResult, skLet:
|
||||
if sfGlobal in s.flags: result = ~"@"
|
||||
else: result = ~"%"
|
||||
of skTemp, skParam, skType, skEnumField, skModule:
|
||||
result = ~"%"
|
||||
else: internalError(s.info, "mangleName")
|
||||
if result == nil:
|
||||
when oKeepVariableNames:
|
||||
let keepOrigName = s.kind in skLocalVars - {skForVar} and
|
||||
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
|
||||
@@ -103,13 +93,11 @@ proc typeName(typ: PType): PRope =
|
||||
else: ~"TY"
|
||||
|
||||
proc getTypeName(typ: PType): PRope =
|
||||
if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and
|
||||
(gCmd != cmdCompileToLLVM):
|
||||
if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}:
|
||||
result = typ.sym.loc.r
|
||||
else:
|
||||
if typ.loc.r == nil:
|
||||
typ.loc.r = if gCmd != cmdCompileToLLVM: con(typ.typeName, typ.id.toRope)
|
||||
else: con([~"%", typ.typeName, typ.id.toRope])
|
||||
typ.loc.r = con(typ.typeName, typ.id.toRope)
|
||||
result = typ.loc.r
|
||||
if result == nil: internalError("getTypeName: " & $typ.kind)
|
||||
|
||||
@@ -161,7 +149,13 @@ proc mapType(typ: PType): TCTypeKind =
|
||||
proc mapReturnType(typ: PType): TCTypeKind =
|
||||
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
|
||||
else: result = mapType(typ)
|
||||
|
||||
|
||||
proc isImportedType(t: PType): bool =
|
||||
result = t.sym != nil and sfImportc in t.sym.flags
|
||||
|
||||
proc isImportedCppType(t: PType): bool =
|
||||
result = t.sym != nil and sfInfixCall in t.sym.flags
|
||||
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
|
||||
proc needsComplexAssignment(typ: PType): bool =
|
||||
result = containsGarbageCollectedRef(typ)
|
||||
@@ -170,19 +164,20 @@ 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
|
||||
# such a poor programming language.
|
||||
# We exclude records with refs too. This enhances efficiency and
|
||||
# is necessary for proper code generation of assignments.
|
||||
if rettype == nil: result = true
|
||||
else:
|
||||
else:
|
||||
case mapType(rettype)
|
||||
of ctArray:
|
||||
of ctArray:
|
||||
result = not (skipTypes(rettype, typedescInst).kind in
|
||||
{tyVar, tyRef, tyPtr})
|
||||
of ctStruct:
|
||||
let t = skipTypes(rettype, typedescInst)
|
||||
if rettype.isImportedCppType or t.isImportedCppType: return false
|
||||
result = needsComplexAssignment(t) or
|
||||
(t.kind == tyObject and not isObjLackingTypeField(t))
|
||||
else: result = false
|
||||
@@ -193,9 +188,6 @@ const
|
||||
"N_SYSCALL", # this is probably not correct for all platforms,
|
||||
# but one can #define it to what one wants
|
||||
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"]
|
||||
CallingConvToStrLLVM: array[TCallingConvention, string] = ["fastcc $1",
|
||||
"stdcall $1", "ccc $1", "safecall $1", "syscall $1", "$1 alwaysinline",
|
||||
"$1 noinline", "fastcc $1", "ccc $1", "$1"]
|
||||
|
||||
proc cacheGetType(tab: TIdTable, key: PType): PRope =
|
||||
# returns nil if we need to declare this type
|
||||
@@ -234,77 +226,8 @@ proc fillResult(param: PSym) =
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.s = OnUnknown
|
||||
|
||||
proc getParamTypeDesc(m: BModule, t: PType, check: var IntSet): PRope =
|
||||
when false:
|
||||
if t.Kind in {tyRef, tyPtr, tyVar}:
|
||||
var b = skipTypes(t.lastson, typedescInst)
|
||||
if b.kind == tySet and mapSetType(b) == ctArray:
|
||||
return getTypeDescAux(m, b, check)
|
||||
result = getTypeDescAux(m, t, check)
|
||||
|
||||
proc paramStorageLoc(param: PSym): TStorageLoc =
|
||||
if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}:
|
||||
result = OnStack
|
||||
else:
|
||||
result = OnUnknown
|
||||
|
||||
proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
check: var IntSet, declareEnvironment=true) =
|
||||
params = nil
|
||||
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
|
||||
rettype = ~"void"
|
||||
else:
|
||||
rettype = getTypeDescAux(m, t.sons[0], check)
|
||||
for i in countup(1, sonsLen(t.n) - 1):
|
||||
if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
|
||||
var param = t.n.sons[i].sym
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
if params != nil: app(params, ~", ")
|
||||
fillLoc(param.loc, locParam, param.typ, mangleName(param),
|
||||
param.paramStorageLoc)
|
||||
app(params, getParamTypeDesc(m, param.typ, check))
|
||||
if ccgIntroducedPtr(param):
|
||||
app(params, ~"*")
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.s = OnUnknown
|
||||
app(params, ~" ")
|
||||
app(params, param.loc.r)
|
||||
# declare the len field for open arrays:
|
||||
var arr = param.typ
|
||||
if arr.kind == tyVar: arr = arr.sons[0]
|
||||
var j = 0
|
||||
while arr.kind in {tyOpenArray, tyVarargs}:
|
||||
# this fixes the 'sort' bug:
|
||||
if param.typ.kind == tyVar: param.loc.s = OnUnknown
|
||||
# need to pass hidden parameter:
|
||||
appff(params, ", NI $1Len$2", ", @NI $1Len$2", [param.loc.r, j.toRope])
|
||||
inc(j)
|
||||
arr = arr.sons[0]
|
||||
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
|
||||
var arr = t.sons[0]
|
||||
if params != nil: app(params, ", ")
|
||||
app(params, getTypeDescAux(m, arr, check))
|
||||
if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM):
|
||||
app(params, "*")
|
||||
appff(params, " Result", " @Result", [])
|
||||
if t.callConv == ccClosure and declareEnvironment:
|
||||
if params != nil: app(params, ", ")
|
||||
app(params, "void* ClEnv")
|
||||
if tfVarargs in t.flags:
|
||||
if params != nil: app(params, ", ")
|
||||
app(params, "...")
|
||||
if params == nil and gCmd != cmdCompileToLLVM: app(params, "void)")
|
||||
else: app(params, ")")
|
||||
params = con("(", params)
|
||||
|
||||
proc isImportedType(t: PType): bool =
|
||||
result = t.sym != nil and sfImportc in t.sym.flags
|
||||
|
||||
proc isImportedCppType(t: PType): bool =
|
||||
result = t.sym != nil and sfInfixCall in t.sym.flags
|
||||
|
||||
proc typeNameOrLiteral(t: PType, literal: string): PRope =
|
||||
if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone):
|
||||
if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
|
||||
result = getTypeName(t)
|
||||
else:
|
||||
result = toRope(literal)
|
||||
@@ -341,7 +264,10 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
|
||||
result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind])
|
||||
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
|
||||
else: result = nil
|
||||
|
||||
|
||||
proc pushType(m: BModule, typ: PType) =
|
||||
add(m.typeStack, typ)
|
||||
|
||||
proc getTypePre(m: BModule, typ: PType): PRope =
|
||||
if typ == nil: result = toRope("void")
|
||||
else:
|
||||
@@ -368,6 +294,81 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
|
||||
[structOrUnion(typ), result])
|
||||
idTablePut(m.forwTypeCache, typ, result)
|
||||
else: internalError("getTypeForward(" & $typ.kind & ')')
|
||||
|
||||
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): PRope =
|
||||
## like getTypeDescAux but creates only a *weak* dependency. In other words
|
||||
## we know we only need a pointer to it so we only generate a struct forward
|
||||
## declaration:
|
||||
var etB = t.skipTypes(abstractInst)
|
||||
case etB.kind
|
||||
of tyObject, tyTuple:
|
||||
if isImportedCppType(etB) and t.kind == tyGenericInst:
|
||||
result = getTypeDescAux(m, t, check)
|
||||
else:
|
||||
let x = getUniqueType(etB)
|
||||
result = getTypeForward(m, x)
|
||||
pushType(m, x)
|
||||
else:
|
||||
result = getTypeDescAux(m, t, check)
|
||||
|
||||
proc paramStorageLoc(param: PSym): TStorageLoc =
|
||||
if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}:
|
||||
result = OnStack
|
||||
else:
|
||||
result = OnUnknown
|
||||
|
||||
proc genProcParams(m: BModule, t: PType, rettype, params: var PRope,
|
||||
check: var IntSet, declareEnvironment=true) =
|
||||
params = nil
|
||||
if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]):
|
||||
rettype = ~"void"
|
||||
else:
|
||||
rettype = getTypeDescAux(m, t.sons[0], check)
|
||||
for i in countup(1, sonsLen(t.n) - 1):
|
||||
if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
|
||||
var param = t.n.sons[i].sym
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
if params != nil: app(params, ~", ")
|
||||
fillLoc(param.loc, locParam, param.typ, mangleName(param),
|
||||
param.paramStorageLoc)
|
||||
if ccgIntroducedPtr(param):
|
||||
app(params, getTypeDescWeak(m, param.typ, check))
|
||||
app(params, ~"*")
|
||||
incl(param.loc.flags, lfIndirect)
|
||||
param.loc.s = OnUnknown
|
||||
else:
|
||||
app(params, getTypeDescAux(m, param.typ, check))
|
||||
app(params, ~" ")
|
||||
app(params, param.loc.r)
|
||||
# declare the len field for open arrays:
|
||||
var arr = param.typ
|
||||
if arr.kind == tyVar: arr = arr.sons[0]
|
||||
var j = 0
|
||||
while arr.kind in {tyOpenArray, tyVarargs}:
|
||||
# this fixes the 'sort' bug:
|
||||
if param.typ.kind == tyVar: param.loc.s = OnUnknown
|
||||
# need to pass hidden parameter:
|
||||
appf(params, ", NI $1Len$2", [param.loc.r, j.toRope])
|
||||
inc(j)
|
||||
arr = arr.sons[0]
|
||||
if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]):
|
||||
var arr = t.sons[0]
|
||||
if params != nil: app(params, ", ")
|
||||
if (mapReturnType(t.sons[0]) != ctArray):
|
||||
app(params, getTypeDescWeak(m, arr, check))
|
||||
app(params, "*")
|
||||
else:
|
||||
app(params, getTypeDescAux(m, arr, check))
|
||||
appf(params, " Result", [])
|
||||
if t.callConv == ccClosure and declareEnvironment:
|
||||
if params != nil: app(params, ", ")
|
||||
app(params, "void* ClEnv")
|
||||
if tfVarargs in t.flags:
|
||||
if params != nil: app(params, ", ")
|
||||
app(params, "...")
|
||||
if params == nil: app(params, "void)")
|
||||
else: app(params, ")")
|
||||
params = con("(", params)
|
||||
|
||||
proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
|
||||
if (rectype.sym != nil) and
|
||||
@@ -421,14 +422,18 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
|
||||
else: ae = sname
|
||||
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
|
||||
let fieldType = field.loc.t.skipTypes(abstractInst)
|
||||
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
||||
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
||||
else:
|
||||
# don't use fieldType here because we need the
|
||||
# tyGenericInst for C++ template support
|
||||
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
|
||||
# for importcpp'ed objects, we only need to set field.loc, but don't
|
||||
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
|
||||
# with heavily templatized C++ code:
|
||||
if not isImportedCppType(rectype):
|
||||
let fieldType = field.loc.t.skipTypes(abstractInst)
|
||||
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
||||
appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
||||
else:
|
||||
# don't use fieldType here because we need the
|
||||
# tyGenericInst for C++ template support
|
||||
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
|
||||
else: internalError(n.info, "genRecordFieldsAux()")
|
||||
|
||||
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
@@ -483,9 +488,6 @@ proc getTupleDesc(m: BModule, typ: PType, name: PRope,
|
||||
else: app(result, desc)
|
||||
app(result, "};" & tnl)
|
||||
|
||||
proc pushType(m: BModule, typ: PType) =
|
||||
add(m.typeStack, typ)
|
||||
|
||||
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
# returns only the type's name
|
||||
var t = getUniqueType(typ)
|
||||
@@ -493,13 +495,16 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
if t.sym != nil: useHeader(m, t.sym)
|
||||
result = getTypePre(m, t)
|
||||
if result != nil: return
|
||||
if containsOrIncl(check, t.id):
|
||||
if containsOrIncl(check, t.id):
|
||||
if isImportedCppType(typ) or isImportedCppType(t): return
|
||||
internalError("cannot generate C type for: " & typeToString(typ))
|
||||
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
|
||||
# but determining when this needs to be done is hard. We should split
|
||||
# C type generation into an analysis and a code generation phase somehow.
|
||||
case t.kind
|
||||
of tyRef, tyPtr, tyVar:
|
||||
of tyRef, tyPtr, tyVar:
|
||||
var star = if t.kind == tyVar and tfVarIsPtr notin typ.flags and
|
||||
compileToCpp(m): "&" else: "*"
|
||||
var et = t.lastSon
|
||||
var etB = et.skipTypes(abstractInst)
|
||||
if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}:
|
||||
@@ -507,27 +512,28 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
|
||||
# ``var set[char]`` in `getParamTypeDesc`
|
||||
et = elemType(etB)
|
||||
etB = et.skipTypes(abstractInst)
|
||||
star[0] = '*'
|
||||
case etB.kind
|
||||
of tyObject, tyTuple:
|
||||
if isImportedCppType(etB) and et.kind == tyGenericInst:
|
||||
result = con(getTypeDescAux(m, et, check), "*")
|
||||
result = con(getTypeDescAux(m, et, check), star)
|
||||
else:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
let x = getUniqueType(etB)
|
||||
let name = getTypeForward(m, x)
|
||||
result = con(name, "*")
|
||||
result = con(name, star)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
pushType(m, x)
|
||||
of tySequence:
|
||||
# no restriction! We have a forward declaration for structs
|
||||
let x = getUniqueType(etB)
|
||||
let name = getTypeForward(m, x)
|
||||
result = con(name, "**")
|
||||
result = con(name, "*" & star)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
pushType(m, x)
|
||||
else:
|
||||
# else we have a strong dependency :-(
|
||||
result = con(getTypeDescAux(m, et, check), "*")
|
||||
result = con(getTypeDescAux(m, et, check), star)
|
||||
idTablePut(m.typeCache, t, result)
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = con(getTypeDescAux(m, t.sons[0], check), "*")
|
||||
@@ -670,7 +676,7 @@ proc genProcHeader(m: BModule, prc: PSym): PRope =
|
||||
rettype, params: PRope
|
||||
genCLineDir(result, prc.info)
|
||||
# using static is needed for inline procs
|
||||
if gCmd != cmdCompileToLLVM and lfExportLib in prc.loc.flags:
|
||||
if lfExportLib in prc.loc.flags:
|
||||
if m.isHeaderFile:
|
||||
result.app "N_LIB_IMPORT "
|
||||
else:
|
||||
@@ -696,16 +702,7 @@ proc getNimNode(m: BModule): PRope =
|
||||
result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
|
||||
inc(m.typeNodes)
|
||||
|
||||
when false:
|
||||
proc getNimType(m: BModule): PRope =
|
||||
result = ropef("$1[$2]", [m.nimTypesName, toRope(m.nimTypes)])
|
||||
inc(m.nimTypes)
|
||||
|
||||
proc allocMemTI(m: BModule, typ: PType, name: PRope) =
|
||||
var tmp = getNimType(m)
|
||||
appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name])
|
||||
|
||||
proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
||||
proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
|
||||
var nimtypeKind: int
|
||||
#allocMemTI(m, typ, name)
|
||||
if isObjLackingTypeField(typ):
|
||||
@@ -715,6 +712,7 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
||||
|
||||
var size: PRope
|
||||
if tfIncompleteStruct in typ.flags: size = toRope"void*"
|
||||
elif m.compileToCpp: size = getTypeDesc(m, origType)
|
||||
else: size = getTypeDesc(m, typ)
|
||||
appf(m.s[cfsTypeInit3],
|
||||
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n",
|
||||
@@ -730,13 +728,13 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
|
||||
appf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
|
||||
[name, toRope(typeToString(typ))])
|
||||
|
||||
proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) =
|
||||
proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) =
|
||||
var base: PRope
|
||||
if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
|
||||
base = genTypeInfo(m, typ.sons[0])
|
||||
else:
|
||||
base = toRope("0")
|
||||
genTypeInfoAuxBase(m, typ, name, base)
|
||||
genTypeInfoAuxBase(m, typ, origType, name, base)
|
||||
|
||||
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
|
||||
# bugfix: we need to search the type that contains the discriminator:
|
||||
@@ -814,11 +812,12 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) =
|
||||
field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
|
||||
else: internalError(n.info, "genObjectFields")
|
||||
|
||||
proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
|
||||
if typ.kind == tyObject: genTypeInfoAux(m, typ, name)
|
||||
else: genTypeInfoAuxBase(m, typ, name, toRope("0"))
|
||||
proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) =
|
||||
if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
|
||||
else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0"))
|
||||
var tmp = getNimNode(m)
|
||||
genObjectFields(m, typ, typ.n, tmp)
|
||||
if not isImportedCppType(typ):
|
||||
genObjectFields(m, typ, typ.n, tmp)
|
||||
appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
|
||||
var t = typ.sons[0]
|
||||
while t != nil:
|
||||
@@ -827,7 +826,7 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
|
||||
t = t.sons[0]
|
||||
|
||||
proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
|
||||
genTypeInfoAuxBase(m, typ, name, toRope("0"))
|
||||
genTypeInfoAuxBase(m, typ, typ, name, toRope("0"))
|
||||
var expr = getNimNode(m)
|
||||
var length = sonsLen(typ)
|
||||
if length > 0:
|
||||
@@ -854,7 +853,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
|
||||
# optimizations here: The ``typ`` field is never set, as it is redundant
|
||||
# anyway. We generate a cstring array and a loop over it. Exceptional
|
||||
# positions will be reset after the loop.
|
||||
genTypeInfoAux(m, typ, name)
|
||||
genTypeInfoAux(m, typ, typ, name)
|
||||
var nodePtrs = getTempName()
|
||||
var length = sonsLen(typ.n)
|
||||
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
|
||||
@@ -894,13 +893,13 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
|
||||
|
||||
proc genSetInfo(m: BModule, typ: PType, name: PRope) =
|
||||
assert(typ.sons[0] != nil)
|
||||
genTypeInfoAux(m, typ, name)
|
||||
genTypeInfoAux(m, typ, typ, name)
|
||||
var tmp = getNimNode(m)
|
||||
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
|
||||
[tmp, toRope(firstOrd(typ)), name])
|
||||
|
||||
proc genArrayInfo(m: BModule, typ: PType, name: PRope) =
|
||||
genTypeInfoAuxBase(m, typ, name, genTypeInfo(m, typ.sons[1]))
|
||||
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1]))
|
||||
|
||||
proc fakeClosureType(owner: PSym): PType =
|
||||
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
|
||||
@@ -946,23 +945,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
|
||||
case t.kind
|
||||
of tyEmpty: result = toRope"0"
|
||||
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
|
||||
genTypeInfoAuxBase(m, t, result, toRope"0")
|
||||
genTypeInfoAuxBase(m, t, t, result, toRope"0")
|
||||
of tyProc:
|
||||
if t.callConv != ccClosure:
|
||||
genTypeInfoAuxBase(m, t, result, toRope"0")
|
||||
genTypeInfoAuxBase(m, t, t, result, toRope"0")
|
||||
else:
|
||||
genTupleInfo(m, fakeClosureType(t.owner), result)
|
||||
of tySequence, tyRef:
|
||||
genTypeInfoAux(m, t, result)
|
||||
genTypeInfoAux(m, t, t, result)
|
||||
if gSelectedGC >= gcMarkAndSweep:
|
||||
let markerProc = genTraverseProc(m, t, tiNew)
|
||||
appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
|
||||
of tyPtr, tyRange: genTypeInfoAux(m, t, result)
|
||||
of tyPtr, tyRange: genTypeInfoAux(m, t, t, result)
|
||||
of tyArrayConstr, tyArray: genArrayInfo(m, t, result)
|
||||
of tySet: genSetInfo(m, t, result)
|
||||
of tyEnum: genEnumInfo(m, t, result)
|
||||
of tyObject: genObjectInfo(m, t, result)
|
||||
of tyTuple:
|
||||
of tyObject: genObjectInfo(m, t, origType, result)
|
||||
of tyTuple:
|
||||
# if t.n != nil: genObjectInfo(m, t, result)
|
||||
# else:
|
||||
# BUGFIX: use consistently RTTI without proper field names; otherwise
|
||||
|
||||
@@ -69,7 +69,20 @@ when false:
|
||||
proc echoStats*() =
|
||||
for i in countup(low(TTypeKind), high(TTypeKind)):
|
||||
echo i, " ", gTypeTable[i].counter
|
||||
|
||||
|
||||
proc slowSearch(key: PType; k: TTypeKind): PType =
|
||||
# tuples are quite horrible as C does not support them directly and
|
||||
# tuple[string, string] is a (strange) subtype of
|
||||
# tuple[nameA, nameB: string]. This bites us here, so we
|
||||
# use 'sameBackendType' instead of 'sameType'.
|
||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
var t = PType(gTypeTable[k].data[h].key)
|
||||
if t != nil and sameBackendType(t, key):
|
||||
return t
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
|
||||
proc getUniqueType*(key: PType): PType =
|
||||
# this is a hotspot in the compiler!
|
||||
if key == nil: return
|
||||
@@ -86,7 +99,7 @@ proc getUniqueType*(key: PType): PType =
|
||||
gCanonicalTypes[k] = key
|
||||
result = key
|
||||
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
|
||||
internalError("GetUniqueType")
|
||||
internalError("getUniqueType")
|
||||
of tyDistinct:
|
||||
if key.deepCopy != nil: result = key
|
||||
else: result = getUniqueType(lastSon(key))
|
||||
@@ -96,23 +109,20 @@ proc getUniqueType*(key: PType): PType =
|
||||
#if obj.sym != nil and obj.sym.name.s == "TOption":
|
||||
# echo "for ", typeToString(key), " I returned "
|
||||
# debug result
|
||||
of tyArrayConstr, tyGenericInvokation, tyGenericBody,
|
||||
of tyPtr, tyRef, tyVar:
|
||||
let elemType = lastSon(key)
|
||||
if elemType.kind in {tyBool, tyChar, tyInt..tyUInt64}:
|
||||
# no canonicalization for integral types, so that e.g. ``ptr pid_t`` is
|
||||
# produced instead of ``ptr NI``.
|
||||
result = key
|
||||
else:
|
||||
result = slowSearch(key, k)
|
||||
of tyArrayConstr, tyGenericInvocation, tyGenericBody,
|
||||
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
|
||||
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar:
|
||||
# tuples are quite horrible as C does not support them directly and
|
||||
# tuple[string, string] is a (strange) subtype of
|
||||
# tuple[nameA, nameB: string]. This bites us here, so we
|
||||
# use 'sameBackendType' instead of 'sameType'.
|
||||
|
||||
tySequence, tyForward, tyVarargs, tyProxy:
|
||||
# we have to do a slow linear search because types may need
|
||||
# to be compared by their structure:
|
||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
var t = PType(gTypeTable[k].data[h].key)
|
||||
if t != nil and sameBackendType(t, key):
|
||||
return t
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
result = slowSearch(key, k)
|
||||
of tyObject:
|
||||
if tfFromGeneric notin key.flags:
|
||||
# fast case; lookup per id suffices:
|
||||
@@ -123,9 +133,9 @@ proc getUniqueType*(key: PType): PType =
|
||||
else:
|
||||
# ugly slow case: need to compare by structure
|
||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
var t = PType(gTypeTable[k].data[h].key)
|
||||
if t != nil and sameType(t, key):
|
||||
if t != nil and sameBackendType(t, key):
|
||||
return t
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
@@ -139,14 +149,8 @@ proc getUniqueType*(key: PType): PType =
|
||||
result = key
|
||||
else:
|
||||
# ugh, we need the canon here:
|
||||
if idTableHasObjectAsKey(gTypeTable[k], key): return key
|
||||
for h in countup(0, high(gTypeTable[k].data)):
|
||||
var t = PType(gTypeTable[k].data[h].key)
|
||||
if t != nil and sameBackendType(t, key):
|
||||
return t
|
||||
idTablePut(gTypeTable[k], key, key)
|
||||
result = key
|
||||
|
||||
result = slowSearch(key, k)
|
||||
|
||||
proc tableGetType*(tab: TIdTable, key: PType): RootRef =
|
||||
# returns nil if we need to declare this type
|
||||
result = idTableGet(tab, key)
|
||||
|
||||
@@ -25,15 +25,6 @@ when options.hasTinyCBackend:
|
||||
var
|
||||
generatedHeader: BModule
|
||||
|
||||
proc ropeff(cformat, llvmformat: string, args: varargs[PRope]): PRope =
|
||||
if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args)
|
||||
else: result = ropef(cformat, args)
|
||||
|
||||
proc appff(dest: var PRope, cformat, llvmformat: string,
|
||||
args: varargs[PRope]) =
|
||||
if gCmd == cmdCompileToLLVM: appf(dest, llvmformat, args)
|
||||
else: appf(dest, cformat, args)
|
||||
|
||||
proc addForwardedProc(m: BModule, prc: PSym) =
|
||||
m.forwardedProcs.add(prc)
|
||||
inc(gForwardedProcsCounter)
|
||||
@@ -137,79 +128,8 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
|
||||
if i - 1 >= start:
|
||||
app(result, substr(frmt, start, i - 1))
|
||||
|
||||
const compileTimeRopeFmt = false
|
||||
|
||||
when compileTimeRopeFmt:
|
||||
import macros
|
||||
|
||||
type TFmtFragmentKind = enum
|
||||
ffSym,
|
||||
ffLit,
|
||||
ffParam
|
||||
|
||||
type TFragment = object
|
||||
case kind: TFmtFragmentKind
|
||||
of ffSym, ffLit:
|
||||
value: string
|
||||
of ffParam:
|
||||
intValue: int
|
||||
|
||||
iterator fmtStringFragments(s: string): tuple[kind: TFmtFragmentKind,
|
||||
value: string,
|
||||
intValue: int] =
|
||||
# This is a bit less featured version of the ropecg's algorithm
|
||||
# (be careful when replacing ropecg calls)
|
||||
var
|
||||
i = 0
|
||||
length = s.len
|
||||
|
||||
while i < length:
|
||||
var start = i
|
||||
case s[i]
|
||||
of '$':
|
||||
let n = s[i+1]
|
||||
case n
|
||||
of '$':
|
||||
inc i, 2
|
||||
of '0'..'9':
|
||||
# XXX: use the new case object construction syntax when it's ready
|
||||
yield (kind: ffParam, value: "", intValue: n.ord - ord('1'))
|
||||
inc i, 2
|
||||
start = i
|
||||
else:
|
||||
inc i
|
||||
of '#':
|
||||
inc i
|
||||
var j = i
|
||||
while s[i] in IdentChars: inc i
|
||||
yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0)
|
||||
start = i
|
||||
else: discard
|
||||
|
||||
while i < length:
|
||||
if s[i] != '$' and s[i] != '#': inc i
|
||||
else: break
|
||||
|
||||
if i - 1 >= start:
|
||||
yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0)
|
||||
|
||||
macro rfmt(m: BModule, fmt: static[string], args: varargs[PRope]): expr =
|
||||
## Experimental optimized rope-formatting operator
|
||||
## The run-time code it produces will be very fast, but will it speed up
|
||||
## the compilation of nimrod itself or will the macro execution time
|
||||
## offset the gains?
|
||||
result = newCall(bindSym"ropeConcat")
|
||||
for frag in fmtStringFragments(fmt):
|
||||
case frag.kind
|
||||
of ffSym:
|
||||
result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value)))
|
||||
of ffLit:
|
||||
result.add(newCall(bindSym"~", newStrLitNode(frag.value)))
|
||||
of ffParam:
|
||||
result.add(args[frag.intValue])
|
||||
else:
|
||||
template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
|
||||
ropecg(m, fmt, args)
|
||||
template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
|
||||
ropecg(m, fmt, args)
|
||||
|
||||
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
@@ -242,24 +162,14 @@ proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
|
||||
|
||||
when compileTimeRopeFmt:
|
||||
template linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
line(p, s, rfmt(p.module, frmt, args))
|
||||
else:
|
||||
proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
|
||||
proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
|
||||
|
||||
proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr,
|
||||
args: varargs[PRope]) =
|
||||
app(r, indentLine(p, ropecg(p.module, frmt, args)))
|
||||
|
||||
proc lineFF(p: BProc, s: TCProcSection, cformat, llvmformat: string,
|
||||
args: varargs[PRope]) =
|
||||
if gCmd == cmdCompileToLLVM: lineF(p, s, llvmformat, args)
|
||||
else: lineF(p, s, cformat, args)
|
||||
|
||||
proc safeLineNm(info: TLineInfo): int =
|
||||
result = toLinenumber(info)
|
||||
if result < 0: result = 0 # negative numbers are not allowed in #line
|
||||
@@ -267,8 +177,8 @@ proc safeLineNm(info: TLineInfo): int =
|
||||
proc genCLineDir(r: var PRope, filename: string, line: int) =
|
||||
assert line >= 0
|
||||
if optLineDir in gOptions:
|
||||
appff(r, "$N#line $2 $1$N", "; line $2 \"$1\"$n",
|
||||
[toRope(makeSingleLineCString(filename)), toRope(line)])
|
||||
appf(r, "$N#line $2 $1$N",
|
||||
[toRope(makeSingleLineCString(filename)), toRope(line)])
|
||||
|
||||
proc genCLineDir(r: var PRope, info: TLineInfo) =
|
||||
genCLineDir(r, info.toFullPath, info.safeLineNm)
|
||||
@@ -402,11 +312,8 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) =
|
||||
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
|
||||
inc(p.labels)
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
result.r = con("%LOC", toRope(p.labels))
|
||||
else:
|
||||
result.r = con("LOC", toRope(p.labels))
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
||||
result.r = con("LOC", toRope(p.labels))
|
||||
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
|
||||
result.k = locTemp
|
||||
#result.a = - 1
|
||||
result.t = getUniqueType(t)
|
||||
@@ -446,29 +353,6 @@ proc deinitGCFrame(p: BProc): PRope =
|
||||
if p.gcFrameId > 0:
|
||||
result = ropecg(p.module,
|
||||
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
|
||||
|
||||
proc cstringLit(p: BProc, r: var PRope, s: string): PRope =
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
inc(p.module.labels)
|
||||
inc(p.labels)
|
||||
result = ropef("%LOC$1", [toRope(p.labels)])
|
||||
appf(p.module.s[cfsData], "@C$1 = private constant [$2 x i8] $3$n",
|
||||
[toRope(p.module.labels), toRope(len(s)), makeLLVMString(s)])
|
||||
appf(r, "$1 = getelementptr [$2 x i8]* @C$3, %NI 0, %NI 0$n",
|
||||
[result, toRope(len(s)), toRope(p.module.labels)])
|
||||
else:
|
||||
result = makeCString(s)
|
||||
|
||||
proc cstringLit(m: BModule, r: var PRope, s: string): PRope =
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
inc(m.labels, 2)
|
||||
result = ropef("%MOC$1", [toRope(m.labels - 1)])
|
||||
appf(m.s[cfsData], "@MOC$1 = private constant [$2 x i8] $3$n",
|
||||
[toRope(m.labels), toRope(len(s)), makeLLVMString(s)])
|
||||
appf(r, "$1 = getelementptr [$2 x i8]* @MOC$3, %NI 0, %NI 0$n",
|
||||
[result, toRope(len(s)), toRope(m.labels)])
|
||||
else:
|
||||
result = makeCString(s)
|
||||
|
||||
proc allocParam(p: BProc, s: PSym) =
|
||||
assert(s.kind == skParam)
|
||||
@@ -494,22 +378,26 @@ proc localDebugInfo(p: BProc, s: PSym) =
|
||||
inc(p.maxFrameLen)
|
||||
inc p.blocks[p.blocks.len-1].frameLen
|
||||
|
||||
proc assignLocalVar(p: BProc, s: PSym) =
|
||||
#assert(s.loc.k == locNone) // not yet assigned
|
||||
# this need not be fullfilled for inline procs; they are regenerated
|
||||
# for each module that uses them!
|
||||
proc localVarDecl(p: BProc; s: PSym): PRope =
|
||||
if s.loc.k == locNone:
|
||||
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
|
||||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||
var decl = getTypeDesc(p.module, s.loc.t)
|
||||
result = getTypeDesc(p.module, s.loc.t)
|
||||
if s.constraint.isNil:
|
||||
if sfRegister in s.flags: app(decl, " register")
|
||||
if sfRegister in s.flags: app(result, " register")
|
||||
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||
# app(decl, " GC_GUARD")
|
||||
if sfVolatile in s.flags: app(decl, " volatile")
|
||||
appf(decl, " $1;$n", [s.loc.r])
|
||||
if sfVolatile in s.flags: app(result, " volatile")
|
||||
app(result, " ")
|
||||
app(result, s.loc.r)
|
||||
else:
|
||||
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
|
||||
result = ropef(s.cgDeclFrmt, result, s.loc.r)
|
||||
|
||||
proc assignLocalVar(p: BProc, s: PSym) =
|
||||
#assert(s.loc.k == locNone) # not yet assigned
|
||||
# this need not be fulfilled for inline procs; they are regenerated
|
||||
# for each module that uses them!
|
||||
let decl = localVarDecl(p, s).con(";" & tnl)
|
||||
line(p, cpsLocals, decl)
|
||||
localDebugInfo(p, s)
|
||||
|
||||
@@ -552,13 +440,11 @@ proc assignGlobalVar(p: BProc, s: PSym) =
|
||||
{optStackTrace, optEndb}:
|
||||
appcg(p.module, p.module.s[cfsDebugInit],
|
||||
"#dbgRegisterGlobal($1, &$2, $3);$n",
|
||||
[cstringLit(p, p.module.s[cfsDebugInit],
|
||||
normalize(s.owner.name.s & '.' & s.name.s)),
|
||||
[makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
|
||||
s.loc.r, genTypeInfo(p.module, s.typ)])
|
||||
|
||||
proc assignParam(p: BProc, s: PSym) =
|
||||
assert(s.loc.r != nil)
|
||||
if sfAddrTaken in s.flags and gCmd == cmdCompileToLLVM: allocParam(p, s)
|
||||
localDebugInfo(p, s)
|
||||
|
||||
proc fillProcLoc(sym: PSym) =
|
||||
@@ -586,6 +472,11 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
|
||||
initLoc(result, locNone, e.typ, OnUnknown)
|
||||
expr(p, e, result)
|
||||
|
||||
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
|
||||
initLoc(result, locNone, e.typ, OnUnknown)
|
||||
result.flags.incl lfSingleUse
|
||||
expr(p, e, result)
|
||||
|
||||
proc lenField(p: BProc): PRope =
|
||||
result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
|
||||
|
||||
@@ -647,7 +538,6 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
let isCall = isGetProcAddr(lib)
|
||||
var extname = sym.loc.r
|
||||
if not isCall: loadDynamicLib(m, lib)
|
||||
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
|
||||
var tmp = mangleDynLibProc(sym)
|
||||
sym.loc.r = tmp # from now on we only need the internal name
|
||||
sym.typ.sym = nil # generate a new name
|
||||
@@ -663,7 +553,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
params.app(", ")
|
||||
let load = ropef("\t$1 = ($2) ($3$4));$n",
|
||||
[tmp, getTypeDesc(m, sym.typ),
|
||||
params, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
|
||||
params, makeCString(ropeToStr(extname))])
|
||||
var last = lastSon(n)
|
||||
if last.kind == nkHiddenStdConv: last = last.sons[1]
|
||||
internalAssert(last.kind == nkStrLit)
|
||||
@@ -678,10 +568,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
||||
[tmp, getTypeDesc(m, sym.typ),
|
||||
lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
|
||||
appff(m.s[cfsVars], "$2 $1;$n",
|
||||
"$1 = linkonce global $2 zeroinitializer$n",
|
||||
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||
lib.name, makeCString(ropeToStr(extname))])
|
||||
appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||
|
||||
proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||
var lib = sym.annex
|
||||
@@ -694,7 +582,7 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"$1 = ($2*) #nimGetProcAddr($3, $4);$n",
|
||||
[tmp, getTypeDesc(m, sym.typ),
|
||||
lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))])
|
||||
lib.name, makeCString(ropeToStr(extname))])
|
||||
appf(m.s[cfsVars], "$2* $1;$n",
|
||||
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
|
||||
|
||||
@@ -717,13 +605,13 @@ proc cgsym(m: BModule, name: string): PRope =
|
||||
rawMessage(errSystemNeeds, name)
|
||||
result = sym.loc.r
|
||||
|
||||
proc generateHeaders(m: BModule) =
|
||||
proc generateHeaders(m: BModule) =
|
||||
app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl)
|
||||
var it = PStrEntry(m.headerFiles.head)
|
||||
while it != nil:
|
||||
while it != nil:
|
||||
if it.data[0] notin {'\"', '<'}:
|
||||
appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)])
|
||||
else:
|
||||
else:
|
||||
appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)])
|
||||
it = PStrEntry(it.next)
|
||||
|
||||
@@ -796,16 +684,17 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
app(generatedProc, initGCFrame(p))
|
||||
if optStackTrace in prc.options:
|
||||
app(generatedProc, p.s(cpsLocals))
|
||||
var procname = cstringLit(p, generatedProc, prc.name.s)
|
||||
var procname = makeCString(prc.name.s)
|
||||
app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
|
||||
else:
|
||||
app(generatedProc, p.s(cpsLocals))
|
||||
if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM):
|
||||
if optProfiler in prc.options:
|
||||
# invoke at proc entry for recursion:
|
||||
appcg(p, cpsInit, "\t#nimProfile();$n", [])
|
||||
if p.beforeRetNeeded: app(generatedProc, "{")
|
||||
app(generatedProc, p.s(cpsInit))
|
||||
app(generatedProc, p.s(cpsStmts))
|
||||
if p.beforeRetNeeded: app(generatedProc, ~"\tBeforeRet: ;$n")
|
||||
if p.beforeRetNeeded: app(generatedProc, ~"\t}BeforeRet: ;$n")
|
||||
app(generatedProc, deinitGCFrame(p))
|
||||
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
|
||||
app(generatedProc, returnStmt)
|
||||
@@ -825,7 +714,6 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
not containsOrIncl(m.declaredThings, sym.id):
|
||||
app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
|
||||
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
|
||||
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
|
||||
elif not containsOrIncl(m.declaredProtos, sym.id):
|
||||
var header = genProcHeader(m, sym)
|
||||
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
|
||||
@@ -923,21 +811,17 @@ proc addIntTypes(result: var PRope) {.inline.} =
|
||||
|
||||
proc getCopyright(cfile: string): PRope =
|
||||
if optCompileOnly in gGlobalOptions:
|
||||
result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
|
||||
result = ropef("/* Generated by Nim Compiler v$1 */$N" &
|
||||
"/* (c) 2015 Andreas Rumpf */$N" &
|
||||
"/* The generated code is subject to the original license. */$N",
|
||||
"; Generated by Nim Compiler v$1$N" &
|
||||
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
|
||||
[toRope(VersionAsString)])
|
||||
else:
|
||||
result = ropeff("/* Generated by Nim Compiler v$1 */$N" &
|
||||
result = ropef("/* Generated by Nim Compiler v$1 */$N" &
|
||||
"/* (c) 2015 Andreas Rumpf */$N" &
|
||||
"/* The generated code is subject to the original license. */$N" &
|
||||
"/* Compiled for: $2, $3, $4 */$N" &
|
||||
"/* Command for C compiler:$n $5 */$N",
|
||||
"; Generated by Nim Compiler v$1$N" &
|
||||
"; (c) 2015 Andreas Rumpf$N" &
|
||||
"; Compiled for: $2, $3, $4$N" &
|
||||
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
|
||||
[toRope(VersionAsString),
|
||||
toRope(platform.OS[targetOS].name),
|
||||
toRope(platform.CPU[targetCPU].name),
|
||||
toRope(extccomp.CC[extccomp.cCompiler].name),
|
||||
@@ -1088,13 +972,11 @@ proc registerModuleToMain(m: PSym) =
|
||||
var
|
||||
init = m.getInitName
|
||||
datInit = m.getDatInitName
|
||||
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
|
||||
"declare void $1() noinline$N", [init])
|
||||
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
|
||||
"declare void $1() noinline$N", [datInit])
|
||||
appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
|
||||
appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
|
||||
if sfSystemModule notin m.flags:
|
||||
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit])
|
||||
let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init])
|
||||
appf(mainDatInit, "\t$1();$N", [datInit])
|
||||
let initCall = ropef("\t$1();$N", [init])
|
||||
if sfMainModule in m.flags:
|
||||
app(mainModInit, initCall)
|
||||
else:
|
||||
@@ -1102,8 +984,7 @@ proc registerModuleToMain(m: PSym) =
|
||||
|
||||
proc genInitCode(m: BModule) =
|
||||
var initname = getInitName(m.module)
|
||||
var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||
"define void $1() noinline {$n", [initname])
|
||||
var prc = ropef("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", [initname])
|
||||
if m.typeNodes > 0:
|
||||
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
||||
[m.typeNodesName, toRope(m.typeNodes)])
|
||||
@@ -1124,7 +1005,7 @@ proc genInitCode(m: BModule) =
|
||||
# declare it nevertheless:
|
||||
m.frameDeclared = true
|
||||
if not m.preventStackTrace:
|
||||
var procname = cstringLit(m.initProc, prc, m.module.name.s)
|
||||
var procname = makeCString(m.module.name.s)
|
||||
app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
|
||||
else:
|
||||
app(prc, ~"\tTFrame F; F.len = 0;$N")
|
||||
@@ -1145,8 +1026,8 @@ proc genInitCode(m: BModule) =
|
||||
app(prc, deinitGCFrame(m.initProc))
|
||||
appf(prc, "}$N$N")
|
||||
|
||||
prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||
"define void $1() noinline {$n", [getDatInitName(m.module)])
|
||||
prc.appf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||
[getDatInitName(m.module)])
|
||||
|
||||
for i in cfsTypeInit1..cfsDynLibInit:
|
||||
app(prc, genSectionStart(i))
|
||||
|
||||
@@ -82,6 +82,9 @@ type
|
||||
maxFrameLen*: int # max length of frame descriptor
|
||||
module*: BModule # used to prevent excessive parameter passing
|
||||
withinLoop*: int # > 0 if we are within a loop
|
||||
splitDecls*: int # > 0 if we are in some context for C++ that
|
||||
# requires 'T x = T()' to become 'T x; x = T()'
|
||||
# (yes, C++ is weird like that)
|
||||
gcFrameId*: Natural # for the GC stack marking
|
||||
gcFrameType*: PRope # the struct {} we put the GC markers into
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo)
|
||||
|
||||
const
|
||||
HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
|
||||
"Copyright (c) 2006-2014 by Andreas Rumpf\n"
|
||||
"Copyright (c) 2006-2015 by Andreas Rumpf\n"
|
||||
|
||||
const
|
||||
Usage = slurp"doc/basicopt.txt".replace("//", "")
|
||||
@@ -141,7 +141,7 @@ proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
|
||||
|
||||
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
info: TLineInfo) =
|
||||
info: TLineInfo; orig: string) =
|
||||
var id = "" # arg = "X]:on|off"
|
||||
var i = 0
|
||||
var n = hintMin
|
||||
@@ -149,17 +149,17 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
|
||||
add(id, arg[i])
|
||||
inc(i)
|
||||
if i < len(arg) and (arg[i] == ']'): inc(i)
|
||||
else: invalidCmdLineOption(pass, arg, info)
|
||||
else: invalidCmdLineOption(pass, orig, info)
|
||||
if i < len(arg) and (arg[i] in {':', '='}): inc(i)
|
||||
else: invalidCmdLineOption(pass, arg, info)
|
||||
if state == wHint:
|
||||
else: invalidCmdLineOption(pass, orig, info)
|
||||
if state == wHint:
|
||||
var x = findStr(msgs.HintsToStr, id)
|
||||
if x >= 0: n = TNoteKind(x + ord(hintMin))
|
||||
else: invalidCmdLineOption(pass, arg, info)
|
||||
else:
|
||||
else: localError(info, "unknown hint: " & id)
|
||||
else:
|
||||
var x = findStr(msgs.WarningsToStr, id)
|
||||
if x >= 0: n = TNoteKind(x + ord(warnMin))
|
||||
else: invalidCmdLineOption(pass, arg, info)
|
||||
else: localError(info, "unknown warning: " & id)
|
||||
case whichKeyword(substr(arg, i))
|
||||
of wOn: incl(gNotes, n)
|
||||
of wOff: excl(gNotes, n)
|
||||
@@ -326,7 +326,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
of "link":
|
||||
expectArg(switch, arg, pass, info)
|
||||
if pass in {passCmd2, passPP}: addFileToLink(arg)
|
||||
of "debuginfo":
|
||||
of "debuginfo":
|
||||
expectNoArg(switch, arg, pass, info)
|
||||
incl(gGlobalOptions, optCDebug)
|
||||
of "embedsrc":
|
||||
@@ -368,16 +368,26 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
|
||||
defineSymbol("nogc")
|
||||
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
|
||||
of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
|
||||
of "warning": processSpecificNote(arg, wWarning, pass, info)
|
||||
of "hint": processSpecificNote(arg, wHint, pass, info)
|
||||
of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
|
||||
of "hint": processSpecificNote(arg, wHint, pass, info, switch)
|
||||
of "hints": processOnOffSwitch({optHints}, arg, pass, info)
|
||||
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
|
||||
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
|
||||
of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
|
||||
of "debugger":
|
||||
processOnOffSwitch({optEndb}, arg, pass, info)
|
||||
if optEndb in gOptions: defineSymbol("endb")
|
||||
else: undefSymbol("endb")
|
||||
of "debugger":
|
||||
case arg.normalize
|
||||
of "on", "endb":
|
||||
gOptions.incl optEndb
|
||||
defineSymbol("endb")
|
||||
of "off":
|
||||
gOptions.excl optEndb
|
||||
undefSymbol("endb")
|
||||
of "native", "gdb":
|
||||
incl(gGlobalOptions, optCDebug)
|
||||
gOptions = gOptions + {optLineDir} - {optEndb}
|
||||
undefSymbol("endb")
|
||||
else:
|
||||
localError(info, "expected endb|gdb but found " & arg)
|
||||
of "profiler":
|
||||
processOnOffSwitch({optProfiler}, arg, pass, info)
|
||||
if optProfiler in gOptions: defineSymbol("profiler")
|
||||
|
||||
@@ -89,6 +89,7 @@ proc initDefines*() =
|
||||
defineSymbol("nimparsebiggestfloatmagic")
|
||||
defineSymbol("nimalias")
|
||||
defineSymbol("nimlocks")
|
||||
defineSymbol("nimnode")
|
||||
|
||||
# add platform specific symbols:
|
||||
for c in low(CPU)..high(CPU):
|
||||
|
||||
@@ -126,7 +126,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: app(result, varvalues[idx])
|
||||
else: rawMessage(errUnkownSubstitionVar, id)
|
||||
else: rawMessage(errUnknownSubstitionVar, id)
|
||||
of '{':
|
||||
var id = ""
|
||||
inc(i)
|
||||
@@ -138,7 +138,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
|
||||
# search for the variable:
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: app(result, varvalues[idx])
|
||||
else: rawMessage(errUnkownSubstitionVar, id)
|
||||
else: rawMessage(errUnknownSubstitionVar, id)
|
||||
else: internalError("ropeFormatNamedVars")
|
||||
var start = i
|
||||
while i < L:
|
||||
@@ -272,7 +272,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string =
|
||||
## type)?(,param type)*``. The callable type part will be added only if the
|
||||
## node is not a proc, as those are the common ones. The suffix will be a dot
|
||||
## and a single letter representing the type of the callable. The parameter
|
||||
## types will be added with a preceeding dash. Return types won't be added.
|
||||
## types will be added with a preceding dash. Return types won't be added.
|
||||
##
|
||||
## If you modify the output of this proc, please update the anchor generation
|
||||
## section of ``doc/docgen.txt``.
|
||||
|
||||
@@ -380,7 +380,7 @@ proc setCC*(ccname: string) =
|
||||
cCompiler = nameToCC(ccname)
|
||||
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
|
||||
compileOptions = getConfigVar(cCompiler, ".options.always")
|
||||
linkOptions = getConfigVar(cCompiler, ".options.linker")
|
||||
linkOptions = ""
|
||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||
defineSymbol(CC[cCompiler].name)
|
||||
@@ -389,8 +389,8 @@ proc addOpt(dest: var string, src: string) =
|
||||
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
|
||||
add(dest, src)
|
||||
|
||||
proc addLinkOption*(option: string) =
|
||||
if find(linkOptions, option, 0) < 0: addOpt(linkOptions, option)
|
||||
proc addLinkOption*(option: string) =
|
||||
addOpt(linkOptions, option)
|
||||
|
||||
proc addCompileOption*(option: string) =
|
||||
if strutils.find(compileOptions, option, 0) < 0:
|
||||
@@ -401,7 +401,7 @@ proc initVars*() =
|
||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||
defineSymbol(CC[cCompiler].name)
|
||||
addCompileOption(getConfigVar(cCompiler, ".options.always"))
|
||||
addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
||||
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
||||
if len(ccompilerpath) == 0:
|
||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
||||
|
||||
@@ -428,13 +428,17 @@ proc addFileToLink*(filename: string) =
|
||||
prependStr(toLink, filename)
|
||||
# BUGFIX: was ``appendStr``
|
||||
|
||||
proc execExternalProgram*(cmd: string, prettyCmd = "") =
|
||||
proc execWithEcho(cmd: string, prettyCmd = ""): int =
|
||||
if optListCmd in gGlobalOptions or gVerbosity > 0:
|
||||
if prettyCmd != "":
|
||||
msgWriteln(prettyCmd)
|
||||
else:
|
||||
msgWriteln(cmd)
|
||||
if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "")
|
||||
result = execCmd(cmd)
|
||||
|
||||
proc execExternalProgram*(cmd: string, prettyCmd = "") =
|
||||
if execWithEcho(cmd, prettyCmd) != 0:
|
||||
rawMessage(errExecutionOfProgramFailed, "")
|
||||
|
||||
proc generateScript(projectFile: string, script: PRope) =
|
||||
let (dir, name, ext) = splitFile(projectFile)
|
||||
@@ -549,13 +553,13 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
|
||||
cfile = quoteShell(cfile)
|
||||
result = quoteShell(compilePattern % [
|
||||
"file", cfile, "objfile", objfile, "options", options,
|
||||
"include", includeCmd, "nimrod", getPrefixDir(),
|
||||
"include", includeCmd, "nim", getPrefixDir(),
|
||||
"nim", getPrefixDir(), "lib", libpath])
|
||||
add(result, ' ')
|
||||
addf(result, CC[c].compileTmpl, [
|
||||
"file", cfile, "objfile", objfile,
|
||||
"options", options, "include", includeCmd,
|
||||
"nimrod", quoteShell(getPrefixDir()),
|
||||
"nim", quoteShell(getPrefixDir()),
|
||||
"nim", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
|
||||
@@ -622,15 +626,17 @@ proc callCCompiler*(projectfile: string) =
|
||||
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
||||
var res = 0
|
||||
if gNumberOfProcessors <= 1:
|
||||
for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res)
|
||||
for i in countup(0, high(cmds)):
|
||||
res = execWithEcho(cmds[i])
|
||||
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
|
||||
elif optListCmd in gGlobalOptions or gVerbosity > 1:
|
||||
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams},
|
||||
res = execProcesses(cmds, {poEchoCmd, poUsePath, poParentStreams},
|
||||
gNumberOfProcessors)
|
||||
elif gVerbosity == 1:
|
||||
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
||||
res = execProcesses(cmds, {poUsePath, poParentStreams},
|
||||
gNumberOfProcessors, prettyCb)
|
||||
else:
|
||||
res = execProcesses(cmds, {poUseShell, poParentStreams},
|
||||
res = execProcesses(cmds, {poUsePath, poParentStreams},
|
||||
gNumberOfProcessors)
|
||||
if res != 0:
|
||||
if gNumberOfProcessors <= 1:
|
||||
@@ -673,15 +679,16 @@ proc callCCompiler*(projectfile: string) =
|
||||
if not exefile.isAbsolute():
|
||||
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
||||
exefile = quoteShell(exefile)
|
||||
let linkOptions = getLinkOptions()
|
||||
let linkOptions = getLinkOptions() & " " &
|
||||
getConfigVar(cCompiler, ".options.linker")
|
||||
linkCmd = quoteShell(linkCmd % ["builddll", builddll,
|
||||
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
||||
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath])
|
||||
"exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
|
||||
linkCmd.add ' '
|
||||
addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
|
||||
"buildgui", buildgui, "options", linkOptions,
|
||||
"objfiles", objfiles, "exefile", exefile,
|
||||
"nimrod", quoteShell(getPrefixDir()),
|
||||
"nim", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
if gVerbosity == 1:
|
||||
@@ -710,7 +717,8 @@ proc writeMapping*(gSymbolMapping: PRope) =
|
||||
app(code, strutils.escape(getCompileOptions()))
|
||||
|
||||
app(code, "\n[Linker]\nFlags=")
|
||||
app(code, strutils.escape(getLinkOptions()))
|
||||
app(code, strutils.escape(getLinkOptions() & " " &
|
||||
getConfigVar(cCompiler, ".options.linker")))
|
||||
|
||||
app(code, "\n[Environment]\nlibpath=")
|
||||
app(code, strutils.escape(libpath))
|
||||
|
||||
89
compiler/forloops.nim
Normal file
89
compiler/forloops.nim
Normal file
@@ -0,0 +1,89 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module implements for loop detection for better C code generation.
|
||||
|
||||
import ast, astalgo
|
||||
|
||||
const
|
||||
someCmp = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
||||
mEqUntracedRef, mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
|
||||
mLeCh, mLeB, mLePtr, mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
|
||||
mLtCh, mLtB, mLtPtr}
|
||||
|
||||
proc isCounter(s: PSym): bool {.inline.} =
|
||||
s.kind in {skResult, skVar, skLet, skTemp} and
|
||||
{sfGlobal, sfAddrTaken} * s.flags == {}
|
||||
|
||||
proc isCall(n: PNode): bool {.inline.} =
|
||||
n.kind in nkCallKinds and n[0].kind == nkSym
|
||||
|
||||
proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
|
||||
|
||||
proc getCounter(lastStmt: PNode): PSym =
|
||||
if lastStmt.isCall:
|
||||
let op = lastStmt.sym
|
||||
if op.magic in {mDec, mInc} or
|
||||
((op.name.s == "+=" or op.name.s == "-=") and op.fromSystem):
|
||||
if op[1].kind == nkSym and isCounter(op[1].sym):
|
||||
result = op[1].sym
|
||||
|
||||
proc counterInTree(n, loop: PNode; counter: PSym): bool =
|
||||
# prune the search tree: within the loop the counter may be used:
|
||||
if n == loop: return
|
||||
case n.kind
|
||||
of nkSym:
|
||||
if n.sym == counter: return true
|
||||
of nkVarSection, nkLetSection:
|
||||
# definitions are fine!
|
||||
for it in n:
|
||||
if counterInTree(it.lastSon): return true
|
||||
else:
|
||||
for i in 0 .. <safeLen(n):
|
||||
if counterInTree(n[i], loop, counter): return true
|
||||
|
||||
proc copyExcept(n: PNode, x, dest: PNode) =
|
||||
if x == n: return
|
||||
if n.kind in {nkStmtList, nkStmtListExpr}:
|
||||
for i in 0 .. <n.len: copyExcept(n[i], x, dest)
|
||||
else:
|
||||
dest.add n
|
||||
|
||||
type
|
||||
ForLoop* = object
|
||||
counter*: PSym
|
||||
init*, cond*, increment*, body*: PNode
|
||||
|
||||
proc extractForLoop*(loop, fullTree: PNode): ForLoop =
|
||||
## returns 'counter == nil' if the while loop 'n' is not a for loop:
|
||||
assert loop.kind == nkWhileStmt
|
||||
let cond == loop[0]
|
||||
|
||||
if not cond.isCall: return
|
||||
if cond[0].sym.magic notin someCmp: return
|
||||
|
||||
var lastStmt = loop[1]
|
||||
while lastStmt.kind in {nkStmtList, nkStmtListExpr}:
|
||||
lastStmt = lastStmt.lastSon
|
||||
|
||||
let counter = getCounter(lastStmt)
|
||||
if counter.isNil or counter.ast.isNil: return
|
||||
|
||||
template `=~`(a, b): expr = a.kind == nkSym and a.sym == b
|
||||
|
||||
if cond[1] =~ counter or cond[2] =~ counter:
|
||||
# ok, now check 'counter' is not used *after* the loop
|
||||
if counterInTree(fullTree, loop, counter): return
|
||||
# ok, success, fill in the fields:
|
||||
result.counter = counter
|
||||
result.init = counter.ast
|
||||
result.cond = cond
|
||||
result.increment = lastStmt
|
||||
result.body = newNodeI(nkStmtList, loop[1].info)
|
||||
copyExcept(loop[1], lastStmt, result.body)
|
||||
@@ -51,10 +51,10 @@ Files: "configure;makefile"
|
||||
Files: "*.ini"
|
||||
Files: "koch.nim"
|
||||
|
||||
Files: "icons/nimrod.ico"
|
||||
Files: "icons/nimrod.rc"
|
||||
Files: "icons/nimrod.res"
|
||||
Files: "icons/nimrod_icon.o"
|
||||
Files: "icons/nim.ico"
|
||||
Files: "icons/nim.rc"
|
||||
Files: "icons/nim.res"
|
||||
Files: "icons/nim_icon.o"
|
||||
Files: "icons/koch.ico"
|
||||
Files: "icons/koch.rc"
|
||||
Files: "icons/koch.res"
|
||||
@@ -148,7 +148,7 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||
tyVarargs:
|
||||
result = etyObject
|
||||
of tyNil: result = etyNull
|
||||
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation,
|
||||
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
|
||||
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
|
||||
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
|
||||
result = etyNone
|
||||
|
||||
@@ -15,7 +15,7 @@ import
|
||||
|
||||
discard """
|
||||
The basic approach is that captured vars need to be put on the heap and
|
||||
that the calling chain needs to be explicitely modelled. Things to consider:
|
||||
that the calling chain needs to be explicitly modelled. Things to consider:
|
||||
|
||||
proc a =
|
||||
var v = 0
|
||||
@@ -583,7 +583,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
|
||||
elif it.kind == nkIdentDefs:
|
||||
var L = sonsLen(it)
|
||||
if it.sons[0].kind == nkSym:
|
||||
# this can be false for recursive invokations that already
|
||||
# this can be false for recursive invocations that already
|
||||
# transformed it into 'env.varName':
|
||||
env.vars.incl(it.sons[0].sym.id)
|
||||
searchForInnerProcs(o, it.sons[L-1], env)
|
||||
@@ -999,7 +999,7 @@ proc liftForLoop*(body: PNode): PNode =
|
||||
# proc invoke(iter: iterator(): int) =
|
||||
# for x in iter(): echo x
|
||||
#
|
||||
# --> When to create the closure? --> for the (count) occurence!
|
||||
# --> When to create the closure? --> for the (count) occurrence!
|
||||
discard """
|
||||
for i in foo(): ...
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ type
|
||||
TToken* = object # a Nim token
|
||||
tokType*: TTokType # the type of the token
|
||||
indent*: int # the indentation; != -1 if the token has been
|
||||
# preceeded with indentation
|
||||
# preceded with indentation
|
||||
ident*: PIdent # the parsed identifier
|
||||
iNumber*: BiggestInt # the parsed integer literal
|
||||
fNumber*: BiggestFloat # the parsed floating point literal
|
||||
@@ -181,10 +181,8 @@ proc prettyTok*(tok: TToken): string =
|
||||
else: result = tokToStr(tok)
|
||||
|
||||
proc printTok*(tok: TToken) =
|
||||
write(stdout, tok.line, ":", tok.col, "\t")
|
||||
write(stdout, TokTypeToStr[tok.tokType])
|
||||
write(stdout, " ")
|
||||
writeln(stdout, tokToStr(tok))
|
||||
msgWriteln($tok.line & ":" & $tok.col & "\t" &
|
||||
TokTypeToStr[tok.tokType] & " " & tokToStr(tok))
|
||||
|
||||
var dummyIdent: PIdent
|
||||
|
||||
@@ -679,7 +677,7 @@ proc getOperator(L: var TLexer, tok: var TToken) =
|
||||
inc(pos)
|
||||
endOperator(L, tok, pos, h)
|
||||
# advance pos but don't store it in L.bufpos so the next token (which might
|
||||
# be an operator too) gets the preceeding spaces:
|
||||
# be an operator too) gets the preceding spaces:
|
||||
tok.strongSpaceB = 0
|
||||
while buf[pos] == ' ':
|
||||
inc pos
|
||||
|
||||
@@ -30,47 +30,32 @@ type
|
||||
|
||||
PLLStream* = ref TLLStream
|
||||
|
||||
proc llStreamOpen*(data: string): PLLStream
|
||||
proc llStreamOpen*(f: var File): PLLStream
|
||||
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream
|
||||
proc llStreamOpen*(): PLLStream
|
||||
proc llStreamOpenStdIn*(): PLLStream
|
||||
proc llStreamClose*(s: PLLStream)
|
||||
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int
|
||||
proc llStreamReadLine*(s: PLLStream, line: var string): bool
|
||||
proc llStreamReadAll*(s: PLLStream): string
|
||||
proc llStreamWrite*(s: PLLStream, data: string)
|
||||
proc llStreamWrite*(s: PLLStream, data: char)
|
||||
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int)
|
||||
proc llStreamWriteln*(s: PLLStream, data: string)
|
||||
# implementation
|
||||
|
||||
proc llStreamOpen(data: string): PLLStream =
|
||||
proc llStreamOpen*(data: string): PLLStream =
|
||||
new(result)
|
||||
result.s = data
|
||||
result.kind = llsString
|
||||
|
||||
proc llStreamOpen(f: var File): PLLStream =
|
||||
proc llStreamOpen*(f: File): PLLStream =
|
||||
new(result)
|
||||
result.f = f
|
||||
result.kind = llsFile
|
||||
|
||||
proc llStreamOpen(filename: string, mode: FileMode): PLLStream =
|
||||
proc llStreamOpen*(filename: string, mode: FileMode): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsFile
|
||||
if not open(result.f, filename, mode): result = nil
|
||||
|
||||
proc llStreamOpen(): PLLStream =
|
||||
proc llStreamOpen*(): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsNone
|
||||
|
||||
proc llStreamOpenStdIn(): PLLStream =
|
||||
proc llStreamOpenStdIn*(): PLLStream =
|
||||
new(result)
|
||||
result.kind = llsStdIn
|
||||
result.s = ""
|
||||
result.lineOffset = -1
|
||||
|
||||
proc llStreamClose(s: PLLStream) =
|
||||
proc llStreamClose*(s: PLLStream) =
|
||||
case s.kind
|
||||
of llsNone, llsString, llsStdIn:
|
||||
discard
|
||||
@@ -130,7 +115,7 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
copyMem(buf, addr(s.s[s.rd]), result)
|
||||
inc(s.rd, result)
|
||||
|
||||
proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
case s.kind
|
||||
of llsNone:
|
||||
result = 0
|
||||
@@ -144,7 +129,7 @@ proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
|
||||
of llsStdIn:
|
||||
result = llReadFromStdin(s, buf, bufLen)
|
||||
|
||||
proc llStreamReadLine(s: PLLStream, line: var string): bool =
|
||||
proc llStreamReadLine*(s: PLLStream, line: var string): bool =
|
||||
setLen(line, 0)
|
||||
case s.kind
|
||||
of llsNone:
|
||||
@@ -168,7 +153,7 @@ proc llStreamReadLine(s: PLLStream, line: var string): bool =
|
||||
of llsStdIn:
|
||||
result = readLine(stdin, line)
|
||||
|
||||
proc llStreamWrite(s: PLLStream, data: string) =
|
||||
proc llStreamWrite*(s: PLLStream, data: string) =
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
discard
|
||||
@@ -178,11 +163,11 @@ proc llStreamWrite(s: PLLStream, data: string) =
|
||||
of llsFile:
|
||||
write(s.f, data)
|
||||
|
||||
proc llStreamWriteln(s: PLLStream, data: string) =
|
||||
proc llStreamWriteln*(s: PLLStream, data: string) =
|
||||
llStreamWrite(s, data)
|
||||
llStreamWrite(s, "\n")
|
||||
|
||||
proc llStreamWrite(s: PLLStream, data: char) =
|
||||
proc llStreamWrite*(s: PLLStream, data: char) =
|
||||
var c: char
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
@@ -194,7 +179,7 @@ proc llStreamWrite(s: PLLStream, data: char) =
|
||||
c = data
|
||||
discard writeBuffer(s.f, addr(c), sizeof(c))
|
||||
|
||||
proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
|
||||
proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) =
|
||||
case s.kind
|
||||
of llsNone, llsStdIn:
|
||||
discard
|
||||
@@ -206,7 +191,7 @@ proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
|
||||
of llsFile:
|
||||
discard writeBuffer(s.f, buf, buflen)
|
||||
|
||||
proc llStreamReadAll(s: PLLStream): string =
|
||||
proc llStreamReadAll*(s: PLLStream): string =
|
||||
const
|
||||
bufSize = 2048
|
||||
case s.kind
|
||||
|
||||
@@ -176,7 +176,7 @@ proc addInterfaceDeclAux(c: PContext, sym: PSym) =
|
||||
if sfExported in sym.flags:
|
||||
# add to interface:
|
||||
if c.module != nil: strTableAdd(c.module.tab, sym)
|
||||
else: internalError(sym.info, "AddInterfaceDeclAux")
|
||||
else: internalError(sym.info, "addInterfaceDeclAux")
|
||||
|
||||
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
|
||||
addDeclAt(scope, sym)
|
||||
|
||||
@@ -62,7 +62,7 @@ proc commandCompileToC =
|
||||
compileProject()
|
||||
cgenWriteModules()
|
||||
if gCmd != cmdRun:
|
||||
extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
|
||||
extccomp.callCCompiler(if gProjectName == "-": "stdinfile" else: changeFileExt(gProjectFull, ""))
|
||||
|
||||
if isServing:
|
||||
# caas will keep track only of the compilation commands
|
||||
@@ -251,7 +251,6 @@ proc mainCommand* =
|
||||
commandCompileToC()
|
||||
of "cpp", "compiletocpp":
|
||||
gCmd = cmdCompileToCpp
|
||||
if cCompiler == ccGcc: setCC("gcc")
|
||||
defineSymbol("cpp")
|
||||
commandCompileToC()
|
||||
of "objc", "compiletooc":
|
||||
|
||||
@@ -116,7 +116,7 @@ proc newModule(fileIdx: int32): PSym =
|
||||
result.kind = skModule
|
||||
let filename = fileIdx.toFullPath
|
||||
result.name = getIdent(splitFile(filename).name)
|
||||
if not isNimIdentifier(result.name.s):
|
||||
if result.name.s != "-" and not isNimIdentifier(result.name.s):
|
||||
rawMessage(errInvalidModuleName, result.name.s)
|
||||
|
||||
result.info = newLineInfo(fileIdx, 1, 1)
|
||||
|
||||
@@ -69,7 +69,7 @@ type
|
||||
errInvalidOrderInArrayConstructor,
|
||||
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
|
||||
errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
|
||||
errUnkownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
|
||||
errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
|
||||
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
|
||||
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
|
||||
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
|
||||
@@ -89,7 +89,7 @@ type
|
||||
errTIsNotAConcreteType,
|
||||
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
|
||||
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
|
||||
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely,
|
||||
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
|
||||
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
|
||||
errMacroBodyDependsOnGenericTypes,
|
||||
errDestructorNotGenericEnough,
|
||||
@@ -113,7 +113,7 @@ type
|
||||
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
|
||||
warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
||||
warnFieldXNotSupported, warnCommentXIgnored,
|
||||
warnNilStatement, warnAnalysisLoophole,
|
||||
warnNilStatement, warnTypelessParam,
|
||||
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnEachIdentIsTuple, warnShadowIdent,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
@@ -280,7 +280,7 @@ const
|
||||
errOptionExpected: "option expected, but found \'$1\'",
|
||||
errXisNoLabel: "\'$1\' is not a label",
|
||||
errNotAllCasesCovered: "not all cases are covered",
|
||||
errUnkownSubstitionVar: "unknown substitution variable: \'$1\'",
|
||||
errUnknownSubstitionVar: "unknown substitution variable: \'$1\'",
|
||||
errComplexStmtRequiresInd: "complex statement requires indentation",
|
||||
errXisNotCallable: "\'$1\' is not callable",
|
||||
errNoPragmasAllowedForX: "no pragmas allowed for $1",
|
||||
@@ -312,7 +312,7 @@ const
|
||||
errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
|
||||
errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
|
||||
errTemplateInstantiationTooNested: "template/macro instantiation too nested",
|
||||
errInstantiationFrom: "instantiation from here",
|
||||
errInstantiationFrom: "template/generic instantiation from here",
|
||||
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
|
||||
errCommandExpectsFilename: "command expects a filename argument",
|
||||
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
|
||||
@@ -326,12 +326,12 @@ const
|
||||
errXisNoValidIndexFile: "\'$1\' is no valid index file",
|
||||
errCannotRenderX: "cannot render reStructuredText element \'$1\'",
|
||||
errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
|
||||
errInstantiateXExplicitely: "instantiate '$1' explicitely",
|
||||
errInstantiateXExplicitly: "instantiate '$1' explicitly",
|
||||
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
|
||||
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
|
||||
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
|
||||
"because the parameter '$1' has a generic type",
|
||||
errDestructorNotGenericEnough: "Destructor signarue is too specific. " &
|
||||
errDestructorNotGenericEnough: "Destructor signature is too specific. " &
|
||||
"A destructor must be associated will all instantiations of a generic type",
|
||||
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
|
||||
"templates, macros and other inline iterators",
|
||||
@@ -360,7 +360,7 @@ const
|
||||
errCannotInferReturnType: "cannot infer the return type of the proc",
|
||||
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
|
||||
"it is used as an operand to another routine and the types " &
|
||||
"of the generic paramers can be infered from the expected signature.",
|
||||
"of the generic paramers can be inferred from the expected signature.",
|
||||
errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
|
||||
@@ -377,7 +377,7 @@ const
|
||||
warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
|
||||
warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
|
||||
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
|
||||
warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]",
|
||||
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]",
|
||||
warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]",
|
||||
warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]",
|
||||
warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]",
|
||||
@@ -420,7 +420,7 @@ const
|
||||
"RedefinitionOfLabel", "UnknownSubstitutionX",
|
||||
"LanguageXNotSupported", "FieldXNotSupported",
|
||||
"CommentXIgnored", "NilStmt",
|
||||
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
|
||||
"TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
|
||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "User"]
|
||||
@@ -445,7 +445,7 @@ type
|
||||
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
TFileInfo*{.final.} = object
|
||||
TFileInfo* = object
|
||||
fullPath: string # This is a canonical full filesystem path
|
||||
projPath*: string # This is relative to the project's root
|
||||
shortName*: string # short name of the module
|
||||
@@ -460,9 +460,9 @@ type
|
||||
# and parsed; usually 'nil' but is used
|
||||
# for 'nimsuggest'
|
||||
|
||||
TLineInfo*{.final.} = object # This is designed to be as small as possible,
|
||||
TLineInfo* = object # This is designed to be as small as possible,
|
||||
# because it is used
|
||||
# in syntax nodes. We safe space here by using
|
||||
# in syntax nodes. We save space here by using
|
||||
# two int16 and an int32.
|
||||
# On 64 bit and on 32 bit systems this is
|
||||
# only 8 bytes.
|
||||
@@ -495,7 +495,7 @@ proc toCChar*(c: char): string =
|
||||
|
||||
proc makeCString*(s: string): PRope =
|
||||
# BUGFIX: We have to split long strings into many ropes. Otherwise
|
||||
# this could trigger an InternalError(). See the ropes module for
|
||||
# this could trigger an internalError(). See the ropes module for
|
||||
# further information.
|
||||
const
|
||||
MaxLineLength = 64
|
||||
@@ -524,7 +524,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
||||
if optEmbedOrigSrc in gGlobalOptions or true:
|
||||
result.lines = @[]
|
||||
|
||||
proc fileInfoIdx*(filename: string): int32 =
|
||||
proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
|
||||
var
|
||||
canon: string
|
||||
pseudoPath = false
|
||||
@@ -541,11 +541,16 @@ proc fileInfoIdx*(filename: string): int32 =
|
||||
if filenameToIndexTbl.hasKey(canon):
|
||||
result = filenameToIndexTbl[canon]
|
||||
else:
|
||||
isKnownFile = false
|
||||
result = fileInfos.len.int32
|
||||
fileInfos.add(newFileInfo(canon, if pseudoPath: filename
|
||||
else: canon.shortenDir))
|
||||
filenameToIndexTbl[canon] = result
|
||||
|
||||
proc fileInfoIdx*(filename: string): int32 =
|
||||
var dummy: bool
|
||||
result = fileInfoIdx(filename, dummy)
|
||||
|
||||
proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
|
||||
result.fileIndex = fileInfoIdx
|
||||
result.line = int16(line)
|
||||
@@ -693,7 +698,9 @@ proc msgWriteln*(s: string) =
|
||||
|
||||
#if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
|
||||
if optStdout in gGlobalOptions:
|
||||
if not isNil(writelnHook):
|
||||
writelnHook(s)
|
||||
elif optStdout in gGlobalOptions:
|
||||
if eStdErr in errorOutputs: writeln(stderr, s)
|
||||
else:
|
||||
if eStdOut in errorOutputs: writeln(stdout, s)
|
||||
@@ -717,7 +724,10 @@ type
|
||||
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
||||
template quit =
|
||||
if defined(debug) or gVerbosity >= 3 or msg == errInternal:
|
||||
writeStackTrace()
|
||||
if stackTraceAvailable() and isNil(writelnHook):
|
||||
writeStackTrace()
|
||||
else:
|
||||
msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>")
|
||||
quit 1
|
||||
|
||||
if msg >= fatalMin and msg <= fatalMax:
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
when defined(gcc) and defined(windows):
|
||||
when defined(x86):
|
||||
{.link: "icons/nimrod.res".}
|
||||
{.link: "icons/nim.res".}
|
||||
else:
|
||||
{.link: "icons/nimrod_icon.o".}
|
||||
{.link: "icons/nim_icon.o".}
|
||||
|
||||
import
|
||||
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
|
||||
@@ -61,6 +61,8 @@ proc handleCmdLine() =
|
||||
if gCmd == cmdRun:
|
||||
tccgen.run(commands.arguments)
|
||||
if optRun in gGlobalOptions:
|
||||
if gProjectName == "-":
|
||||
gProjectFull = "stdinfile"
|
||||
if gCmd == cmdCompileToJS:
|
||||
var ex: string
|
||||
if options.outFile.len > 0:
|
||||
|
||||
@@ -33,7 +33,7 @@ proc `<.`(a, b: string): bool =
|
||||
while true:
|
||||
let ii = parseInt(a, verA, i)
|
||||
let jj = parseInt(b, verB, j)
|
||||
# if A has no number left, but B has, B is prefered: 0.8 vs 0.8.3
|
||||
# if A has no number left, but B has, B is preferred: 0.8 vs 0.8.3
|
||||
if ii <= 0 or jj <= 0: return jj > 0
|
||||
if verA < verB: return true
|
||||
elif verA > verB: return false
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
|
||||
import
|
||||
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
|
||||
options, idents, wordrecg
|
||||
options, idents, wordrecg, strtabs
|
||||
|
||||
# ---------------- configuration file parser -----------------------------
|
||||
# we use Nim's scanner here to safe space and work
|
||||
# we use Nim's scanner here to save space and work
|
||||
|
||||
proc ppGetTok(L: var TLexer, tok: var TToken) =
|
||||
# simple filter
|
||||
@@ -82,17 +82,17 @@ proc doElif(L: var TLexer, tok: var TToken) =
|
||||
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
|
||||
var nestedIfs = 0
|
||||
while true:
|
||||
if (tok.ident != nil) and (tok.ident.s == "@"):
|
||||
if tok.ident != nil and tok.ident.s == "@":
|
||||
ppGetTok(L, tok)
|
||||
case whichKeyword(tok.ident)
|
||||
of wIf:
|
||||
inc(nestedIfs)
|
||||
of wElse:
|
||||
if (dest == jdElseEndif) and (nestedIfs == 0):
|
||||
if dest == jdElseEndif and nestedIfs == 0:
|
||||
doElse(L, tok)
|
||||
break
|
||||
of wElif:
|
||||
if (dest == jdElseEndif) and (nestedIfs == 0):
|
||||
if dest == jdElseEndif and nestedIfs == 0:
|
||||
doElif(L, tok)
|
||||
break
|
||||
of wEnd:
|
||||
@@ -119,9 +119,10 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
|
||||
of wElif: doElif(L, tok)
|
||||
of wElse: doElse(L, tok)
|
||||
of wEnd: doEnd(L, tok)
|
||||
of wWrite:
|
||||
of wWrite:
|
||||
ppGetTok(L, tok)
|
||||
msgs.msgWriteln(tokToStr(tok))
|
||||
msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars,
|
||||
{useEnvironment, useKey}))
|
||||
ppGetTok(L, tok)
|
||||
else:
|
||||
case tok.ident.s.normalize
|
||||
@@ -157,7 +158,7 @@ proc checkSymbol(L: TLexer, tok: TToken) =
|
||||
proc parseAssignment(L: var TLexer, tok: var TToken) =
|
||||
if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id:
|
||||
confTok(L, tok) # skip unnecessary prefix
|
||||
var info = getLineInfo(L, tok) # safe for later in case of an error
|
||||
var info = getLineInfo(L, tok) # save for later in case of an error
|
||||
checkSymbol(L, tok)
|
||||
var s = tokToStr(tok)
|
||||
confTok(L, tok) # skip symbol
|
||||
@@ -178,9 +179,10 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
|
||||
if tok.tokType == tkBracketRi: confTok(L, tok)
|
||||
else: lexMessage(L, errTokenExpected, "']'")
|
||||
add(val, ']')
|
||||
if tok.tokType in {tkColon, tkEquals}:
|
||||
let percent = tok.ident.id == getIdent("%=").id
|
||||
if tok.tokType in {tkColon, tkEquals} or percent:
|
||||
if len(val) > 0: add(val, ':')
|
||||
confTok(L, tok) # skip ':' or '='
|
||||
confTok(L, tok) # skip ':' or '=' or '%'
|
||||
checkSymbol(L, tok)
|
||||
add(val, tokToStr(tok))
|
||||
confTok(L, tok) # skip symbol
|
||||
@@ -189,7 +191,11 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
|
||||
checkSymbol(L, tok)
|
||||
add(val, tokToStr(tok))
|
||||
confTok(L, tok)
|
||||
processSwitch(s, val, passPP, info)
|
||||
if percent:
|
||||
processSwitch(s, strtabs.`%`(val, options.gConfigVars,
|
||||
{useEnvironment, useEmpty}), passPP, info)
|
||||
else:
|
||||
processSwitch(s, val, passPP, info)
|
||||
|
||||
proc readConfigFile(filename: string) =
|
||||
var
|
||||
@@ -246,6 +252,11 @@ proc loadConfigs*(cfg: string) =
|
||||
|
||||
if gProjectName.len != 0:
|
||||
# new project wide config file:
|
||||
let projectConfig = changeFileExt(gProjectFull, "nim.cfg")
|
||||
if fileExists(projectConfig): readConfigFile(projectConfig)
|
||||
else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg"))
|
||||
var projectConfig = changeFileExt(gProjectFull, "nimcfg")
|
||||
if not fileExists(projectConfig):
|
||||
projectConfig = changeFileExt(gProjectFull, "nim.cfg")
|
||||
if not fileExists(projectConfig):
|
||||
projectConfig = changeFileExt(gProjectFull, "nimrod.cfg")
|
||||
if fileExists(projectConfig):
|
||||
rawMessage(warnDeprecated, projectConfig)
|
||||
readConfigFile(projectConfig)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# gc:markAndSweep
|
||||
|
||||
hint[XDeclaredButNotUsed]:off
|
||||
path:"$projectPath/../.."
|
||||
path:"$projectPath/.."
|
||||
|
||||
path:"$lib/packages/docutils"
|
||||
path:"$nim/compiler"
|
||||
|
||||
@@ -87,8 +87,9 @@ proc action(cmd: string) =
|
||||
i += skipWhile(cmd, seps, i)
|
||||
i += parseInt(cmd, col, i)
|
||||
|
||||
var isKnownFile = true
|
||||
if orig.len == 0: err()
|
||||
let dirtyIdx = orig.fileInfoIdx
|
||||
let dirtyIdx = orig.fileInfoIdx(isKnownFile)
|
||||
|
||||
if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile)
|
||||
else: msgs.setDirtyFile(dirtyIdx, nil)
|
||||
@@ -99,7 +100,10 @@ proc action(cmd: string) =
|
||||
gTrackPos = newLineInfo(dirtyIdx, line, col)
|
||||
#echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx
|
||||
gErrorCounter = 0
|
||||
compileProject()
|
||||
if not isKnownFile:
|
||||
compileProject(dirtyIdx)
|
||||
else:
|
||||
compileProject()
|
||||
|
||||
proc serve() =
|
||||
# do not stop after the first error:
|
||||
@@ -116,13 +120,17 @@ proc serve() =
|
||||
server.bindAddr(gPort, gAddress)
|
||||
var inp = "".TaintedString
|
||||
server.listen()
|
||||
var stdoutSocket = newSocket()
|
||||
msgs.writelnHook = proc (line: string) =
|
||||
stdoutSocket.send(line & "\c\L")
|
||||
|
||||
while true:
|
||||
var stdoutSocket = newSocket()
|
||||
msgs.writelnHook = proc (line: string) =
|
||||
stdoutSocket.send(line & "\c\L")
|
||||
|
||||
accept(server, stdoutSocket)
|
||||
|
||||
stdoutSocket.readLine(inp)
|
||||
action inp.string
|
||||
|
||||
stdoutSocket.send("\c\L")
|
||||
stdoutSocket.close()
|
||||
|
||||
|
||||
@@ -283,19 +283,19 @@ when noTimeMachine:
|
||||
var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
|
||||
discard p.waitForExit
|
||||
p.close
|
||||
except E_Base, EOS:
|
||||
except Exception:
|
||||
discard
|
||||
|
||||
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
||||
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
||||
var (head, tail) = splitPath(f)
|
||||
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
|
||||
var subdir = getGeneratedPath() # / head
|
||||
if createSubDir:
|
||||
try:
|
||||
try:
|
||||
createDir(subdir)
|
||||
when noTimeMachine:
|
||||
excludeDirFromTimeMachine(subdir)
|
||||
except OSError:
|
||||
except OSError:
|
||||
writeln(stdout, "cannot create directory: " & subdir)
|
||||
quit(1)
|
||||
result = joinPath(subdir, tail)
|
||||
|
||||
@@ -198,8 +198,8 @@ proc isSigilLike(tok: TToken): bool {.inline.} =
|
||||
|
||||
proc isRightAssociative(tok: TToken): bool {.inline.} =
|
||||
## Determines whether the token is right assocative.
|
||||
result = tok.tokType == tkOpr and (tok.ident.s[0] == '^' or
|
||||
(let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
|
||||
result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
|
||||
# or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
|
||||
|
||||
proc getPrecedence(tok: TToken, strongSpaces: bool): int =
|
||||
## Calculates the precedence of the given token.
|
||||
@@ -1597,6 +1597,7 @@ proc parseEnum(p: var TParser): PNode =
|
||||
optInd(p, result)
|
||||
while true:
|
||||
var a = parseSymbol(p)
|
||||
if a.kind == nkEmpty: return
|
||||
if p.tok.indent >= 0 and p.tok.indent <= p.currInd:
|
||||
add(result, a)
|
||||
break
|
||||
|
||||
@@ -170,7 +170,11 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
||||
openPasses(a, module)
|
||||
if stream == nil:
|
||||
let filename = fileIdx.toFullPathConsiderDirty
|
||||
s = llStreamOpen(filename, fmRead)
|
||||
if module.name.s == "-":
|
||||
module.name.s = "stdinfile"
|
||||
s = llStreamOpen(stdin)
|
||||
else:
|
||||
s = llStreamOpen(filename, fmRead)
|
||||
if s == nil:
|
||||
rawMessage(errCannotOpenFile, filename)
|
||||
return
|
||||
|
||||
@@ -275,7 +275,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||
if arg != rs and aliases.isPartOf(rs, arg) == arYes:
|
||||
ok = true
|
||||
break
|
||||
# constraint not fullfilled:
|
||||
# constraint not fulfilled:
|
||||
if not ok: return nil
|
||||
of aqNoAlias:
|
||||
# it MUST not alias with any other param:
|
||||
@@ -284,7 +284,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
|
||||
if arg != rs and aliases.isPartOf(rs, arg) != arNo:
|
||||
ok = false
|
||||
break
|
||||
# constraint not fullfilled:
|
||||
# constraint not fulfilled:
|
||||
if not ok: return nil
|
||||
|
||||
markUsed(n.info, s)
|
||||
|
||||
@@ -138,7 +138,7 @@ const
|
||||
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
|
||||
(name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
|
||||
scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".",
|
||||
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
|
||||
(name: "JS", parDir: "..",
|
||||
dllFrmt: "lib$1.so", altDirSep: "/",
|
||||
|
||||
@@ -735,11 +735,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
|
||||
incl(sym.flags, sfProcvar)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfThread)
|
||||
of wGcSafe:
|
||||
if optThreadAnalysis in gGlobalOptions:
|
||||
noVal(it)
|
||||
if sym.kind != skType: incl(sym.flags, sfThread)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
|
||||
else: invalidPragma(it)
|
||||
noVal(it)
|
||||
if sym.kind != skType: incl(sym.flags, sfThread)
|
||||
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
|
||||
else: invalidPragma(it)
|
||||
of wPacked:
|
||||
noVal(it)
|
||||
if sym.typ == nil: invalidPragma(it)
|
||||
|
||||
@@ -666,7 +666,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
|
||||
r.readerIndex = readerIndex
|
||||
r.filename = modfilename
|
||||
initIdTable(r.syms)
|
||||
# we terminate the file explicitely with ``\0``, so the cast to `cstring`
|
||||
# we terminate the file explicitly with ``\0``, so the cast to `cstring`
|
||||
# is safe:
|
||||
r.s = cast[cstring](r.memfile.mem)
|
||||
if startsWith(r.s, "NIM:"):
|
||||
|
||||
@@ -200,7 +200,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
|
||||
return
|
||||
# we need no surrounding [] here because the type is in a line of its own
|
||||
if t.kind == tyForward: internalError("encodeType: tyForward")
|
||||
# for the new rodfile viewer we use a preceeding [ so that the data section
|
||||
# for the new rodfile viewer we use a preceding [ so that the data section
|
||||
# can easily be disambiguated:
|
||||
add(result, '[')
|
||||
encodeVInt(ord(t.kind), result)
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
# Note that the left and right pointers are not needed for leaves.
|
||||
# Leaves have relatively high memory overhead (~30 bytes on a 32
|
||||
# bit machines) and we produce many of them. This is why we cache and
|
||||
# share leaves accross different rope trees.
|
||||
# share leaves across different rope trees.
|
||||
# To cache them they are inserted in a `cache` array.
|
||||
|
||||
import
|
||||
|
||||
@@ -95,15 +95,6 @@ proc inferWithMetatype(c: PContext, formal: PType,
|
||||
|
||||
var commonTypeBegin = PType(kind: tyExpr)
|
||||
|
||||
proc isEmptyContainer(t: PType): bool =
|
||||
case t.kind
|
||||
of tyExpr, tyNil: result = true
|
||||
of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
|
||||
of tySet, tySequence, tyOpenArray, tyVarargs:
|
||||
result = t.sons[0].kind == tyEmpty
|
||||
of tyGenericInst: result = isEmptyContainer(t.lastSon)
|
||||
else: result = false
|
||||
|
||||
proc commonType*(x, y: PType): PType =
|
||||
# new type relation that is used for array constructors,
|
||||
# if expressions, etc.:
|
||||
@@ -130,9 +121,11 @@ proc commonType*(x, y: PType): PType =
|
||||
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]):
|
||||
let aEmpty = isEmptyContainer(a.sons[i])
|
||||
let bEmpty = isEmptyContainer(b.sons[i])
|
||||
if aEmpty != bEmpty:
|
||||
if nt.isNil: nt = copyType(a, a.owner, false)
|
||||
nt.sons[i] = b.sons[i]
|
||||
nt.sons[i] = if aEmpty: b.sons[i] else: a.sons[i]
|
||||
if not nt.isNil: result = nt
|
||||
#elif b.sons[idx].kind == tyEmpty: return x
|
||||
elif a.kind == tyRange and b.kind == tyRange:
|
||||
|
||||
@@ -184,7 +184,7 @@ proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) =
|
||||
of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
|
||||
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
|
||||
tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
|
||||
tyTypeDesc, tyGenericInvokation, tyBigNum, tyConst, tyForward:
|
||||
tyTypeDesc, tyGenericInvocation, tyBigNum, tyConst, tyForward:
|
||||
internalError(c.info, "assignment requested for type: " & typeToString(t))
|
||||
of tyDistinct, tyOrdinal, tyRange,
|
||||
tyGenericInst, tyFieldAccessor, tyStatic, tyVar:
|
||||
|
||||
@@ -42,7 +42,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
errors: var CandidateErrors) =
|
||||
var o: TOverloadIter
|
||||
var sym = initOverloadIter(o, c, headSymbol)
|
||||
var symScope = o.lastOverloadScope
|
||||
let symScope = o.lastOverloadScope
|
||||
|
||||
var z: TCandidate
|
||||
|
||||
@@ -56,6 +56,9 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
determineType(c, sym)
|
||||
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
|
||||
z.calleeSym = sym
|
||||
|
||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||
# gDebug = true
|
||||
matches(c, n, orig, z)
|
||||
if errors != nil:
|
||||
errors.safeAdd(sym)
|
||||
@@ -72,9 +75,13 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
|
||||
if cmp < 0: best = z # x is better than the best so far
|
||||
elif cmp == 0: alt = z # x is as good as the best so far
|
||||
else: discard
|
||||
#if sym.name.s == "shl" and (n.info ?? "net.nim"):
|
||||
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
|
||||
# echo "Matches ", n.info, " ", typeToString(sym.typ)
|
||||
# debug sym
|
||||
# writeMatches(z)
|
||||
# for i in 1 .. <len(z.call):
|
||||
# z.call[i].typ.debug
|
||||
# quit 1
|
||||
sym = nextOverloadIter(o, c, headSymbol)
|
||||
|
||||
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
|
||||
@@ -264,7 +271,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
|
||||
instGenericConvertersArg(c, result, m)
|
||||
if result != nil:
|
||||
# This almost exactly replicates the steps taken by the compiler during
|
||||
# param matching. It performs an embarassing ammount of back-and-forth
|
||||
# param matching. It performs an embarrassing amount of back-and-forth
|
||||
# type jugling, but it's the price to pay for consistency and correctness
|
||||
result.typ = generateTypeInstance(c, m.bindings, arg.info,
|
||||
formal.skipTypes({tyCompositeTypeClass}))
|
||||
@@ -315,6 +322,8 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
|
||||
var r = resolveOverloads(c, n, nOrig, filter, errors)
|
||||
if r.state == csMatch: result = semResolvedCall(c, n, r)
|
||||
else:
|
||||
# get rid of the deref again for a better error message:
|
||||
n.sons[1] = n.sons[1].sons[0]
|
||||
notFoundError(c, n, errors)
|
||||
else:
|
||||
notFoundError(c, n, errors)
|
||||
|
||||
@@ -221,6 +221,7 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
|
||||
|
||||
proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
|
||||
result = newTypeS(tyFromExpr, c)
|
||||
assert n != nil
|
||||
result.n = n
|
||||
|
||||
proc newTypeWithSons*(c: PContext, kind: TTypeKind,
|
||||
|
||||
@@ -30,7 +30,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType
|
||||
|
||||
proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
|
||||
var t = s.typ.sons[1].skipTypes({tyVar})
|
||||
if t.kind == tyGenericInvokation:
|
||||
if t.kind == tyGenericInvocation:
|
||||
for i in 1 .. <t.sonsLen:
|
||||
if t.sons[i].kind != tyGenericParam:
|
||||
localError(n.info, errDestructorNotGenericEnough)
|
||||
|
||||
@@ -103,28 +103,31 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
||||
result = newSymNode(s, n.info)
|
||||
of skMacro: result = semMacroExpr(c, n, n, s, flags)
|
||||
of skTemplate: result = semTemplateExpr(c, n, s, flags)
|
||||
of skVar, skLet, skResult, skParam, skForVar:
|
||||
of skParam:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
if s.typ.kind == tyStatic and s.typ.n != nil:
|
||||
# XXX see the hack in sigmatch.nim ...
|
||||
return s.typ.n
|
||||
elif sfGenSym in s.flags:
|
||||
if c.p.wasForwarded:
|
||||
# gensym'ed parameters that nevertheless have been forward declared
|
||||
# need a special fixup:
|
||||
let realParam = c.p.owner.typ.n[s.position+1]
|
||||
internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
|
||||
return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
|
||||
elif c.p.owner.kind == skMacro:
|
||||
# gensym'ed macro parameters need a similar hack (see bug #1944):
|
||||
var u = searchInScopes(c, s.name)
|
||||
internalAssert u != nil and u.kind == skParam and u.owner == s.owner
|
||||
return newSymNode(u, n.info)
|
||||
result = newSymNode(s, n.info)
|
||||
of skVar, skLet, skResult, skForVar:
|
||||
markUsed(n.info, s)
|
||||
styleCheckUse(n.info, s)
|
||||
# if a proc accesses a global variable, it is not side effect free:
|
||||
if sfGlobal in s.flags:
|
||||
incl(c.p.owner.flags, sfSideEffect)
|
||||
elif s.kind == skParam:
|
||||
if s.typ.kind == tyStatic and s.typ.n != nil:
|
||||
# XXX see the hack in sigmatch.nim ...
|
||||
return s.typ.n
|
||||
elif sfGenSym in s.flags:
|
||||
if c.p.wasForwarded:
|
||||
# gensym'ed parameters that nevertheless have been forward declared
|
||||
# need a special fixup:
|
||||
let realParam = c.p.owner.typ.n[s.position+1]
|
||||
internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam
|
||||
return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info)
|
||||
elif c.p.owner.kind == skMacro:
|
||||
# gensym'ed macro parameters need a similar hack (see bug #1944):
|
||||
var u = searchInScopes(c, s.name)
|
||||
internalAssert u != nil and u.kind == skParam and u.owner == s.owner
|
||||
return newSymNode(u, n.info)
|
||||
result = newSymNode(s, n.info)
|
||||
# We cannot check for access to outer vars for example because it's still
|
||||
# not sure the symbol really ends up being used:
|
||||
@@ -306,7 +309,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
var typ = skipTypes(n.sons[1].typ, abstractVarRange +
|
||||
{tyTypeDesc, tyFieldAccessor})
|
||||
case typ.kind
|
||||
of tySequence, tyString, tyOpenArray, tyVarargs:
|
||||
of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
|
||||
n.typ = getSysType(tyInt)
|
||||
of tyArrayConstr, tyArray:
|
||||
n.typ = typ.sons[0] # indextype
|
||||
@@ -445,25 +448,30 @@ proc changeType(n: PNode, newType: PType, check: bool) =
|
||||
let tup = newType.skipTypes({tyGenericInst})
|
||||
if tup.kind != tyTuple:
|
||||
internalError(n.info, "changeType: no tuple type for constructor")
|
||||
elif newType.n == nil: discard
|
||||
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
|
||||
# named tuple?
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var m = n.sons[i].sons[0]
|
||||
if m.kind != nkSym:
|
||||
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)
|
||||
if tup.n != nil:
|
||||
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:
|
||||
changeType(n.sons[i].sons[1], tup.sons[i], check)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var m = n.sons[i]
|
||||
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
|
||||
addSon(a, newSymNode(newType.n.sons[i].sym))
|
||||
addSon(a, m)
|
||||
changeType(m, tup.sons[i], check)
|
||||
changeType(n.sons[i], tup.sons[i], check)
|
||||
when false:
|
||||
var m = n.sons[i]
|
||||
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
|
||||
addSon(a, newSymNode(newType.n.sons[i].sym))
|
||||
addSon(a, m)
|
||||
changeType(m, tup.sons[i], check)
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
if check:
|
||||
let value = n.intVal
|
||||
@@ -578,11 +586,12 @@ proc skipObjConv(n: PNode): PNode =
|
||||
proc isAssignable(c: PContext, n: PNode): TAssignableResult =
|
||||
result = parampatterns.isAssignable(c.p.owner, n)
|
||||
|
||||
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
|
||||
if n.kind == nkHiddenDeref:
|
||||
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
|
||||
if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or
|
||||
sfCompileToCpp in c.module.flags):
|
||||
checkSonsLen(n, 1)
|
||||
result = n.sons[0]
|
||||
else:
|
||||
else:
|
||||
result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ))
|
||||
addSon(result, n)
|
||||
if isAssignable(c, n) notin {arLValue, arLocalLValue}:
|
||||
@@ -677,7 +686,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||
# implicit statics.
|
||||
if n.len > 1:
|
||||
for i in 1 .. <n.len:
|
||||
if n[i].typ.kind != tyStatic or tfUnresolved notin n[i].typ.flags:
|
||||
# see bug #2113, it's possible that n[i].typ for errornous code:
|
||||
if n[i].typ.isNil or n[i].typ.kind != tyStatic or
|
||||
tfUnresolved notin n[i].typ.flags:
|
||||
break maybeLabelAsStatic
|
||||
n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
|
||||
n.typ.flags.incl tfUnresolved
|
||||
@@ -745,6 +756,9 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
|
||||
else:
|
||||
if callee.kind in skIterators and callee.id == c.p.owner.id:
|
||||
localError(n.info, errRecursiveDependencyX, callee.name.s)
|
||||
# error correction, prevents endless for loop elimination in transf.
|
||||
# See bug #2051:
|
||||
result.sons[0] = newSymNode(errorSym(c, n))
|
||||
if sfNoSideEffect notin callee.flags:
|
||||
if {sfImportc, sfSideEffect} * callee.flags != {}:
|
||||
incl(c.p.owner.flags, sfSideEffect)
|
||||
@@ -1209,6 +1223,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} =
|
||||
if x.typ.kind == tyVar and x.kind == nkSym and x.sym.kind == skResult:
|
||||
n.sons[0] = x # 'result[]' --> 'result'
|
||||
n.sons[1] = takeImplicitAddr(c, ri)
|
||||
x.typ.flags.incl tfVarIsPtr
|
||||
|
||||
template resultTypeIsInferrable(typ: PType): expr =
|
||||
typ.isMetaType and typ.kind != tyTypeDesc
|
||||
@@ -1327,7 +1342,12 @@ proc semProcBody(c: PContext, n: PNode): PNode =
|
||||
|
||||
if c.p.owner.kind notin {skMacro, skTemplate} and
|
||||
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType:
|
||||
localError(c.p.resultSym.info, errCannotInferReturnType)
|
||||
if isEmptyType(result.typ):
|
||||
# we inferred a 'void' return type:
|
||||
c.p.resultSym.typ = nil
|
||||
c.p.owner.typ.sons[0] = nil
|
||||
else:
|
||||
localError(c.p.resultSym.info, errCannotInferReturnType)
|
||||
|
||||
closeScope(c)
|
||||
|
||||
@@ -1492,7 +1512,9 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
|
||||
|
||||
# Preserve the magic symbol in order to be handled in evals.nim
|
||||
internalAssert n.sons[0].sym.magic == mExpandToAst
|
||||
n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
|
||||
#n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType
|
||||
n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
|
||||
else: sysTypeFromName"PNimrodNode"
|
||||
result = n
|
||||
|
||||
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
|
||||
@@ -1620,7 +1642,7 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
result = semDirectOp(c, n, flags)
|
||||
|
||||
proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType =
|
||||
result = newType(tyGenericInvokation, c.module)
|
||||
result = newType(tyGenericInvocation, c.module)
|
||||
addSonSkipIntLit(result, magicsys.getCompilerProc("FlowVar").typ)
|
||||
addSonSkipIntLit(result, t)
|
||||
result = instGenericContainer(c, info, result, allowMetaTypes = false)
|
||||
@@ -1900,7 +1922,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
it.sons[0] = newSymNode(f)
|
||||
e = fitNode(c, f.typ, e)
|
||||
# small hack here in a nkObjConstr the ``nkExprColonExpr`` node can have
|
||||
# 3 childen the last being the field check
|
||||
# 3 children the last being the field check
|
||||
if check != nil:
|
||||
check.sons[0] = it.sons[0]
|
||||
it.add(check)
|
||||
@@ -1984,7 +2006,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
if result.kind == nkSym:
|
||||
markIndirect(c, result.sym)
|
||||
# if isGenericRoutine(result.sym):
|
||||
# localError(n.info, errInstantiateXExplicitely, s.name.s)
|
||||
# localError(n.info, errInstantiateXExplicitly, s.name.s)
|
||||
of nkSym:
|
||||
# because of the changed symbol binding, this does not mean that we
|
||||
# don't have to check the symbol for semantics here again!
|
||||
@@ -2113,7 +2135,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
||||
of nkCurly: result = semSetConstr(c, n)
|
||||
of nkBracket: result = semArrayConstr(c, n, flags)
|
||||
of nkObjConstr: result = semObjConstr(c, n, flags)
|
||||
of nkLambdaKinds: result = semLambda(c, n, flags)
|
||||
of nkLambda: result = semLambda(c, n, flags)
|
||||
of nkDo: result = semDo(c, n, flags)
|
||||
of nkDerefExpr: result = semDeref(c, n)
|
||||
of nkAddr:
|
||||
result = n
|
||||
|
||||
@@ -19,12 +19,13 @@ type
|
||||
|
||||
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
case n.kind
|
||||
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n
|
||||
of nkIdent:
|
||||
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
|
||||
of nkIdent, nkSym:
|
||||
result = n
|
||||
let ident = considerQuotedIdent(n)
|
||||
var L = sonsLen(forLoop)
|
||||
if c.replaceByFieldName:
|
||||
if n.ident.id == forLoop[0].ident.id:
|
||||
if ident.id == considerQuotedIdent(forLoop[0]).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
|
||||
@@ -32,7 +33,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
|
||||
return
|
||||
# other fields:
|
||||
for i in ord(c.replaceByFieldName)..L-3:
|
||||
if n.ident.id == forLoop[i].ident.id:
|
||||
if ident.id == considerQuotedIdent(forLoop[i]).id:
|
||||
var call = forLoop.sons[L-2]
|
||||
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
|
||||
if c.field.isNil:
|
||||
@@ -155,7 +156,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
|
||||
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):
|
||||
if containsNode(stmts, {nkBreakStmt}):
|
||||
var b = newNodeI(nkBreakStmt, n.info)
|
||||
b.add(ast.emptyNode)
|
||||
stmts.add(b)
|
||||
|
||||
@@ -665,8 +665,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
of mLow:
|
||||
result = newIntNodeT(firstOrd(n.sons[1].typ), n)
|
||||
of mHigh:
|
||||
if skipTypes(n.sons[1].typ, abstractVar).kind notin
|
||||
{tyOpenArray, tyVarargs, tySequence, tyString}:
|
||||
if skipTypes(n.sons[1].typ, abstractVar).kind notin
|
||||
{tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
|
||||
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
|
||||
else:
|
||||
var a = getArrayConstr(m, n.sons[1])
|
||||
|
||||
@@ -243,7 +243,7 @@ proc semGenericStmt(c: PContext, n: PNode,
|
||||
elif fn.kind == nkDotExpr:
|
||||
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
|
||||
first = 1
|
||||
# Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
||||
# Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
|
||||
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
|
||||
# is not exported and yet the generic 'threadProcWrapper' works correctly.
|
||||
let flags = if mixinContext: flags+{withinMixin} else: flags
|
||||
|
||||
@@ -36,7 +36,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable,
|
||||
elif t.kind == tyGenericParam:
|
||||
localError(a.info, errCannotInstantiateX, q.name.s)
|
||||
t = errorType(c)
|
||||
elif t.kind == tyGenericInvokation:
|
||||
elif t.kind == tyGenericInvocation:
|
||||
#t = instGenericContainer(c, a, t)
|
||||
t = generateTypeInstance(c, pt, a, t)
|
||||
#t = ReplaceTypeVarsT(cl, t)
|
||||
@@ -77,11 +77,12 @@ proc removeDefaultParamValues(n: PNode) =
|
||||
proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
|
||||
# we need to create a fresh set of gensym'ed symbols:
|
||||
if n.kind == nkSym and sfGenSym in n.sym.flags:
|
||||
var x = PSym(idTableGet(symMap, n.sym))
|
||||
let s = n.sym
|
||||
var x = PSym(idTableGet(symMap, s))
|
||||
if x == nil:
|
||||
x = copySym(n.sym, false)
|
||||
x = copySym(s, false)
|
||||
x.owner = owner
|
||||
idTablePut(symMap, n.sym, x)
|
||||
idTablePut(symMap, s, x)
|
||||
n.sym = x
|
||||
else:
|
||||
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap)
|
||||
@@ -99,13 +100,18 @@ proc addProcDecls(c: PContext, fn: PSym) =
|
||||
|
||||
maybeAddResult(c, fn, fn.ast)
|
||||
|
||||
proc instantiateBody(c: PContext, n: PNode, result: PSym) =
|
||||
proc instantiateBody(c: PContext, n, params: PNode, result: PSym) =
|
||||
if n.sons[bodyPos].kind != nkEmpty:
|
||||
inc c.inGenericInst
|
||||
# add it here, so that recursive generic procs are possible:
|
||||
var b = n.sons[bodyPos]
|
||||
var symMap: TIdTable
|
||||
initIdTable symMap
|
||||
if params != nil:
|
||||
for i in 1 .. <params.len:
|
||||
let param = params[i].sym
|
||||
if sfGenSym in param.flags:
|
||||
idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym)
|
||||
freshGenSyms(b, result, symMap)
|
||||
b = semProcBody(c, b)
|
||||
b = hloBody(c, b)
|
||||
@@ -122,7 +128,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
|
||||
openScope(c)
|
||||
var n = oldPrc.ast
|
||||
n.sons[bodyPos] = copyTree(s.getBody)
|
||||
instantiateBody(c, n, oldPrc)
|
||||
instantiateBody(c, n, nil, oldPrc)
|
||||
closeScope(c)
|
||||
popInfoContext()
|
||||
|
||||
@@ -169,17 +175,27 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
result.n = originalParams.shallowCopy
|
||||
|
||||
for i in 1 .. <result.len:
|
||||
# twrong_field_caching requires these 'resetIdTable' calls:
|
||||
if i > 1: resetIdTable(cl.symMap)
|
||||
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
||||
propagateToOwner(result, result.sons[i])
|
||||
let param = replaceTypeVarsN(cl, originalParams[i])
|
||||
result.n.sons[i] = param
|
||||
if param.kind == nkSym:
|
||||
# XXX: this won't be true for void params
|
||||
# implement pass-through of void params and
|
||||
# the "sort by distance to point" container
|
||||
internalAssert originalParams[i].kind == nkSym
|
||||
when true:
|
||||
let oldParam = originalParams[i].sym
|
||||
let param = copySym(oldParam)
|
||||
param.owner = prc
|
||||
param.typ = result.sons[i]
|
||||
param.ast = oldParam.ast.copyTree
|
||||
# don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])!
|
||||
result.n.sons[i] = newSymNode(param)
|
||||
addDecl(c, param)
|
||||
else:
|
||||
let param = replaceTypeVarsN(cl, originalParams[i])
|
||||
result.n.sons[i] = param
|
||||
param.sym.owner = prc
|
||||
addDecl(c, param.sym)
|
||||
|
||||
addDecl(c, result.n.sons[i].sym)
|
||||
|
||||
resetIdTable(cl.symMap)
|
||||
result.sons[0] = replaceTypeVarsT(cl, result.sons[0])
|
||||
result.n.sons[0] = originalParams[0].copyTree
|
||||
|
||||
@@ -234,7 +250,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
|
||||
if isNil(n.sons[bodyPos]):
|
||||
n.sons[bodyPos] = copyTree(fn.getBody)
|
||||
instantiateBody(c, n, result)
|
||||
instantiateBody(c, n, fn.typ.n, result)
|
||||
sideEffectsCheck(c, result)
|
||||
paramsTypeCheck(c, result.typ)
|
||||
else:
|
||||
|
||||
@@ -23,7 +23,7 @@ import
|
||||
# Predefined effects:
|
||||
# io, time (time dependent), gc (performs GC'ed allocation), exceptions,
|
||||
# side effect (accesses global), store (stores into *type*),
|
||||
# store_unkown (performs some store) --> store(any)|store(x)
|
||||
# store_unknown (performs some store) --> store(any)|store(x)
|
||||
# load (loads from *type*), recursive (recursive call), unsafe,
|
||||
# endless (has endless loops), --> user effects are defined over *patterns*
|
||||
# --> a TR macro can annotate the proc with user defined annotations
|
||||
@@ -194,6 +194,9 @@ proc warnAboutGcUnsafe(n: PNode) =
|
||||
#assert false
|
||||
message(n.info, warnGcUnsafe, renderTree(n))
|
||||
|
||||
template markGcUnsafe(a: PEffects) =
|
||||
a.gcUnsafe = true
|
||||
|
||||
proc useVar(a: PEffects, n: PNode) =
|
||||
let s = n.sym
|
||||
if isLocalVar(a, s):
|
||||
@@ -209,7 +212,7 @@ proc useVar(a: PEffects, n: PNode) =
|
||||
if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
|
||||
tfGcSafe notin s.typ.flags:
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
a.gcUnsafe = true
|
||||
markGcUnsafe(a)
|
||||
|
||||
type
|
||||
TIntersection = seq[tuple[id, count: int]] # a simple count table
|
||||
@@ -230,7 +233,7 @@ proc getEbase(): PType =
|
||||
|
||||
proc excType(n: PNode): PType =
|
||||
# reraise is like raising E_Base:
|
||||
let t = if n.kind == nkEmpty: getEbase() else: n.typ
|
||||
let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ
|
||||
result = skipTypes(t, skipPtrs)
|
||||
|
||||
proc createRaise(n: PNode): PNode =
|
||||
@@ -448,7 +451,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||
|
||||
if notGcSafe(s.typ) and sfImportc notin s.flags:
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
tracked.gcUnsafe = true
|
||||
markGcUnsafe(tracked)
|
||||
mergeLockLevels(tracked, n, s.getLockLevel)
|
||||
|
||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
@@ -502,13 +505,13 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
||||
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
tracked.gcUnsafe = true
|
||||
markGcUnsafe(tracked)
|
||||
else:
|
||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||
if notGcSafe(op):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
tracked.gcUnsafe = true
|
||||
markGcUnsafe(tracked)
|
||||
notNilCheck(tracked, n, paramType)
|
||||
|
||||
proc breaksBlock(n: PNode): bool =
|
||||
@@ -656,7 +659,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
# and it's not a recursive call:
|
||||
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||
warnAboutGcUnsafe(n)
|
||||
tracked.gcUnsafe = true
|
||||
markGcUnsafe(tracked)
|
||||
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}:
|
||||
# may not look like an assignment, but it is:
|
||||
@@ -825,7 +828,7 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
# effects already computed?
|
||||
if sfForward in s.flags: return
|
||||
if effects.len == effectListLen: return
|
||||
|
||||
|
||||
var t: TEffects
|
||||
initEffects(effects, s, t)
|
||||
track(t, body)
|
||||
@@ -849,19 +852,20 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
# after the check, use the formal spec:
|
||||
effects.sons[tagEffects] = tagsSpec
|
||||
|
||||
if optThreadAnalysis in gGlobalOptions:
|
||||
if sfThread in s.flags and t.gcUnsafe:
|
||||
if optThreads in gGlobalOptions:
|
||||
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
else:
|
||||
localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe
|
||||
if s.typ.lockLevel == UnspecifiedLockLevel:
|
||||
s.typ.lockLevel = t.maxLockLevel
|
||||
elif t.maxLockLevel > s.typ.lockLevel:
|
||||
localError(s.info,
|
||||
"declared lock level is $1, but real lock level is $2" %
|
||||
[$s.typ.lockLevel, $t.maxLockLevel])
|
||||
if sfThread in s.flags and t.gcUnsafe:
|
||||
if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
|
||||
localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
else:
|
||||
localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
if not t.gcUnsafe:
|
||||
s.typ.flags.incl tfGcSafe
|
||||
if s.typ.lockLevel == UnspecifiedLockLevel:
|
||||
s.typ.lockLevel = t.maxLockLevel
|
||||
elif t.maxLockLevel > s.typ.lockLevel:
|
||||
#localError(s.info,
|
||||
message(s.info, warnLockLevel,
|
||||
"declared lock level is $1, but real lock level is $2" %
|
||||
[$s.typ.lockLevel, $t.maxLockLevel])
|
||||
|
||||
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
|
||||
|
||||
@@ -359,13 +359,17 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
|
||||
var def: PNode
|
||||
if a.sons[length-1].kind != nkEmpty:
|
||||
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
|
||||
if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro:
|
||||
# prevent the all too common 'var x = int' bug:
|
||||
localError(def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?")
|
||||
def.typ = errorType(c)
|
||||
if typ != nil:
|
||||
if typ.isMetaType:
|
||||
def = inferWithMetatype(c, typ, def)
|
||||
typ = def.typ
|
||||
else:
|
||||
# BUGFIX: ``fitNode`` is needed here!
|
||||
# check type compability between def.typ and typ
|
||||
# check type compatibility between def.typ and typ
|
||||
def = fitNode(c, typ, def)
|
||||
#changeType(def.skipConv, typ, check=true)
|
||||
else:
|
||||
@@ -666,8 +670,8 @@ proc checkForMetaFields(n: PNode) =
|
||||
let t = n.sym.typ
|
||||
case t.kind
|
||||
of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
|
||||
tyProc, tyGenericInvokation, tyGenericInst:
|
||||
let start = ord(t.kind in {tyGenericInvokation, tyGenericInst})
|
||||
tyProc, tyGenericInvocation, tyGenericInst:
|
||||
let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
|
||||
for i in start .. <t.sons.len:
|
||||
checkMeta(t.sons[i])
|
||||
else:
|
||||
@@ -756,7 +760,8 @@ proc lookupMacro(c: PContext, n: PNode): PSym =
|
||||
else:
|
||||
result = searchInScopes(c, considerQuotedIdent(n), {skMacro, skTemplate})
|
||||
|
||||
proc semProcAnnotation(c: PContext, prc: PNode): PNode =
|
||||
proc semProcAnnotation(c: PContext, prc: PNode;
|
||||
validPragmas: TSpecialWords): PNode =
|
||||
var n = prc.sons[pragmasPos]
|
||||
if n == nil or n.kind == nkEmpty: return
|
||||
for i in countup(0, <n.len):
|
||||
@@ -781,12 +786,18 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode =
|
||||
x.add(it.sons[1])
|
||||
x.add(prc)
|
||||
# recursion assures that this works for multiple macro annotations too:
|
||||
return semStmt(c, x)
|
||||
result = semStmt(c, x)
|
||||
# since a proc annotation can set pragmas, we process these here again.
|
||||
# This is required for SqueakNim-like export pragmas.
|
||||
if result.kind in procDefs and result[namePos].kind == nkSym and
|
||||
result[pragmasPos].kind != nkEmpty:
|
||||
pragma(c, result[namePos].sym, result[pragmasPos], validPragmas)
|
||||
return
|
||||
|
||||
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# XXX semProcAux should be good enough for this now, we will eventually
|
||||
# remove semLambda
|
||||
result = semProcAnnotation(c, n)
|
||||
result = semProcAnnotation(c, n, lambdaPragmas)
|
||||
if result != nil: return result
|
||||
result = n
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
@@ -816,8 +827,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# we have a list of implicit type parameters:
|
||||
n.sons[genericParamsPos] = gp
|
||||
else:
|
||||
s.typ = newTypeS(tyProc, c)
|
||||
rawAddSon(s.typ, nil)
|
||||
s.typ = newProcType(c, n.info)
|
||||
if n.sons[pragmasPos].kind != nkEmpty:
|
||||
pragma(c, s, n.sons[pragmasPos], lambdaPragmas)
|
||||
s.options = gOptions
|
||||
@@ -829,9 +839,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags):
|
||||
pushProcCon(c, s)
|
||||
addResult(c, s.typ.sons[0], n.info, skProc)
|
||||
addResultNode(c, n)
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
n.sons[bodyPos] = transformBody(c.module, semBody, s)
|
||||
addResultNode(c, n)
|
||||
popProcCon(c)
|
||||
elif efOperand notin flags:
|
||||
localError(n.info, errGenericLambdaNotAllowed)
|
||||
@@ -842,6 +852,13 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
popOwner()
|
||||
result.typ = s.typ
|
||||
|
||||
proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
||||
# 'do' without params produces a stmt:
|
||||
if n[genericParamsPos].kind == nkEmpty and n[paramsPos].kind == nkEmpty:
|
||||
result = semStmt(c, n[bodyPos])
|
||||
else:
|
||||
result = semLambda(c, n, flags)
|
||||
|
||||
proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||
var n = n
|
||||
|
||||
@@ -857,9 +874,9 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
|
||||
addParams(c, n.typ.n, skProc)
|
||||
pushProcCon(c, s)
|
||||
addResult(c, n.typ.sons[0], n.info, skProc)
|
||||
addResultNode(c, n)
|
||||
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
|
||||
n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym)
|
||||
addResultNode(c, n)
|
||||
popProcCon(c)
|
||||
popOwner()
|
||||
closeScope(c)
|
||||
@@ -905,7 +922,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) =
|
||||
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]
|
||||
elif t.kind == tyGenericInvocation: t = t.sons[0]
|
||||
else: break
|
||||
if t.kind in {tyObject, tyDistinct, tyEnum}:
|
||||
if t.deepCopy.isNil: t.deepCopy = s
|
||||
@@ -936,7 +953,7 @@ proc isForwardDecl(s: PSym): bool =
|
||||
proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
validPragmas: TSpecialWords,
|
||||
phase = stepRegisterSymbol): PNode =
|
||||
result = semProcAnnotation(c, n)
|
||||
result = semProcAnnotation(c, n, validPragmas)
|
||||
if result != nil: return result
|
||||
result = n
|
||||
checkSonsLen(n, bodyPos + 1)
|
||||
@@ -991,8 +1008,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
|
||||
# check for semantics again:
|
||||
# semParamList(c, n.sons[ParamsPos], nil, s)
|
||||
else:
|
||||
s.typ = newTypeS(tyProc, c)
|
||||
rawAddSon(s.typ, nil)
|
||||
s.typ = newProcType(c, n.info)
|
||||
if n.sons[patternPos].kind != nkEmpty:
|
||||
n.sons[patternPos] = semPattern(c, n.sons[patternPos])
|
||||
if s.kind in skIterators:
|
||||
|
||||
@@ -436,7 +436,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
|
||||
of nkEmpty, nkSym..nkNilLit:
|
||||
discard
|
||||
else:
|
||||
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
|
||||
# dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
|
||||
# so we use the generic code for nkDotExpr too
|
||||
if n.kind == nkDotExpr or n.kind == nkAccQuoted:
|
||||
let s = qualifiedLookUp(c.c, n, {})
|
||||
@@ -494,7 +494,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
|
||||
semParamList(c, n.sons[paramsPos], gp, s)
|
||||
# a template's parameters are not gensym'ed even if that was originally the
|
||||
# case as we determine whether it's a template parameter in the template
|
||||
# body by the absense of the skGenSym flag:
|
||||
# body by the absence of the sfGenSym flag:
|
||||
for i in 1 .. s.typ.n.len-1:
|
||||
s.typ.n.sons[i].sym.flags.excl sfGenSym
|
||||
if sonsLen(gp) > 0:
|
||||
@@ -640,7 +640,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result.sons[i] = semPatternBody(c, n.sons[i])
|
||||
else:
|
||||
# dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam',
|
||||
# dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam',
|
||||
# so we use the generic code for nkDotExpr too
|
||||
case n.kind
|
||||
of nkDotExpr, nkAccQuoted:
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
# this module does the semantic checking of type declarations
|
||||
# included from sem.nim
|
||||
|
||||
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
|
||||
if prev == nil:
|
||||
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
|
||||
if prev == nil:
|
||||
result = newTypeS(kind, c)
|
||||
else:
|
||||
else:
|
||||
result = prev
|
||||
if result.kind == tyForward: result.kind = kind
|
||||
|
||||
proc newConstraint(c: PContext, k: TTypeKind): PType =
|
||||
proc newConstraint(c: PContext, k: TTypeKind): PType =
|
||||
result = newTypeS(tyBuiltInTypeClass, c)
|
||||
result.addSonSkipIntLit(newTypeS(k, c))
|
||||
|
||||
@@ -32,22 +32,22 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = newOrPrevType(tyEnum, prev, c)
|
||||
result.n = newNodeI(nkEnumTy, n.info)
|
||||
checkMinSonsLen(n, 1)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
base = semTypeNode(c, n.sons[0].sons[0], nil)
|
||||
if base.kind != tyEnum:
|
||||
if base.kind != tyEnum:
|
||||
localError(n.sons[0].info, errInheritanceOnlyWithEnums)
|
||||
counter = lastOrd(base) + 1
|
||||
rawAddSon(result, base)
|
||||
let isPure = result.sym != nil and sfPure in result.sym.flags
|
||||
var hasNull = false
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
case n.sons[i].kind
|
||||
of nkEnumFieldDef:
|
||||
of nkEnumFieldDef:
|
||||
e = newSymS(skEnumField, n.sons[i].sons[0], c)
|
||||
var v = semConstExpr(c, n.sons[i].sons[1])
|
||||
var strVal: PNode = nil
|
||||
case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
|
||||
of tyTuple:
|
||||
case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind
|
||||
of tyTuple:
|
||||
if sonsLen(v) == 2:
|
||||
strVal = v.sons[1] # second tuple part is the string value
|
||||
if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
|
||||
@@ -63,14 +63,14 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
x = getOrdValue(v)
|
||||
if i != 1:
|
||||
if x != counter: incl(result.flags, tfEnumHasHoles)
|
||||
if x < counter:
|
||||
if x < counter:
|
||||
localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s)
|
||||
x = counter
|
||||
e.ast = strVal # might be nil
|
||||
counter = x
|
||||
of nkSym:
|
||||
of nkSym:
|
||||
e = n.sons[i].sym
|
||||
of nkIdent, nkAccQuoted:
|
||||
of nkIdent, nkAccQuoted:
|
||||
e = newSymS(skEnumField, n.sons[i], c)
|
||||
else:
|
||||
illFormedAst(n[i])
|
||||
@@ -87,28 +87,28 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
|
||||
inc(counter)
|
||||
if not hasNull: incl(result.flags, tfNeedsInit)
|
||||
|
||||
proc semSet(c: PContext, n: PNode, prev: PType): PType =
|
||||
proc semSet(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = newOrPrevType(tySet, prev, c)
|
||||
if sonsLen(n) == 2:
|
||||
if sonsLen(n) == 2:
|
||||
var base = semTypeNode(c, n.sons[1], nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
if base.kind == tyGenericInst: base = lastSon(base)
|
||||
if base.kind != tyGenericParam:
|
||||
if not isOrdinalType(base):
|
||||
if not isOrdinalType(base):
|
||||
localError(n.info, errOrdinalTypeExpected)
|
||||
elif lengthOrd(base) > MaxSetElements:
|
||||
elif lengthOrd(base) > MaxSetElements:
|
||||
localError(n.info, errSetTooBig)
|
||||
else:
|
||||
localError(n.info, errXExpectsOneTypeParam, "set")
|
||||
addSonSkipIntLit(result, errorType(c))
|
||||
|
||||
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
|
||||
prev: PType): PType =
|
||||
|
||||
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
|
||||
prev: PType): PType =
|
||||
result = newOrPrevType(kind, prev, c)
|
||||
if sonsLen(n) == 2:
|
||||
if sonsLen(n) == 2:
|
||||
var base = semTypeNode(c, n.sons[1], nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
else:
|
||||
localError(n.info, errXExpectsOneTypeParam, kindStr)
|
||||
addSonSkipIntLit(result, errorType(c))
|
||||
|
||||
@@ -140,23 +140,23 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
|
||||
var base = semTypeNode(c, n.lastSon, nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
|
||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||
if sonsLen(n) == 1:
|
||||
proc semVarType(c: PContext, n: PNode, prev: PType): PType =
|
||||
if sonsLen(n) == 1:
|
||||
result = newOrPrevType(tyVar, prev, c)
|
||||
var base = semTypeNode(c, n.sons[0], nil)
|
||||
if base.kind == tyVar:
|
||||
if base.kind == tyVar:
|
||||
localError(n.info, errVarVarTypeNotAllowed)
|
||||
base = base.sons[0]
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
result = newConstraint(c, tyVar)
|
||||
|
||||
proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
|
||||
proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
|
||||
if n.len == 0: return newConstraint(c, tyDistinct)
|
||||
result = newOrPrevType(tyDistinct, prev, c)
|
||||
addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil))
|
||||
if n.len > 1: result.n = n[1]
|
||||
|
||||
|
||||
proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||
assert isRange(n)
|
||||
checkSonsLen(n, 3)
|
||||
@@ -164,11 +164,11 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||
result.n = newNodeI(nkRange, n.info)
|
||||
if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
|
||||
localError(n.info, errRangeIsEmpty)
|
||||
|
||||
|
||||
var range: array[2, PNode]
|
||||
range[0] = semExprWithType(c, n[1], {efDetermineType})
|
||||
range[1] = semExprWithType(c, n[2], {efDetermineType})
|
||||
|
||||
|
||||
var rangeT: array[2, PType]
|
||||
for i in 0..1:
|
||||
rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit
|
||||
@@ -179,13 +179,13 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
||||
localError(n.info, errOrdinalTypeExpected)
|
||||
elif enumHasHoles(rangeT[0]):
|
||||
localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
|
||||
|
||||
|
||||
for i in 0..1:
|
||||
if hasGenericArguments(range[i]):
|
||||
result.n.addSon makeStaticExpr(c, range[i])
|
||||
else:
|
||||
result.n.addSon semConstExpr(c, range[i])
|
||||
|
||||
|
||||
if weakLeValue(result.n[0], result.n[1]) == impNo:
|
||||
localError(n.info, errRangeIsEmpty)
|
||||
|
||||
@@ -201,10 +201,10 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
|
||||
incl(result.flags, tfNeedsInit)
|
||||
elif n.sons[1].kind in {nkCharLit..nkUInt64Lit} and n.sons[1].intVal < 0:
|
||||
incl(result.flags, tfNeedsInit)
|
||||
elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and
|
||||
elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and
|
||||
n.sons[0].floatVal > 0.0:
|
||||
incl(result.flags, tfNeedsInit)
|
||||
elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and
|
||||
elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and
|
||||
n.sons[1].floatVal < 0.0:
|
||||
incl(result.flags, tfNeedsInit)
|
||||
else:
|
||||
@@ -243,13 +243,13 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
|
||||
else:
|
||||
let x = semConstExpr(c, e)
|
||||
if x.kind in {nkIntLit..nkUInt64Lit}:
|
||||
result = makeRangeType(c, 0, x.intVal-1, n.info,
|
||||
result = makeRangeType(c, 0, x.intVal-1, n.info,
|
||||
x.typ.skipTypes({tyTypeDesc}))
|
||||
else:
|
||||
result = x.typ.skipTypes({tyTypeDesc})
|
||||
#localError(n[1].info, errConstExprExpected)
|
||||
|
||||
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||
proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||
var base: PType
|
||||
result = newOrPrevType(tyArray, prev, c)
|
||||
if sonsLen(n) == 3:
|
||||
@@ -260,20 +260,20 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
|
||||
if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}:
|
||||
if not isOrdinalType(indx):
|
||||
localError(n.sons[1].info, errOrdinalTypeExpected)
|
||||
elif enumHasHoles(indx):
|
||||
elif enumHasHoles(indx):
|
||||
localError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
|
||||
base = semTypeNode(c, n.sons[2], nil)
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
else:
|
||||
localError(n.info, errArrayExpectsTwoTypeParams)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
|
||||
proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
||||
|
||||
proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = newOrPrevType(tyOrdinal, prev, c)
|
||||
if sonsLen(n) == 2:
|
||||
if sonsLen(n) == 2:
|
||||
var base = semTypeNode(c, n.sons[1], nil)
|
||||
if base.kind != tyGenericParam:
|
||||
if not isOrdinalType(base):
|
||||
if base.kind != tyGenericParam:
|
||||
if not isOrdinalType(base):
|
||||
localError(n.sons[1].info, errOrdinalTypeExpected)
|
||||
addSonSkipIntLit(result, base)
|
||||
else:
|
||||
@@ -281,7 +281,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
|
||||
proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
if n.kind == nkSym:
|
||||
if n.kind == nkSym:
|
||||
result = n.sym
|
||||
else:
|
||||
when defined(nimfix):
|
||||
@@ -307,7 +307,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
result = result.typ.sym.copySym
|
||||
result.typ = copyType(result.typ, result.typ.owner, true)
|
||||
result.typ.flags.incl tfUnresolved
|
||||
|
||||
|
||||
if result.kind == skGenericParam:
|
||||
if result.typ.kind == tyGenericParam and result.typ.len == 0 and
|
||||
tfWildcard in result.typ.flags:
|
||||
@@ -319,7 +319,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
localError(n.info, errTypeExpected)
|
||||
return errorSym(c, n)
|
||||
|
||||
if result.kind != skType:
|
||||
if result.kind != skType:
|
||||
# this implements the wanted ``var v: V, x: V`` feature ...
|
||||
var ov: TOverloadIter
|
||||
var amb = initOverloadIter(ov, c, n)
|
||||
@@ -332,55 +332,60 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
|
||||
if result.typ.kind != tyGenericParam:
|
||||
# XXX get rid of this hack!
|
||||
var oldInfo = n.info
|
||||
when defined(useNodeIds):
|
||||
let oldId = n.id
|
||||
reset(n[])
|
||||
when defined(useNodeIds):
|
||||
n.id = oldId
|
||||
n.kind = nkSym
|
||||
n.sym = result
|
||||
n.info = oldInfo
|
||||
n.typ = result.typ
|
||||
else:
|
||||
localError(n.info, errIdentifierExpected)
|
||||
result = errorSym(c, n)
|
||||
|
||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
|
||||
proc semTuple(c: PContext, n: PNode, prev: PType): PType =
|
||||
if n.sonsLen == 0: return newConstraint(c, tyTuple)
|
||||
var typ: PType
|
||||
result = newOrPrevType(tyTuple, prev, c)
|
||||
result.n = newNodeI(nkRecList, n.info)
|
||||
var check = initIntSet()
|
||||
var counter = 0
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = n.sons[i]
|
||||
if (a.kind != nkIdentDefs): illFormedAst(a)
|
||||
checkMinSonsLen(a, 3)
|
||||
var length = sonsLen(a)
|
||||
if a.sons[length - 2].kind != nkEmpty:
|
||||
if a.sons[length - 2].kind != nkEmpty:
|
||||
typ = semTypeNode(c, a.sons[length - 2], nil)
|
||||
else:
|
||||
localError(a.info, errTypeExpected)
|
||||
typ = errorType(c)
|
||||
if a.sons[length - 1].kind != nkEmpty:
|
||||
if a.sons[length - 1].kind != nkEmpty:
|
||||
localError(a.sons[length - 1].info, errInitHereNotAllowed)
|
||||
for j in countup(0, length - 3):
|
||||
for j in countup(0, length - 3):
|
||||
var field = newSymG(skField, a.sons[j], c)
|
||||
field.typ = typ
|
||||
field.position = counter
|
||||
inc(counter)
|
||||
if containsOrIncl(check, field.name.id):
|
||||
if containsOrIncl(check, field.name.id):
|
||||
localError(a.sons[j].info, errAttemptToRedefine, field.name.s)
|
||||
else:
|
||||
addSon(result.n, newSymNode(field))
|
||||
addSonSkipIntLit(result, typ)
|
||||
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
|
||||
|
||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
# identifier with visibility
|
||||
if n.kind == nkPostfix:
|
||||
if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
|
||||
if n.kind == nkPostfix:
|
||||
if sonsLen(n) == 2 and n.sons[0].kind == nkIdent:
|
||||
# for gensym'ed identifiers the identifier may already have been
|
||||
# transformed to a symbol and we need to use that here:
|
||||
result = newSymG(kind, n.sons[1], c)
|
||||
var v = n.sons[0].ident
|
||||
if sfExported in allowed and v.id == ord(wStar):
|
||||
if sfExported in allowed and v.id == ord(wStar):
|
||||
incl(result.flags, sfExported)
|
||||
else:
|
||||
localError(n.sons[0].info, errInvalidVisibilityX, v.s)
|
||||
@@ -388,7 +393,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
|
||||
illFormedAst(n)
|
||||
else:
|
||||
result = newSymG(kind, n, c)
|
||||
|
||||
|
||||
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
allowed: TSymFlags): PSym =
|
||||
if n.kind == nkPragmaExpr:
|
||||
@@ -410,31 +415,31 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
|
||||
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
|
||||
let ex = t[branchIndex][currentEx].skipConv
|
||||
for i in countup(1, branchIndex):
|
||||
for j in countup(0, sonsLen(t.sons[i]) - 2):
|
||||
for j in countup(0, sonsLen(t.sons[i]) - 2):
|
||||
if i == branchIndex and j == currentEx: break
|
||||
if overlap(t.sons[i].sons[j].skipConv, ex):
|
||||
localError(ex.info, errDuplicateCaseLabel)
|
||||
|
||||
|
||||
proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode =
|
||||
checkMinSonsLen(t, 1)
|
||||
let ac = semConstExpr(c, a)
|
||||
let bc = semConstExpr(c, b)
|
||||
let at = fitNode(c, t.sons[0].typ, ac).skipConvTakeType
|
||||
let bt = fitNode(c, t.sons[0].typ, bc).skipConvTakeType
|
||||
|
||||
|
||||
result = newNodeI(nkRange, a.info)
|
||||
result.add(at)
|
||||
result.add(bt)
|
||||
if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty)
|
||||
else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
|
||||
|
||||
proc semCaseBranchRange(c: PContext, t, b: PNode,
|
||||
covered: var BiggestInt): PNode =
|
||||
proc semCaseBranchRange(c: PContext, t, b: PNode,
|
||||
covered: var BiggestInt): PNode =
|
||||
checkSonsLen(b, 3)
|
||||
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
||||
|
||||
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||
covered: var BiggestInt): PNode =
|
||||
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||
covered: var BiggestInt): PNode =
|
||||
if isRange(b):
|
||||
checkSonsLen(b, 3)
|
||||
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
|
||||
@@ -445,9 +450,10 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode,
|
||||
result = fitNode(c, t.sons[0].typ, b)
|
||||
inc(covered)
|
||||
|
||||
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||
covered: var BiggestInt) =
|
||||
for i in countup(0, sonsLen(branch) - 2):
|
||||
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||
covered: var BiggestInt) =
|
||||
|
||||
for i in countup(0, sonsLen(branch) - 2):
|
||||
var b = branch.sons[i]
|
||||
if b.kind == nkRange:
|
||||
branch.sons[i] = b
|
||||
@@ -456,8 +462,11 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||
else:
|
||||
# constant sets and arrays are allowed:
|
||||
var r = semConstExpr(c, b)
|
||||
# for ``{}`` we want to trigger the type mismatch in ``fitNode``:
|
||||
if r.kind notin {nkCurly, nkBracket} or len(r) == 0:
|
||||
if r.kind in {nkCurly, nkBracket} and len(r) == 0 and sonsLen(branch)==2:
|
||||
# discarding ``{}`` and ``[]`` branches silently
|
||||
delSon(branch, 0)
|
||||
return
|
||||
elif r.kind notin {nkCurly, nkBracket} or len(r) == 0:
|
||||
checkMinSonsLen(t, 1)
|
||||
branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r))
|
||||
inc(covered)
|
||||
@@ -471,7 +480,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
|
||||
var L = branch.len
|
||||
swap(branch.sons[L-2], branch.sons[L-1])
|
||||
checkForOverlap(c, t, i, branchIndex)
|
||||
|
||||
|
||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
father: PNode, rectype: PType)
|
||||
proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
@@ -505,11 +514,11 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
else: illFormedAst(n)
|
||||
delSon(b, sonsLen(b) - 1)
|
||||
semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype)
|
||||
if chckCovered and (covered != lengthOrd(a.sons[0].typ)):
|
||||
if chckCovered and (covered != lengthOrd(a.sons[0].typ)):
|
||||
localError(a.info, errNotAllCasesCovered)
|
||||
addSon(father, a)
|
||||
|
||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
father: PNode, rectype: PType) =
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
@@ -547,12 +556,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
semRecordNodeAux(c, branch, check, pos, father, rectype)
|
||||
of nkRecCase:
|
||||
semRecordCase(c, n, check, pos, father, rectype)
|
||||
of nkNilLit:
|
||||
of nkNilLit:
|
||||
if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info))
|
||||
of nkRecList:
|
||||
# attempt to keep the nesting at a sane level:
|
||||
var a = if father.kind == nkRecList: father else: copyNode(n)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
semRecordNodeAux(c, n.sons[i], check, pos, a, rectype)
|
||||
if a != father: addSon(father, a)
|
||||
of nkIdentDefs:
|
||||
@@ -561,10 +570,10 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
var a: PNode
|
||||
if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
|
||||
else: a = ast.emptyNode
|
||||
if n.sons[length-1].kind != nkEmpty:
|
||||
if n.sons[length-1].kind != nkEmpty:
|
||||
localError(n.sons[length-1].info, errInitHereNotAllowed)
|
||||
var typ: PType
|
||||
if n.sons[length-2].kind == nkEmpty:
|
||||
if n.sons[length-2].kind == nkEmpty:
|
||||
localError(n.info, errTypeExpected)
|
||||
typ = errorType(c)
|
||||
else:
|
||||
@@ -577,7 +586,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
f.typ = typ
|
||||
f.position = pos
|
||||
if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and
|
||||
(f.loc.r == nil):
|
||||
(f.loc.r == nil):
|
||||
f.loc.r = toRope(f.name.s)
|
||||
f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags)
|
||||
inc(pos)
|
||||
@@ -589,8 +598,8 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
|
||||
if a.kind != nkEmpty: addSon(father, a)
|
||||
of nkEmpty: discard
|
||||
else: illFormedAst(n)
|
||||
|
||||
proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||
|
||||
proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||
n: PNode) =
|
||||
case n.kind
|
||||
of nkRecCase:
|
||||
@@ -609,31 +618,31 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
|
||||
inc(pos)
|
||||
else: internalError(n.info, "addInheritedFieldsAux()")
|
||||
|
||||
proc skipGenericInvokation(t: PType): PType {.inline.} =
|
||||
proc skipGenericInvocation(t: PType): PType {.inline.} =
|
||||
result = t
|
||||
if result.kind == tyGenericInvokation:
|
||||
if result.kind == tyGenericInvocation:
|
||||
result = result.sons[0]
|
||||
if result.kind == tyGenericBody:
|
||||
result = lastSon(result)
|
||||
|
||||
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||
proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
|
||||
obj: PType) =
|
||||
assert obj.kind == tyObject
|
||||
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
|
||||
addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvokation)
|
||||
if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
|
||||
addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvocation)
|
||||
addInheritedFieldsAux(c, check, pos, obj.n)
|
||||
|
||||
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
if n.sonsLen == 0: return newConstraint(c, tyObject)
|
||||
var check = initIntSet()
|
||||
var pos = 0
|
||||
var pos = 0
|
||||
var base: PType = nil
|
||||
# n.sons[0] contains the pragmas (if any). We process these later...
|
||||
checkSonsLen(n, 3)
|
||||
if n.sons[1].kind != nkEmpty:
|
||||
if n.sons[1].kind != nkEmpty:
|
||||
base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
|
||||
var concreteBase = skipGenericInvokation(base).skipTypes(skipPtrs)
|
||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||
var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
|
||||
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
|
||||
addInheritedFields(c, check, pos, concreteBase)
|
||||
else:
|
||||
if concreteBase.kind != tyError:
|
||||
@@ -672,8 +681,9 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
|
||||
elif param.typ.kind == tyTypeDesc:
|
||||
addDecl(c, param)
|
||||
else:
|
||||
# within a macro, every param has the type PNimrodNode!
|
||||
let nn = getSysSym"PNimrodNode"
|
||||
# within a macro, every param has the type NimNode!
|
||||
let nn = if getCompilerProc("NimNode") != nil: getSysSym"NimNode"
|
||||
else: getSysSym"PNimrodNode"
|
||||
var a = copySym(param)
|
||||
a.typ = nn.typ
|
||||
addDecl(c, a)
|
||||
@@ -713,7 +723,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
genericParams.addSon(newSymNode(s))
|
||||
result = typeClass
|
||||
addDecl(c, s)
|
||||
|
||||
|
||||
# XXX: There are codegen errors if this is turned into a nested proc
|
||||
template liftingWalk(typ: PType, anonFlag = false): expr =
|
||||
liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag)
|
||||
@@ -732,7 +742,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
case paramType.kind:
|
||||
of tyAnything:
|
||||
result = addImplicitGeneric(newTypeS(tyGenericParam, c))
|
||||
|
||||
|
||||
of tyStatic:
|
||||
# proc(a: expr{string}, b: expr{nkLambda})
|
||||
# overload on compile time values and AST trees
|
||||
@@ -743,7 +753,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
localError(info, errMacroBodyDependsOnGenericTypes, paramName)
|
||||
result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base]))
|
||||
result.flags.incl({tfHasStatic, tfUnresolved})
|
||||
|
||||
|
||||
of tyTypeDesc:
|
||||
if tfUnresolved notin paramType.flags:
|
||||
# naked typedescs are not bindOnce types
|
||||
@@ -751,12 +761,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
paramTypId.id == typedescId.id: paramTypId = nil
|
||||
result = addImplicitGeneric(
|
||||
c.newTypeWithSons(tyTypeDesc, @[paramType.base]))
|
||||
|
||||
|
||||
of tyDistinct:
|
||||
if paramType.sonsLen == 1:
|
||||
# disable the bindOnce behavior for the type class
|
||||
result = liftingWalk(paramType.sons[0], true)
|
||||
|
||||
|
||||
of tySequence, tySet, tyArray, tyOpenArray,
|
||||
tyVar, tyPtr, tyRef, tyProc:
|
||||
# XXX: this is a bit strange, but proc(s: seq)
|
||||
@@ -775,21 +785,22 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
if lifted != nil:
|
||||
paramType.sons[i] = lifted
|
||||
result = paramType
|
||||
|
||||
|
||||
of tyGenericBody:
|
||||
result = newTypeS(tyGenericInvokation, c)
|
||||
result = newTypeS(tyGenericInvocation, c)
|
||||
result.rawAddSon(paramType)
|
||||
|
||||
|
||||
for i in 0 .. paramType.sonsLen - 2:
|
||||
let dummyType = if paramType.sons[i].kind == tyStatic: tyUnknown
|
||||
else: tyAnything
|
||||
result.rawAddSon newTypeS(dummyType, c)
|
||||
|
||||
if paramType.sons[i].kind == tyStatic:
|
||||
result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnknown'
|
||||
else:
|
||||
result.rawAddSon newTypeS(tyAnything, c)
|
||||
|
||||
if paramType.lastSon.kind == tyUserTypeClass:
|
||||
result.kind = tyUserTypeClassInst
|
||||
result.rawAddSon paramType.lastSon
|
||||
return addImplicitGeneric(result)
|
||||
|
||||
|
||||
result = instGenericContainer(c, paramType.sym.info, result,
|
||||
allowMetaTypes = true)
|
||||
result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result])
|
||||
@@ -821,8 +832,8 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
if liftBody != nil:
|
||||
result = liftBody
|
||||
result.shouldHaveMeta
|
||||
|
||||
of tyGenericInvokation:
|
||||
|
||||
of tyGenericInvocation:
|
||||
for i in 1 .. <paramType.sonsLen:
|
||||
let lifted = liftingWalk(paramType.sons[i])
|
||||
if lifted != nil: paramType.sons[i] = lifted
|
||||
@@ -833,18 +844,18 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
|
||||
|
||||
of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot:
|
||||
result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true))
|
||||
|
||||
|
||||
of tyExpr:
|
||||
if procKind notin {skMacro, skTemplate}:
|
||||
result = addImplicitGeneric(newTypeS(tyAnything, c))
|
||||
|
||||
|
||||
of tyGenericParam:
|
||||
markUsed(info, paramType.sym)
|
||||
styleCheckUse(info, paramType.sym)
|
||||
if tfWildcard in paramType.flags:
|
||||
paramType.flags.excl tfWildcard
|
||||
paramType.sym.kind = skType
|
||||
|
||||
|
||||
else: discard
|
||||
|
||||
# result = liftingWalk(paramType)
|
||||
@@ -856,25 +867,25 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
|
||||
else:
|
||||
result = semTypeNode(c, n, nil)
|
||||
|
||||
proc newProcType(c: PContext; info: TLineInfo; prev: PType = nil): PType =
|
||||
result = newOrPrevType(tyProc, prev, c)
|
||||
result.callConv = lastOptionEntry(c).defaultCC
|
||||
result.n = newNodeI(nkFormalParams, info)
|
||||
rawAddSon(result, nil) # return type
|
||||
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
|
||||
# the effects are now stored in there too ... this is a bit hacky, but as
|
||||
# usual we desperately try to save memory:
|
||||
addSon(result.n, newNodeI(nkEffectList, info))
|
||||
|
||||
proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
prev: PType, kind: TSymKind; isType=false): PType =
|
||||
# for historical reasons (code grows) this is invoked for parameter
|
||||
# lists too and then 'isType' is false.
|
||||
var
|
||||
res: PNode
|
||||
cl: IntSet
|
||||
var cl: IntSet
|
||||
checkMinSonsLen(n, 1)
|
||||
result = newOrPrevType(tyProc, prev, c)
|
||||
result.callConv = lastOptionEntry(c).defaultCC
|
||||
result.n = newNodeI(nkFormalParams, n.info)
|
||||
result = newProcType(c, n.info, prev)
|
||||
if genericParams != nil and sonsLen(genericParams) == 0:
|
||||
cl = initIntSet()
|
||||
rawAddSon(result, nil) # return type
|
||||
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
|
||||
# the effects are now stored in there too ... this is a bit hacky, but as
|
||||
# usual we desperately try to save memory:
|
||||
res = newNodeI(nkEffectList, n.info)
|
||||
addSon(result.n, res)
|
||||
var check = initIntSet()
|
||||
var counter = 0
|
||||
for i in countup(1, n.len - 1):
|
||||
@@ -898,8 +909,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
typ = semParamType(c, a.sons[length-2], constraint)
|
||||
|
||||
if hasDefault:
|
||||
def = semExprWithType(c, a.sons[length-1])
|
||||
# check type compability between def.typ and typ:
|
||||
def = semExprWithType(c, a.sons[length-1])
|
||||
# check type compatibility between def.typ and typ:
|
||||
if typ == nil:
|
||||
typ = def.typ
|
||||
elif def != nil:
|
||||
@@ -911,10 +922,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
if not hasType and not hasDefault:
|
||||
if isType: localError(a.info, "':' expected")
|
||||
let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
|
||||
if tdef == tyAnything:
|
||||
message(a.info, warnTypelessParam, renderTree(n))
|
||||
typ = newTypeS(tdef, c)
|
||||
|
||||
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
|
||||
for j in countup(0, length-3):
|
||||
for j in countup(0, length-3):
|
||||
var arg = newSymG(skParam, a.sons[j], c)
|
||||
let lifted = liftParamType(c, kind, genericParams, typ,
|
||||
arg.name.s, arg.info)
|
||||
@@ -924,7 +937,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
arg.constraint = constraint
|
||||
inc(counter)
|
||||
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
|
||||
if containsOrIncl(check, arg.name.id):
|
||||
if containsOrIncl(check, arg.name.id):
|
||||
localError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
|
||||
addSon(result.n, newSymNode(arg))
|
||||
rawAddSon(result, finalType)
|
||||
@@ -937,9 +950,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
elif kind == skIterator:
|
||||
# XXX This is special magic we should likely get rid of
|
||||
r = newTypeS(tyExpr, c)
|
||||
|
||||
|
||||
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':
|
||||
if skipTypes(r, {tyGenericInst}).kind != tyEmpty:
|
||||
# 'auto' as a return type does not imply a generic:
|
||||
@@ -956,7 +969,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
|
||||
# we don't need to change the return type to iter[T]
|
||||
if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
|
||||
result.sons[0] = r
|
||||
res.typ = r
|
||||
result.n.typ = r
|
||||
|
||||
if genericParams != nil:
|
||||
for n in genericParams:
|
||||
@@ -975,8 +988,8 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
|
||||
n.sons[length - 1].typ = result
|
||||
else:
|
||||
result = nil
|
||||
|
||||
proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||
|
||||
proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||
inc(c.p.nestedBlockCounter)
|
||||
checkSonsLen(n, 2)
|
||||
openScope(c)
|
||||
@@ -988,7 +1001,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
|
||||
closeScope(c)
|
||||
dec(c.p.nestedBlockCounter)
|
||||
|
||||
proc semGenericParamInInvokation(c: PContext, n: PNode): PType =
|
||||
proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
|
||||
result = semTypeNode(c, n, nil)
|
||||
|
||||
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
@@ -996,12 +1009,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
localError(n.info, "cannot instantiate the '$1' $2" %
|
||||
[s.name.s, ($s.kind).substr(2).toLower])
|
||||
return newOrPrevType(tyError, prev, c)
|
||||
|
||||
|
||||
var t = s.typ
|
||||
if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
|
||||
t = t.base
|
||||
|
||||
result = newOrPrevType(tyGenericInvokation, prev, c)
|
||||
result = newOrPrevType(tyGenericInvocation, prev, c)
|
||||
addSonSkipIntLit(result, t)
|
||||
|
||||
template addToResult(typ) =
|
||||
@@ -1012,7 +1025,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
|
||||
if t.kind == tyForward:
|
||||
for i in countup(1, sonsLen(n)-1):
|
||||
var elem = semGenericParamInInvokation(c, n.sons[i])
|
||||
var elem = semGenericParamInInvocation(c, n.sons[i])
|
||||
addToResult(elem)
|
||||
return
|
||||
elif t.kind != tyGenericBody:
|
||||
@@ -1023,7 +1036,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
else:
|
||||
var m = newCandidate(c, t)
|
||||
matches(c, n, copyTree(n), m)
|
||||
|
||||
|
||||
if m.state != csMatch:
|
||||
var err = "cannot instantiate " & typeToString(t) & "\n" &
|
||||
"got: (" & describeArgs(c, n) & ")\n" &
|
||||
@@ -1032,12 +1045,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
|
||||
return newOrPrevType(tyError, prev, c)
|
||||
|
||||
var isConcrete = true
|
||||
|
||||
|
||||
for i in 1 .. <m.call.len:
|
||||
let typ = m.call[i].typ.skipTypes({tyTypeDesc})
|
||||
if containsGenericType(typ): isConcrete = false
|
||||
addToResult(typ)
|
||||
|
||||
|
||||
if isConcrete:
|
||||
if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
|
||||
# XXX: What kind of error is this? is it still relevant?
|
||||
@@ -1068,7 +1081,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
|
||||
let
|
||||
pragmas = n[1]
|
||||
inherited = n[2]
|
||||
|
||||
|
||||
if inherited.kind != nkEmpty:
|
||||
for n in inherited.sons:
|
||||
let typ = semTypeNode(c, n, nil)
|
||||
@@ -1101,7 +1114,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
checkSonsLen(n, 1)
|
||||
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
|
||||
result = typExpr.typ.skipTypes({tyIter})
|
||||
of nkPar:
|
||||
of nkPar:
|
||||
if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
|
||||
else:
|
||||
# XXX support anon tuple here
|
||||
@@ -1132,7 +1145,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
case n.len
|
||||
of 3:
|
||||
result = semTypeNode(c, n.sons[1], prev)
|
||||
if result.kind in NilableTypes and n.sons[2].kind == nkNilLit:
|
||||
if result.skipTypes({tyGenericInst}).kind in NilableTypes+GenericTypes and
|
||||
n.sons[2].kind == nkNilLit:
|
||||
result = freshType(result, prev)
|
||||
result.flags.incl(tfNotNil)
|
||||
else:
|
||||
@@ -1175,14 +1189,15 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
var typeExpr = semExpr(c, n)
|
||||
if typeExpr.typ.kind != tyTypeDesc:
|
||||
localError(n.info, errTypeExpected)
|
||||
return errorType(c)
|
||||
result = typeExpr.typ.base
|
||||
if result.isMetaType:
|
||||
var preprocessed = semGenericStmt(c, n)
|
||||
return makeTypeFromExpr(c, preprocessed)
|
||||
result = errorType(c)
|
||||
else:
|
||||
result = typeExpr.typ.base
|
||||
if result.isMetaType:
|
||||
var preprocessed = semGenericStmt(c, n)
|
||||
result = makeTypeFromExpr(c, preprocessed.copyTree)
|
||||
of nkIdent, nkAccQuoted:
|
||||
var s = semTypeIdent(c, n)
|
||||
if s.typ == nil:
|
||||
if s.typ == nil:
|
||||
if s.kind != skError: localError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
elif s.kind == skParam and s.typ.kind == tyTypeDesc:
|
||||
@@ -1190,19 +1205,19 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
result = s.typ.base
|
||||
elif prev == nil:
|
||||
result = s.typ
|
||||
else:
|
||||
else:
|
||||
assignType(prev, s.typ)
|
||||
# bugfix: keep the fresh id for aliases to integral types:
|
||||
if s.typ.kind notin {tyBool, tyChar, tyInt..tyInt64, tyFloat..tyFloat128,
|
||||
tyUInt..tyUInt64}:
|
||||
tyUInt..tyUInt64}:
|
||||
prev.id = s.typ.id
|
||||
result = prev
|
||||
of nkSym:
|
||||
if n.sym.kind == skType and n.sym.typ != nil:
|
||||
var t = n.sym.typ
|
||||
if prev == nil:
|
||||
if prev == nil:
|
||||
result = t
|
||||
else:
|
||||
else:
|
||||
assignType(prev, t)
|
||||
result = prev
|
||||
markUsed(n.info, n.sym)
|
||||
@@ -1250,13 +1265,14 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||
else:
|
||||
localError(n.info, errTypeExpected)
|
||||
result = newOrPrevType(tyError, prev, c)
|
||||
|
||||
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
||||
n.typ = result
|
||||
|
||||
proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
|
||||
m.typ.kind = kind
|
||||
m.typ.align = size.int16
|
||||
m.typ.size = size
|
||||
|
||||
proc processMagicType(c: PContext, m: PSym) =
|
||||
|
||||
proc processMagicType(c: PContext, m: PSym) =
|
||||
case m.magic
|
||||
of mInt: setMagicType(m, tyInt, intSize)
|
||||
of mInt8: setMagicType(m, tyInt8, 1)
|
||||
@@ -1274,21 +1290,21 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||
of mFloat128: setMagicType(m, tyFloat128, 16)
|
||||
of mBool: setMagicType(m, tyBool, 1)
|
||||
of mChar: setMagicType(m, tyChar, 1)
|
||||
of mString:
|
||||
of mString:
|
||||
setMagicType(m, tyString, ptrSize)
|
||||
rawAddSon(m.typ, getSysType(tyChar))
|
||||
of mCstring:
|
||||
of mCstring:
|
||||
setMagicType(m, tyCString, ptrSize)
|
||||
rawAddSon(m.typ, getSysType(tyChar))
|
||||
of mPointer: setMagicType(m, tyPointer, ptrSize)
|
||||
of mEmptySet:
|
||||
of mEmptySet:
|
||||
setMagicType(m, tySet, 1)
|
||||
rawAddSon(m.typ, newTypeS(tyEmpty, c))
|
||||
of mIntSetBaseType: setMagicType(m, tyRange, intSize)
|
||||
of mNil: setMagicType(m, tyNil, ptrSize)
|
||||
of mExpr: setMagicType(m, tyExpr, 0)
|
||||
of mStmt: setMagicType(m, tyStmt, 0)
|
||||
of mTypeDesc:
|
||||
of mTypeDesc:
|
||||
setMagicType(m, tyTypeDesc, 0)
|
||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||
of mVoidType: setMagicType(m, tyEmpty, 0)
|
||||
@@ -1302,8 +1318,8 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||
setMagicType(m, tyRange, 0)
|
||||
rawAddSon(m.typ, newTypeS(tyNone, c))
|
||||
of mSet:
|
||||
setMagicType(m, tySet, 0)
|
||||
of mSeq:
|
||||
setMagicType(m, tySet, 0)
|
||||
of mSeq:
|
||||
setMagicType(m, tySequence, 0)
|
||||
of mOrdinal:
|
||||
setMagicType(m, tyOrdinal, 0)
|
||||
@@ -1319,13 +1335,13 @@ proc processMagicType(c: PContext, m: PSym) =
|
||||
incl m.typ.flags, tfShared
|
||||
rawAddSon(m.typ, sysTypeFromName"shared")
|
||||
else: localError(m.info, errTypeExpected)
|
||||
|
||||
|
||||
proc semGenericConstraints(c: PContext, x: PType): PType =
|
||||
result = newTypeWithSons(c, tyGenericParam, @[x])
|
||||
|
||||
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||
result = copyNode(n)
|
||||
if n.kind != nkGenericParams:
|
||||
if n.kind != nkGenericParams:
|
||||
illFormedAst(n)
|
||||
return
|
||||
for i in countup(0, sonsLen(n)-1):
|
||||
@@ -1335,7 +1351,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||
var def = a{-1}
|
||||
let constraint = a{-2}
|
||||
var typ: PType
|
||||
|
||||
|
||||
if constraint.kind != nkEmpty:
|
||||
typ = semTypeNode(c, constraint, nil)
|
||||
if typ.kind != tyStatic or typ.len == 0:
|
||||
@@ -1344,7 +1360,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||
typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)])
|
||||
else:
|
||||
typ = semGenericConstraints(c, typ)
|
||||
|
||||
|
||||
if def.kind != nkEmpty:
|
||||
def = semConstExpr(c, def)
|
||||
if typ == nil:
|
||||
@@ -1356,7 +1372,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
|
||||
def.typ = def.typ.skipTypes({tyTypeDesc})
|
||||
if not containsGenericType(def.typ):
|
||||
def = fitNode(c, typ, def)
|
||||
|
||||
|
||||
if typ == nil:
|
||||
typ = newTypeS(tyGenericParam, c)
|
||||
if father == nil: typ.flags.incl tfWildcard
|
||||
|
||||
@@ -61,7 +61,7 @@ proc searchInstTypes*(key: PType): PType =
|
||||
if inst.sons.len < key.sons.len:
|
||||
# XXX: This happens for prematurely cached
|
||||
# types such as TChannel[empty]. Why?
|
||||
# See the notes for PActor in handleGenericInvokation
|
||||
# See the notes for PActor in handleGenericInvocation
|
||||
return
|
||||
block matchType:
|
||||
for j in 1 .. high(key.sons):
|
||||
@@ -223,7 +223,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
|
||||
result = errorType(cl.c)
|
||||
# In order to prevent endless recursions, we must remember
|
||||
# this bad lookup and replace it with errorType everywhere.
|
||||
# These code paths are only active in nimrod check
|
||||
# These code paths are only active in "nim check"
|
||||
idTablePut(cl.typeMap, t, result)
|
||||
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
|
||||
internalError(cl.info, "substitution with generic parameter")
|
||||
@@ -234,9 +234,9 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
|
||||
result.flags.incl tfFromGeneric
|
||||
result.flags.excl tfInstClearedFlags
|
||||
|
||||
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||
# tyGenericInvokation[A, tyGenericInvokation[A, B]]
|
||||
# is difficult to handle:
|
||||
proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
|
||||
# tyGenericInvocation[A, tyGenericInvocation[A, B]]
|
||||
# is difficult to handle:
|
||||
var body = t.sons[0]
|
||||
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
|
||||
var header: PType = t
|
||||
@@ -245,7 +245,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||
result = PType(idTableGet(cl.localCache, t))
|
||||
else:
|
||||
result = searchInstTypes(t)
|
||||
if result != nil: return
|
||||
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
var x = t.sons[i]
|
||||
if x.kind == tyGenericParam:
|
||||
@@ -260,10 +260,10 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||
if header != t:
|
||||
# search again after first pass:
|
||||
result = searchInstTypes(header)
|
||||
if result != nil: return
|
||||
if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
|
||||
else:
|
||||
header = instCopyType(cl, t)
|
||||
|
||||
|
||||
result = newType(tyGenericInst, t.sons[0].owner)
|
||||
result.flags = header.flags
|
||||
# be careful not to propagate unnecessary flags here (don't use rawAddSon)
|
||||
@@ -278,7 +278,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||
|
||||
for i in countup(1, sonsLen(t) - 1):
|
||||
var x = replaceTypeVarsT(cl, t.sons[i])
|
||||
assert x.kind != tyGenericInvokation
|
||||
assert x.kind != tyGenericInvocation
|
||||
header.sons[i] = x
|
||||
propagateToOwner(header, x)
|
||||
idTablePut(cl.typeMap, body.sons[i-1], x)
|
||||
@@ -295,7 +295,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
|
||||
#newbody.callConv = body.callConv
|
||||
# This type may be a generic alias and we want to resolve it here.
|
||||
# One step is enough, because the recursive nature of
|
||||
# handleGenericInvokation will handle the alias-to-alias-to-alias case
|
||||
# handleGenericInvocation will handle the alias-to-alias-to-alias case
|
||||
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
|
||||
rawAddSon(result, newbody)
|
||||
checkPartialConstructedType(cl.info, newbody)
|
||||
@@ -359,8 +359,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
if lookup != nil: return lookup
|
||||
|
||||
case t.kind
|
||||
of tyGenericInvokation:
|
||||
result = handleGenericInvokation(cl, t)
|
||||
of tyGenericInvocation:
|
||||
result = handleGenericInvocation(cl, t)
|
||||
|
||||
of tyGenericBody:
|
||||
localError(cl.info, errCannotInstantiateX, typeToString(t))
|
||||
@@ -369,6 +369,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
|
||||
of tyFromExpr:
|
||||
if cl.allowMetaTypes: return
|
||||
assert t.n.typ != t
|
||||
var n = prepareNode(cl, t.n)
|
||||
n = cl.c.semConstExpr(cl.c, n)
|
||||
if n.typ.kind == tyTypeDesc:
|
||||
@@ -389,9 +390,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
|
||||
else:
|
||||
result = n.typ
|
||||
|
||||
of tyInt:
|
||||
of tyInt, tyFloat:
|
||||
result = skipIntLit(t)
|
||||
# XXX now there are also float literals
|
||||
|
||||
of tyTypeDesc:
|
||||
let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t)
|
||||
|
||||
@@ -33,7 +33,12 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||
parseopt.next(p)
|
||||
case p.kind
|
||||
of cmdEnd: break
|
||||
of cmdLongoption, cmdShortOption: processSwitch(pass, p)
|
||||
of cmdLongoption, cmdShortOption:
|
||||
if p.key == " ":
|
||||
p.key = "-"
|
||||
if processArgument(pass, p, argsCount): break
|
||||
else:
|
||||
processSwitch(pass, p)
|
||||
of cmdArgument:
|
||||
if processArgument(pass, p, argsCount): break
|
||||
if pass == passCmd2:
|
||||
|
||||
@@ -91,7 +91,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
|
||||
initIdTable(c.bindings)
|
||||
|
||||
proc put(t: var TIdTable, key, val: PType) {.inline.} =
|
||||
idTablePut(t, key, val)
|
||||
idTablePut(t, key, val.skipIntLit)
|
||||
|
||||
proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
|
||||
binding: PNode, calleeScope = -1) =
|
||||
@@ -153,12 +153,12 @@ proc sumGeneric(t: PType): int =
|
||||
of tyVar:
|
||||
# but do not make 'var T' more specific than 'T'!
|
||||
t = t.sons[0]
|
||||
of tyGenericInvokation, tyTuple:
|
||||
result = ord(t.kind == tyGenericInvokation)
|
||||
of tyGenericInvocation, tyTuple:
|
||||
result = ord(t.kind == tyGenericInvocation)
|
||||
for i in 0 .. <t.len: result += t.sons[i].sumGeneric
|
||||
break
|
||||
of tyProc:
|
||||
# proc matche proc better than 'stmt' to disambiguate 'spawn'
|
||||
# proc matches proc better than 'stmt' to disambiguate 'spawn'
|
||||
return 1
|
||||
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
|
||||
else: return 0
|
||||
@@ -262,7 +262,7 @@ proc concreteType(c: TCandidate, t: PType): PType =
|
||||
# example code that triggers it:
|
||||
# proc sort[T](cmp: proc(a, b: T): int = cmp)
|
||||
if result.kind != tyGenericParam: break
|
||||
of tyGenericInvokation:
|
||||
of tyGenericInvocation:
|
||||
internalError("cannot resolve type: " & typeToString(t))
|
||||
result = t
|
||||
else:
|
||||
@@ -418,7 +418,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
|
||||
|
||||
if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
|
||||
return isNone
|
||||
elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {}:
|
||||
elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and
|
||||
optThreadAnalysis in gGlobalOptions:
|
||||
# noSideEffect implies ``tfThread``!
|
||||
return isNone
|
||||
elif f.flags * {tfIterator} != a.flags * {tfIterator}:
|
||||
@@ -461,7 +462,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
|
||||
openScope(c)
|
||||
inc c.inTypeClass
|
||||
|
||||
finally:
|
||||
defer:
|
||||
dec c.inTypeClass
|
||||
closeScope(c)
|
||||
|
||||
@@ -570,7 +571,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
assert(f != nil)
|
||||
|
||||
if f.kind == tyExpr:
|
||||
put(c.bindings, f, aOrig)
|
||||
if aOrig != nil: put(c.bindings, f, aOrig)
|
||||
return isGeneric
|
||||
|
||||
assert(aOrig != nil)
|
||||
@@ -584,7 +585,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
|
||||
if a.kind == tyGenericInst and
|
||||
skipTypes(f, {tyVar}).kind notin {
|
||||
tyGenericBody, tyGenericInvokation,
|
||||
tyGenericBody, tyGenericInvocation,
|
||||
tyGenericInst, tyGenericParam} + tyTypeClasses:
|
||||
return typeRel(c, f, lastSon(a))
|
||||
|
||||
@@ -864,8 +865,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
result = typeRel(c, ff, aa)
|
||||
if result == isNone: return
|
||||
if ff.kind == tyRange and result != isEqual: return isNone
|
||||
|
||||
result = isGeneric
|
||||
# XXX See bug #2220. A[int] should match A[int] better than some generic X
|
||||
else:
|
||||
result = typeRel(c, lastSon(f), a)
|
||||
|
||||
@@ -876,10 +877,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
let ff = lastSon(f)
|
||||
if ff != nil: result = typeRel(c, ff, a)
|
||||
|
||||
of tyGenericInvokation:
|
||||
of tyGenericInvocation:
|
||||
var x = a.skipGenericAlias
|
||||
if x.kind == tyGenericInvokation or f.sons[0].kind != tyGenericBody:
|
||||
#InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation")
|
||||
if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
|
||||
#InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
|
||||
# simply no match for now:
|
||||
discard
|
||||
elif x.kind == tyGenericInst and
|
||||
@@ -896,7 +897,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
# we steal the generic parameters from the tyGenericBody:
|
||||
for i in countup(1, sonsLen(f) - 1):
|
||||
var x = PType(idTableGet(c.bindings, f.sons[0].sons[i - 1]))
|
||||
if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}:
|
||||
if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}:
|
||||
internalError("wrong instantiated type!")
|
||||
put(c.bindings, f.sons[i], x)
|
||||
|
||||
@@ -1015,9 +1016,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
if result != isNone: put(c.bindings, f, aOrig)
|
||||
else:
|
||||
result = isNone
|
||||
elif prev.kind == tyStatic:
|
||||
if aOrig.kind == tyStatic:
|
||||
result = typeRel(c, prev.lastSon, a)
|
||||
if result != isNone and prev.n != nil:
|
||||
if not exprStructuralEquivalent(prev.n, aOrig.n):
|
||||
result = isNone
|
||||
else: result = isNone
|
||||
else:
|
||||
result = typeRel(c, prev, aOrig)
|
||||
|
||||
# XXX endless recursion?
|
||||
#result = typeRel(c, prev, aOrig)
|
||||
result = isNone
|
||||
of tyTypeDesc:
|
||||
var prev = PType(idTableGet(c.bindings, f))
|
||||
if prev == nil:
|
||||
@@ -1056,7 +1065,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
|
||||
|
||||
of tyFromExpr:
|
||||
# fix the expression, so it contains the already instantiated types
|
||||
if f.n == nil: return isGeneric
|
||||
if f.n == nil or f.n.kind == nkEmpty: return isGeneric
|
||||
let reevaluated = tryResolvingStaticExpr(c, f.n)
|
||||
case reevaluated.typ.kind
|
||||
of tyTypeDesc:
|
||||
@@ -1156,6 +1165,15 @@ proc isInlineIterator*(t: PType): bool =
|
||||
result = t.kind == tyIter or
|
||||
(t.kind == tyBuiltInTypeClass and t.base.kind == tyIter)
|
||||
|
||||
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 paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
argSemantized, argOrig: PNode): PNode =
|
||||
var
|
||||
@@ -1178,8 +1196,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
|
||||
if argType.kind == tyStatic:
|
||||
if m.callee.kind == tyGenericBody and tfGenericTypeParam notin argType.flags:
|
||||
result = newNodeI(nkType, argOrig.info)
|
||||
result.typ = makeTypeFromExpr(c, arg)
|
||||
result = newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg))
|
||||
return
|
||||
else:
|
||||
var evaluated = c.semTryConstExpr(c, arg)
|
||||
@@ -1252,12 +1269,25 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
|
||||
result = implicitConv(nkHiddenStdConv, f, result, m, c)
|
||||
of isGeneric:
|
||||
inc(m.genericMatches)
|
||||
result = copyTree(arg)
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
# BUG: f may not be the right key!
|
||||
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
# BUGFIX: use ``result.typ`` and not `f` here
|
||||
when true:
|
||||
if arg.typ == nil:
|
||||
result = arg
|
||||
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
elif arg.typ.isEmptyContainer:
|
||||
result = arg.copyTree
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
else:
|
||||
result = arg
|
||||
else:
|
||||
# XXX Why is this ever necessary? arg's type should not be retrofitted
|
||||
# to match formal's type in this way!
|
||||
result = copyTree(arg)
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
# BUG: f may not be the right key!
|
||||
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
# BUGFIX: use ``result.typ`` and not `f` here
|
||||
of isFromIntLit:
|
||||
# too lazy to introduce another ``*matches`` field, so we conflate
|
||||
# ``isIntConv`` and ``isIntLit`` here:
|
||||
@@ -1441,13 +1471,14 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
return
|
||||
checkConstraint(n.sons[a].sons[1])
|
||||
if m.baseTypeMatch:
|
||||
assert(container == nil)
|
||||
#assert(container == nil)
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||
addSon(container, arg)
|
||||
setSon(m.call, formal.position + 1, container)
|
||||
if f != formalLen - 1: container = nil
|
||||
else:
|
||||
else:
|
||||
setSon(m.call, formal.position + 1, arg)
|
||||
inc f
|
||||
else:
|
||||
# unnamed param
|
||||
if f >= formalLen:
|
||||
@@ -1466,7 +1497,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
|
||||
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
|
||||
n.sons[a], nOrig.sons[a])
|
||||
if (arg != nil) and m.baseTypeMatch and (container != nil):
|
||||
if arg != nil and m.baseTypeMatch and container != nil:
|
||||
addSon(container, arg)
|
||||
incrIndexType(container.typ)
|
||||
else:
|
||||
@@ -1480,7 +1511,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
internalError(n.sons[a].info, "matches")
|
||||
return
|
||||
formal = m.callee.n.sons[f].sym
|
||||
if containsOrIncl(marker, formal.position):
|
||||
if containsOrIncl(marker, formal.position) and container.isNil:
|
||||
# already in namedParams:
|
||||
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
|
||||
m.state = csNoMatch
|
||||
@@ -1493,17 +1524,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
|
||||
m.state = csNoMatch
|
||||
return
|
||||
if m.baseTypeMatch:
|
||||
assert(container == nil)
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||
#assert(container == nil)
|
||||
if container.isNil:
|
||||
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
|
||||
addSon(container, arg)
|
||||
setSon(m.call, formal.position + 1,
|
||||
implicitConv(nkHiddenStdConv, formal.typ, container, m, c))
|
||||
if f != formalLen - 1: container = nil
|
||||
#if f != formalLen - 1: container = nil
|
||||
|
||||
# pick the formal from the end, so that 'x, y, varargs, z' works:
|
||||
f = max(f, formalLen - n.len + a + 1)
|
||||
else:
|
||||
setSon(m.call, formal.position + 1, arg)
|
||||
inc(f)
|
||||
container = nil
|
||||
checkConstraint(n.sons[a])
|
||||
inc(a)
|
||||
inc(f)
|
||||
|
||||
proc semFinishOperands*(c: PContext, n: PNode) =
|
||||
# this needs to be called to ensure that after overloading resolution every
|
||||
|
||||
@@ -321,6 +321,7 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||
|
||||
proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
||||
result = transformSons(c, n)
|
||||
if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
|
||||
var n = result.PNode
|
||||
case n.sons[0].kind
|
||||
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||
@@ -491,7 +492,8 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
var newC = newTransCon(getCurrOwner(c))
|
||||
newC.forStmt = n
|
||||
newC.forLoopBody = loopBody
|
||||
internalAssert iter.kind == skIterator
|
||||
# this can fail for 'nimsuggest' and 'check':
|
||||
if iter.kind != skIterator: return result
|
||||
# generate access statements for the parameters (unless they are constant)
|
||||
pushTransCon(c, newC)
|
||||
for i in countup(1, sonsLen(call) - 1):
|
||||
|
||||
@@ -28,8 +28,9 @@ proc hashTree(n: PNode): THash =
|
||||
of nkFloatLit..nkFloat64Lit:
|
||||
if (n.floatVal >= - 1000000.0) and (n.floatVal <= 1000000.0):
|
||||
result = result !& toInt(n.floatVal)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
result = result !& hash(n.strVal)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
if not n.strVal.isNil:
|
||||
result = result !& hash(n.strVal)
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result = result !& hashTree(n.sons[i])
|
||||
|
||||
@@ -250,7 +250,7 @@ proc containsObject(t: PType): bool =
|
||||
|
||||
proc isObjectWithTypeFieldPredicate(t: PType): bool =
|
||||
result = t.kind == tyObject and t.sons[0] == nil and
|
||||
not (t.sym != nil and sfPure in t.sym.flags) and
|
||||
not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and
|
||||
tfFinal notin t.flags
|
||||
|
||||
proc analyseObjectWithTypeFieldAux(t: PType,
|
||||
@@ -396,7 +396,7 @@ proc rangeToStr(n: PNode): string =
|
||||
const
|
||||
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
|
||||
"Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc",
|
||||
"GenericInvokation", "GenericBody", "GenericInst", "GenericParam",
|
||||
"GenericInvocation", "GenericBody", "GenericInst", "GenericParam",
|
||||
"distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
|
||||
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
|
||||
"pointer", "OpenArray[$1]", "string", "CString", "Forward",
|
||||
@@ -432,9 +432,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
||||
result = $t.n.intVal
|
||||
else:
|
||||
result = "int literal(" & $t.n.intVal & ")"
|
||||
of tyGenericBody, tyGenericInst, tyGenericInvokation:
|
||||
of tyGenericBody, tyGenericInst, tyGenericInvocation:
|
||||
result = typeToString(t.sons[0]) & '['
|
||||
for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
|
||||
for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)):
|
||||
if i > 1: add(result, ", ")
|
||||
add(result, typeToString(t.sons[i], preferGenericArg))
|
||||
add(result, ']')
|
||||
@@ -649,7 +649,7 @@ proc lengthOrd(t: PType): BiggestInt =
|
||||
type
|
||||
TDistinctCompare* = enum ## how distinct types are to be compared
|
||||
dcEq, ## a and b should be the same type
|
||||
dcEqIgnoreDistinct, ## compare symetrically: (distinct a) == b, a == b
|
||||
dcEqIgnoreDistinct, ## compare symmetrically: (distinct a) == b, a == b
|
||||
## or a == (distinct b)
|
||||
dcEqOrDistinctOf ## a equals b or a is distinct of b
|
||||
|
||||
@@ -796,7 +796,7 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
|
||||
else:
|
||||
# expensive structural equality test; however due to the way generic and
|
||||
# objects work, if one of the types does **not** contain tfFromGeneric,
|
||||
# they cannot be equal. The check ``a.sym.Id == b.sym.Id`` checks
|
||||
# they cannot be equal. The check ``a.sym.id == b.sym.id`` checks
|
||||
# for the same origin and is essential because we don't want "pure"
|
||||
# structural type equivalence:
|
||||
#
|
||||
@@ -941,7 +941,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
|
||||
if result and ExactGenericParams in c.flags:
|
||||
result = a.sym.position == b.sym.position
|
||||
of tyGenericInvokation, tyGenericBody, tySequence,
|
||||
of tyGenericInvocation, tyGenericBody, tySequence,
|
||||
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
|
||||
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
|
||||
tyOrdinal, tyTypeClasses, tyFieldAccessor:
|
||||
@@ -1029,16 +1029,18 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||
|
||||
proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
|
||||
flags: TTypeAllowedFlags = {}): PType =
|
||||
if n != nil:
|
||||
if n != nil:
|
||||
result = typeAllowedAux(marker, n.typ, kind, flags)
|
||||
#if not result: debug(n.typ)
|
||||
if result == nil:
|
||||
case n.kind
|
||||
of nkNone..nkNilLit:
|
||||
of nkNone..nkNilLit:
|
||||
discard
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
result = typeAllowedNode(marker, n.sons[i], kind, flags)
|
||||
let it = n.sons[i]
|
||||
if it.kind == nkRecCase and kind == skConst: return n.typ
|
||||
result = typeAllowedNode(marker, it, kind, flags)
|
||||
if result != nil: break
|
||||
|
||||
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
|
||||
@@ -1085,7 +1087,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||
if taField notin flags: result = t
|
||||
of tyTypeClasses:
|
||||
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
|
||||
of tyGenericBody, tyGenericParam, tyGenericInvokation,
|
||||
of tyGenericBody, tyGenericParam, tyGenericInvocation,
|
||||
tyNone, tyForward, tyFromExpr, tyFieldAccessor:
|
||||
result = t
|
||||
of tyNil:
|
||||
@@ -1098,7 +1100,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||
result = typeAllowedAux(marker, lastSon(t), kind, flags)
|
||||
of tyRange:
|
||||
if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin
|
||||
{tyChar, tyEnum, tyInt..tyFloat128}: result = t
|
||||
{tyChar, tyEnum, tyInt..tyFloat128, tyUInt8..tyUInt32}: result = t
|
||||
of tyOpenArray, tyVarargs:
|
||||
if kind != skParam: result = t
|
||||
else: result = typeAllowedAux(marker, t.sons[0], skVar, flags)
|
||||
@@ -1118,7 +1120,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||
result = typeAllowedAux(marker, t.sons[i], kind, flags)
|
||||
if result != nil: break
|
||||
of tyObject, tyTuple:
|
||||
if kind == skConst and t.kind == tyObject: return t
|
||||
if kind == skConst and t.kind == tyObject and t.sons[0] != nil: return t
|
||||
let flags = flags+{taField}
|
||||
for i in countup(0, sonsLen(t) - 1):
|
||||
result = typeAllowedAux(marker, t.sons[i], kind, flags)
|
||||
|
||||
@@ -123,8 +123,12 @@ proc createStrKeepNode(x: var TFullReg) =
|
||||
if x.node.isNil:
|
||||
x.node = newNode(nkStrLit)
|
||||
elif x.node.kind == nkNilLit:
|
||||
when defined(useNodeIds):
|
||||
let id = x.node.id
|
||||
system.reset(x.node[])
|
||||
x.node.kind = nkStrLit
|
||||
when defined(useNodeIds):
|
||||
x.node.id = id
|
||||
elif x.node.kind notin {nkStrLit..nkTripleStrLit} or
|
||||
nfAllConst in x.node.flags:
|
||||
# XXX this is hacky; tests/txmlgen triggers it:
|
||||
@@ -154,7 +158,7 @@ proc moveConst(x: var TFullReg, y: TFullReg) =
|
||||
of rkNodeAddr: x.nodeAddr = y.nodeAddr
|
||||
|
||||
# this seems to be the best way to model the reference semantics
|
||||
# of PNimrodNode:
|
||||
# of system.NimNode:
|
||||
template asgnRef(x, y: expr) = moveConst(x, y)
|
||||
|
||||
proc copyValue(src: PNode): PNode =
|
||||
@@ -772,10 +776,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
stackTrace(c, tos, pc, errNilAccess)
|
||||
of opcEcho:
|
||||
let rb = instr.regB
|
||||
for i in ra..ra+rb-1:
|
||||
#if regs[i].kind != rkNode: debug regs[i]
|
||||
write(stdout, regs[i].node.strVal)
|
||||
writeln(stdout, "")
|
||||
if rb == 1:
|
||||
msgWriteln(regs[ra].node.strVal)
|
||||
else:
|
||||
var outp = ""
|
||||
for i in ra..ra+rb-1:
|
||||
#if regs[i].kind != rkNode: debug regs[i]
|
||||
outp.add(regs[i].node.strVal)
|
||||
msgWriteln(outp)
|
||||
of opcContainsSet:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
|
||||
@@ -1087,14 +1095,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcNAdd:
|
||||
decodeBC(rkNode)
|
||||
var u = regs[rb].node
|
||||
u.add(regs[rc].node)
|
||||
if u.kind notin {nkEmpty..nkNilLit}:
|
||||
u.add(regs[rc].node)
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
|
||||
regs[ra].node = u
|
||||
of opcNAddMultiple:
|
||||
decodeBC(rkNode)
|
||||
let x = regs[rc].node
|
||||
var u = regs[rb].node
|
||||
# XXX can be optimized:
|
||||
for i in 0.. <x.len: u.add(x.sons[i])
|
||||
if u.kind notin {nkEmpty..nkNilLit}:
|
||||
# XXX can be optimized:
|
||||
for i in 0.. <x.len: u.add(x.sons[i])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
|
||||
regs[ra].node = u
|
||||
of opcNKind:
|
||||
decodeB(rkInt)
|
||||
@@ -1127,7 +1141,21 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
|
||||
of opcNGetType:
|
||||
internalError(c.debug[pc], "unknown opcode " & $instr.opcode)
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
if rc == 0:
|
||||
ensureKind(rkNode)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
else:
|
||||
# typeKind opcode:
|
||||
ensureKind(rkInt)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].intVal = ord(regs[rb].node.typ.kind)
|
||||
#else:
|
||||
# stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
of opcNStrVal:
|
||||
decodeB(rkNode)
|
||||
createStr regs[ra]
|
||||
@@ -1364,9 +1392,11 @@ var
|
||||
globalCtx: PCtx
|
||||
|
||||
proc setupGlobalCtx(module: PSym) =
|
||||
if globalCtx.isNil: globalCtx = newCtx(module)
|
||||
else: refresh(globalCtx, module)
|
||||
registerAdditionalOps(globalCtx)
|
||||
if globalCtx.isNil:
|
||||
globalCtx = newCtx(module)
|
||||
registerAdditionalOps(globalCtx)
|
||||
else:
|
||||
refresh(globalCtx, module)
|
||||
|
||||
proc myOpen(module: PSym): PPassContext =
|
||||
#var c = newEvalContext(module, emRepl)
|
||||
@@ -1436,7 +1466,9 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
||||
# immediate macros can bypass any type and arity checking so we check the
|
||||
# arity here too:
|
||||
if sym.typ.len > n.safeLen and sym.typ.len > 1:
|
||||
globalError(n.info, "got $#, but expected $# argument(s)" % [$ <n.safeLen, $ <sym.typ.len])
|
||||
globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [
|
||||
n.renderTree,
|
||||
$ <n.safeLen, $ <sym.typ.len])
|
||||
|
||||
setupGlobalCtx(module)
|
||||
var c = globalCtx
|
||||
|
||||
@@ -213,6 +213,7 @@ proc newCtx*(module: PSym): PCtx =
|
||||
proc refresh*(c: PCtx, module: PSym) =
|
||||
c.module = module
|
||||
c.prc = PProc(blocks: @[])
|
||||
c.loopIterations = MaxLoopIterations
|
||||
|
||||
proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
|
||||
c.callbacks.add((name, callback))
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2013 Andreas Rumpf
|
||||
# (c) Copyright 2015 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
import ast, types, msgs, osproc, streams, options
|
||||
import ast, types, msgs, osproc, streams, options, idents
|
||||
|
||||
proc readOutput(p: Process): string =
|
||||
result = ""
|
||||
@@ -19,11 +19,14 @@ proc readOutput(p: Process): string =
|
||||
discard p.waitForExit
|
||||
|
||||
proc opGorge*(cmd, input: string): string =
|
||||
var p = startCmd(cmd)
|
||||
if input.len != 0:
|
||||
p.inputStream.write(input)
|
||||
p.inputStream.close()
|
||||
result = p.readOutput
|
||||
try:
|
||||
var p = startProcess(cmd, options={poEvalCommand})
|
||||
if input.len != 0:
|
||||
p.inputStream.write(input)
|
||||
p.inputStream.close()
|
||||
result = p.readOutput
|
||||
except IOError, OSError:
|
||||
result = ""
|
||||
|
||||
proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
|
||||
try:
|
||||
@@ -36,3 +39,116 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
|
||||
except IOError:
|
||||
localError(info, errCannotOpenFile, file)
|
||||
result = ""
|
||||
|
||||
proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode =
|
||||
let sym = newSym(skType, getIdent(name), t.owner, info)
|
||||
result = newSymNode(sym)
|
||||
result.typ = t
|
||||
|
||||
proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode
|
||||
|
||||
proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode =
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicTypeX(name, t, info)
|
||||
for i in 0 .. < t.len:
|
||||
if t.sons[i] == nil:
|
||||
let void = atomicTypeX("void", t, info)
|
||||
void.typ = newType(tyEmpty, t.owner)
|
||||
result.add void
|
||||
else:
|
||||
result.add mapTypeToAst(t.sons[i], info)
|
||||
|
||||
proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode =
|
||||
template atomicType(name): expr = atomicTypeX(name, t, info)
|
||||
|
||||
case t.kind
|
||||
of tyNone: result = atomicType("none")
|
||||
of tyBool: result = atomicType("bool")
|
||||
of tyChar: result = atomicType("char")
|
||||
of tyNil: result = atomicType("nil")
|
||||
of tyExpr: result = atomicType("expr")
|
||||
of tyStmt: result = atomicType("stmt")
|
||||
of tyEmpty: result = atomicType"void"
|
||||
of tyArrayConstr, tyArray:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicType("array")
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
result.add mapTypeToAst(t.sons[1], info)
|
||||
of tyTypeDesc:
|
||||
if t.base != nil:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicType("typeDesc")
|
||||
result.add mapTypeToAst(t.base, info)
|
||||
else:
|
||||
result = atomicType"typeDesc"
|
||||
of tyGenericInvocation:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
for i in 0 .. < t.len:
|
||||
result.add mapTypeToAst(t.sons[i], info)
|
||||
of tyGenericInst, tyGenericBody, tyOrdinal, tyUserTypeClassInst:
|
||||
result = mapTypeToAst(t.lastSon, info)
|
||||
of tyGenericParam, tyDistinct, tyForward: result = atomicType(t.sym.name.s)
|
||||
of tyObject:
|
||||
if allowRecursion:
|
||||
result = newNodeIT(nkObjectTy, info, t)
|
||||
if t.sons[0] == nil:
|
||||
result.add ast.emptyNode
|
||||
else:
|
||||
result.add mapTypeToAst(t.sons[0], info)
|
||||
result.add copyTree(t.n)
|
||||
else:
|
||||
result = atomicType(t.sym.name.s)
|
||||
of tyEnum:
|
||||
result = newNodeIT(nkEnumTy, info, t)
|
||||
result.add copyTree(t.n)
|
||||
of tyTuple: result = mapTypeToBracket("tuple", t, info)
|
||||
of tySet: result = mapTypeToBracket("set", t, info)
|
||||
of tyPtr: result = mapTypeToBracket("ptr", t, info)
|
||||
of tyRef: result = mapTypeToBracket("ref", t, info)
|
||||
of tyVar: result = mapTypeToBracket("var", t, info)
|
||||
of tySequence: result = mapTypeToBracket("seq", t, info)
|
||||
of tyProc: result = mapTypeToBracket("proc", t, info)
|
||||
of tyOpenArray: result = mapTypeToBracket("openArray", t, info)
|
||||
of tyRange:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicType("range")
|
||||
result.add t.n.sons[0].copyTree
|
||||
result.add t.n.sons[1].copyTree
|
||||
of tyPointer: result = atomicType"pointer"
|
||||
of tyString: result = atomicType"string"
|
||||
of tyCString: result = atomicType"cstring"
|
||||
of tyInt: result = atomicType"int"
|
||||
of tyInt8: result = atomicType"int8"
|
||||
of tyInt16: result = atomicType"int16"
|
||||
of tyInt32: result = atomicType"int32"
|
||||
of tyInt64: result = atomicType"int64"
|
||||
of tyFloat: result = atomicType"float"
|
||||
of tyFloat32: result = atomicType"float32"
|
||||
of tyFloat64: result = atomicType"float64"
|
||||
of tyFloat128: result = atomicType"float128"
|
||||
of tyUInt: result = atomicType"uint"
|
||||
of tyUInt8: result = atomicType"uint8"
|
||||
of tyUInt16: result = atomicType"uint16"
|
||||
of tyUInt32: result = atomicType"uint32"
|
||||
of tyUInt64: result = atomicType"uint64"
|
||||
of tyBigNum: result = atomicType"bignum"
|
||||
of tyConst: result = mapTypeToBracket("const", t, info)
|
||||
of tyMutable: result = mapTypeToBracket("mutable", t, info)
|
||||
of tyVarargs: result = mapTypeToBracket("varargs", t, info)
|
||||
of tyIter: result = mapTypeToBracket("iter", t, info)
|
||||
of tyProxy: result = atomicType"error"
|
||||
of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info)
|
||||
of tyUserTypeClass: result = mapTypeToBracket("userTypeClass", t, info)
|
||||
of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info)
|
||||
of tyAnd: result = mapTypeToBracket("and", t, info)
|
||||
of tyOr: result = mapTypeToBracket("or", t, info)
|
||||
of tyNot: result = mapTypeToBracket("not", t, info)
|
||||
of tyAnything: result = atomicType"anything"
|
||||
of tyStatic, tyFromExpr, tyFieldAccessor:
|
||||
result = newNodeIT(nkBracketExpr, info, t)
|
||||
result.add atomicType("static")
|
||||
if t.n != nil:
|
||||
result.add t.n.copyTree
|
||||
|
||||
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
|
||||
result = mapTypeToAst(t, info, true)
|
||||
|
||||
@@ -604,7 +604,8 @@ proc genNarrowU(c: PCtx; n: PNode; dest: TDest) =
|
||||
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
|
||||
# uint is uint64 in the VM, we we only need to mask the result for
|
||||
# other unsigned types:
|
||||
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}:
|
||||
if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or
|
||||
(t.kind == tyInt and t.size == 4):
|
||||
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
|
||||
|
||||
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||
@@ -893,7 +894,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||
of mHigh:
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
let tmp = c.genx(n.sons[1])
|
||||
if n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind == tyString:
|
||||
case n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind:
|
||||
of tyString, tyCString:
|
||||
c.gABI(n, opcLenStr, dest, tmp, 1)
|
||||
else:
|
||||
c.gABI(n, opcLenSeq, dest, tmp, 1)
|
||||
@@ -948,7 +950,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||
of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal)
|
||||
of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol)
|
||||
of mNIdent: genUnaryABC(c, n, dest, opcNIdent)
|
||||
of mNGetType: genUnaryABC(c, n, dest, opcNGetType)
|
||||
of mNGetType:
|
||||
let tmp = c.genx(n.sons[1])
|
||||
if dest < 0: dest = c.getTemp(n.typ)
|
||||
c.gABC(n, opcNGetType, dest, tmp, if n[0].sym.name.s == "typeKind": 1 else: 0)
|
||||
c.freeTemp(tmp)
|
||||
#genUnaryABC(c, n, dest, opcNGetType)
|
||||
of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
|
||||
of mNSetIntVal:
|
||||
unused(n, dest)
|
||||
@@ -1244,8 +1251,8 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
|
||||
c.globals.add(getNullValue(s.typ, n.info))
|
||||
s.position = c.globals.len
|
||||
# This is rather hard to support, due to the laziness of the VM code
|
||||
# generator. See tests/compile/tmacro2 for why this is necesary:
|
||||
# var decls{.compileTime.}: seq[PNimrodNode] = @[]
|
||||
# generator. See tests/compile/tmacro2 for why this is necessary:
|
||||
# var decls{.compileTime.}: seq[NimNode] = @[]
|
||||
let dest = c.getTemp(s.typ)
|
||||
c.gABx(n, opcLdGlobal, dest, s.position)
|
||||
let tmp = c.genx(s.ast)
|
||||
|
||||
@@ -5,10 +5,17 @@
|
||||
|
||||
# You may set environment variables with
|
||||
# @putenv "key" "val"
|
||||
# Environment variables cannot be used in the options, however!
|
||||
# Environment variables can be accessed like so:
|
||||
# gcc.path %= "$CC_PATH"
|
||||
|
||||
cc = gcc
|
||||
|
||||
# additional options always passed to the compiler:
|
||||
--parallel_build: "0" # 0 to auto-detect number of processors
|
||||
|
||||
hint[LineTooLong]=off
|
||||
#hint[XDeclaredButNotUsed]=off
|
||||
|
||||
# example of how to setup a cross-compiler:
|
||||
arm.linux.gcc.exe = "arm-linux-gcc"
|
||||
arm.linux.gcc.linkerexe = "arm-linux-gcc"
|
||||
@@ -21,6 +28,7 @@ mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc"
|
||||
@end
|
||||
|
||||
path="$lib/core"
|
||||
|
||||
path="$lib/pure"
|
||||
path="$lib/pure/collections"
|
||||
path="$lib/pure/concurrency"
|
||||
@@ -64,12 +72,6 @@ path="$lib/pure/unidecode"
|
||||
opt:speed
|
||||
@end
|
||||
|
||||
# additional options always passed to the compiler:
|
||||
--parallel_build: "0" # 0 to auto-detect number of processors
|
||||
|
||||
hint[LineTooLong]=off
|
||||
#hint[XDeclaredButNotUsed]=off
|
||||
|
||||
@if unix:
|
||||
@if not bsd:
|
||||
# -fopenmp
|
||||
@@ -103,13 +105,27 @@ hint[LineTooLong]=off
|
||||
@if macosx or freebsd:
|
||||
cc = clang
|
||||
tlsEmulation:on
|
||||
gcc.options.always = "-w -fasm-blocks"
|
||||
gcc.cpp.options.always = "-w -fasm-blocks -fpermissive"
|
||||
gcc.options.always = "-w"
|
||||
gcc.cpp.options.always = "-w -fpermissive"
|
||||
@else:
|
||||
gcc.options.always = "-w"
|
||||
gcc.cpp.options.always = "-w -fpermissive"
|
||||
@end
|
||||
|
||||
# Configuration for the VxWorks
|
||||
# This has been tested with VxWorks 6.9 only
|
||||
@if vxworks:
|
||||
# For now we only support compiling RTPs applications (i.e. no DKMs)
|
||||
gcc.options.always = "-mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
|
||||
# The linker config must add the VxWorks common library for the selected
|
||||
# processor which is usually found in:
|
||||
# "$WIND_BASE/target/lib/usr/lib/PROCESSOR_FAMILY/PROCESSOR_TYPE/common",
|
||||
# where PROCESSOR_FAMILY and PROCESSOR_TYPE are those supported by the VxWorks
|
||||
# compiler (e.g. ppc/PPC32 or mips/MIPSI64, etc)
|
||||
# For now we only support the PowerPC CPU
|
||||
gcc.options.linker %= "-L $WIND_BASE/target/lib/usr/lib/ppc/PPC32/common -mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
|
||||
@end
|
||||
|
||||
gcc.options.speed = "-O3 -fno-strict-aliasing"
|
||||
gcc.options.size = "-Os"
|
||||
gcc.options.debug = "-g3 -O0"
|
||||
|
||||
@@ -24,7 +24,7 @@ doc.section.toc = """
|
||||
</li>
|
||||
"""
|
||||
|
||||
# Chunk of HTML emmited for each entry in the HTML table of contents.
|
||||
# Chunk of HTML emitted for each entry in the HTML table of contents.
|
||||
# Available variables are:
|
||||
# * $desc: the actual docstring of the item.
|
||||
# * $header: the full version of name, including types, pragmas, tags, etc.
|
||||
@@ -45,7 +45,7 @@ $seeSrc
|
||||
</dd>
|
||||
"""
|
||||
|
||||
# Chunk of HTML emmited for each entry in the HTML table of contents.
|
||||
# Chunk of HTML emitted for each entry in the HTML table of contents.
|
||||
# See doc.item for available substitution variables.
|
||||
doc.item.toc = """
|
||||
<li><a class="reference" href="#$itemSymOrID"
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
# Configuration file for the Nim Compiler.
|
||||
# (c) 2015 Andreas Rumpf
|
||||
|
||||
# Feel free to edit the default values as you need.
|
||||
|
||||
# You may set environment variables with
|
||||
# @putenv "key" "val"
|
||||
# Environment variables cannot be used in the options, however!
|
||||
|
||||
cc = gcc
|
||||
|
||||
# example of how to setup a cross-compiler:
|
||||
arm.linux.gcc.exe = "arm-linux-gcc"
|
||||
arm.linux.gcc.linkerexe = "arm-linux-gcc"
|
||||
|
||||
cs:partial
|
||||
|
||||
path="$lib/core"
|
||||
path="$lib/pure"
|
||||
path="$lib/pure/collections"
|
||||
path="$lib/pure/concurrency"
|
||||
path="$lib/impure"
|
||||
path="$lib/wrappers"
|
||||
# path="$lib/wrappers/cairo"
|
||||
# path="$lib/wrappers/gtk"
|
||||
# path="$lib/wrappers/lua"
|
||||
# path="$lib/wrappers/opengl"
|
||||
path="$lib/wrappers/pcre"
|
||||
path="$lib/wrappers/readline"
|
||||
path="$lib/wrappers/sdl"
|
||||
# path="$lib/wrappers/x11"
|
||||
path="$lib/wrappers/zip"
|
||||
path="$lib/wrappers/libffi"
|
||||
path="$lib/windows"
|
||||
path="$lib/posix"
|
||||
path="$lib/js"
|
||||
path="$lib/pure/unidecode"
|
||||
|
||||
@if nimbabel:
|
||||
babelpath="$home/.babel/pkgs/"
|
||||
@end
|
||||
|
||||
@if release or quick:
|
||||
obj_checks:off
|
||||
field_checks:off
|
||||
range_checks:off
|
||||
bound_checks:off
|
||||
overflow_checks:off
|
||||
assertions:off
|
||||
stacktrace:off
|
||||
linetrace:off
|
||||
debugger:off
|
||||
line_dir:off
|
||||
dead_code_elim:on
|
||||
@end
|
||||
|
||||
@if release:
|
||||
opt:speed
|
||||
@end
|
||||
|
||||
# additional options always passed to the compiler:
|
||||
--parallel_build: "0" # 0 to auto-detect number of processors
|
||||
|
||||
hint[LineTooLong]=off
|
||||
#hint[XDeclaredButNotUsed]=off
|
||||
|
||||
@if unix:
|
||||
@if not bsd:
|
||||
# -fopenmp
|
||||
gcc.options.linker = "-ldl"
|
||||
gpp.options.linker = "-ldl"
|
||||
clang.options.linker = "-ldl"
|
||||
tcc.options.linker = "-ldl"
|
||||
@end
|
||||
@if bsd or haiku:
|
||||
# BSD got posix_spawn only recently, so we deactivate it for osproc:
|
||||
define:useFork
|
||||
# at least NetBSD has problems with thread local storage:
|
||||
tlsEmulation:on
|
||||
@end
|
||||
@end
|
||||
|
||||
# Configuration for the Intel C/C++ compiler:
|
||||
@if windows:
|
||||
icl.options.speed = "/Ox /arch:SSE2"
|
||||
icl.options.always = "/nologo"
|
||||
@end
|
||||
|
||||
# Configuration for the GNU C/C++ compiler:
|
||||
@if windows:
|
||||
#gcc.path = r"$nimrod\dist\mingw\bin"
|
||||
@if gcc:
|
||||
tlsEmulation:on
|
||||
@end
|
||||
@end
|
||||
|
||||
@if macosx:
|
||||
cc = clang
|
||||
tlsEmulation:on
|
||||
gcc.options.always = "-w -fasm-blocks"
|
||||
gpp.options.always = "-w -fasm-blocks -fpermissive"
|
||||
@else:
|
||||
gcc.options.always = "-w"
|
||||
gpp.options.always = "-w -fpermissive"
|
||||
@end
|
||||
|
||||
gcc.options.speed = "-O3 -fno-strict-aliasing"
|
||||
gcc.options.size = "-Os"
|
||||
gcc.options.debug = "-g3 -O0"
|
||||
|
||||
gpp.options.speed = "-O3 -fno-strict-aliasing"
|
||||
gpp.options.size = "-Os"
|
||||
gpp.options.debug = "-g3 -O0"
|
||||
#passl = "-pg"
|
||||
|
||||
# Configuration for the LLVM GCC compiler:
|
||||
llvm_gcc.options.debug = "-g"
|
||||
llvm_gcc.options.always = "-w"
|
||||
llvm_gcc.options.speed = "-O2"
|
||||
llvm_gcc.options.size = "-Os"
|
||||
|
||||
# Configuration for the LLVM CLang compiler:
|
||||
clang.options.debug = "-g"
|
||||
clang.options.always = "-w"
|
||||
clang.options.speed = "-O3"
|
||||
clang.options.size = "-Os"
|
||||
|
||||
# Configuration for the Visual C/C++ compiler:
|
||||
vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
|
||||
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
|
||||
vcc.options.always = "/nologo"
|
||||
vcc.options.speed = "/Ox /arch:SSE2"
|
||||
vcc.options.size = "/O1"
|
||||
|
||||
# Configuration for the Tiny C Compiler:
|
||||
tcc.options.always = "-w"
|
||||
@@ -1,7 +1,7 @@
|
||||
=====================================================
|
||||
Nim -- a Compiler for Nim. http://nim-lang.org/
|
||||
|
||||
Copyright (C) 2006-2014 Andreas Rumpf. All rights reserved.
|
||||
Copyright (C) 2006-2015 Andreas Rumpf. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -18,7 +18,7 @@ Advanced commands:
|
||||
track a file, currently not saved to disk
|
||||
--suggest suggest all possible symbols at position
|
||||
--def list all possible definitions at position
|
||||
--context list possible invokation context
|
||||
--context list possible invocation context
|
||||
--usages list all usages of the symbol at position
|
||||
--eval evaluates an expression
|
||||
//serve start the compiler as a service mode (CAAS)
|
||||
@@ -48,7 +48,6 @@ Advanced options:
|
||||
--os:SYMBOL set the target operating system (cross-compilation)
|
||||
--cpu:SYMBOL set the target processor (cross-compilation)
|
||||
--debuginfo enables debug information
|
||||
--debugger:on|off turn Embedded Nim Debugger on|off
|
||||
-t, --passC:OPTION pass an option to the C compiler
|
||||
-l, --passL:OPTION pass an option to the linker
|
||||
--cincludes:DIR modify the C compiler header search path
|
||||
@@ -66,7 +65,6 @@ Advanced options:
|
||||
--threadanalysis:on|off turn thread analysis on|off
|
||||
--tlsEmulation:on|off turn thread local storage emulation on|off
|
||||
--taintMode:on|off turn taint mode on|off
|
||||
--symbolFiles:on|off turn symbol files on|off (experimental)
|
||||
--implicitStatic:on|off turn implicit compile time evaluation on|off
|
||||
--patterns:on|off turn pattern matching on|off
|
||||
--skipCfg do not read the general configuration file
|
||||
@@ -86,10 +84,8 @@ Advanced options:
|
||||
that --dynlibOverride:lua matches
|
||||
dynlib: "liblua.so.3"
|
||||
--listCmd list the commands used to execute external programs
|
||||
--parallelBuild=0|1|... perform a parallel build
|
||||
--parallelBuild:0|1|... perform a parallel build
|
||||
value = number of processors (0 for auto-detect)
|
||||
--verbosity:0|1|2|3 set Nim's verbosity level (1 is default)
|
||||
--cs:none|partial set case sensitivity level (default: none);
|
||||
do not use! this setting affects the whole language
|
||||
--experimental enable experimental language features
|
||||
-v, --version show detailed version information
|
||||
|
||||
@@ -79,10 +79,3 @@ string str
|
||||
identifier ident
|
||||
indentation indent
|
||||
------------------- ------------ --------------------------------------
|
||||
|
||||
|
||||
Coding Guidelines
|
||||
=================
|
||||
|
||||
For coding guidelines see the `Internals of the Nim Compiler
|
||||
<intern.html#coding-guidelines>`_ documentation.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
The AST in Nim
|
||||
=================
|
||||
This section describes how the AST is modelled with Nim's type system.
|
||||
The AST consists of nodes (``PNimrodNode``) with a variable number of
|
||||
The AST consists of nodes (``NimNode``) with a variable number of
|
||||
children. Each node has a field named ``kind`` which describes what the node
|
||||
contains:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
type
|
||||
TNimrodNodeKind = enum ## kind of a node; only explanatory
|
||||
NimNodeKind = enum ## kind of a node; only explanatory
|
||||
nnkNone, ## invalid node kind
|
||||
nnkEmpty, ## empty node
|
||||
nnkIdent, ## node contains an identifier
|
||||
@@ -18,11 +18,11 @@ contains:
|
||||
nnkCaseStmt, ## node represents a case statement
|
||||
... ## many more
|
||||
|
||||
PNimrodNode = ref TNimrodNode
|
||||
TNimrodNode {.final.} = object
|
||||
case kind: TNimrodNodeKind ## the node's kind
|
||||
NimNode = ref NimNodeObj
|
||||
NimNodeObj = object
|
||||
case kind: NimNodeKind ## the node's kind
|
||||
of nnkNone, nnkEmpty, nnkNilLit:
|
||||
nil ## node contains no additional fields
|
||||
discard ## node contains no additional fields
|
||||
of nnkCharLit..nnkInt64Lit:
|
||||
intVal: biggestInt ## the int literal
|
||||
of nnkFloatLit..nnkFloat64Lit:
|
||||
@@ -30,13 +30,13 @@ contains:
|
||||
of nnkStrLit..nnkTripleStrLit:
|
||||
strVal: string ## the string literal
|
||||
of nnkIdent:
|
||||
ident: TNimrodIdent ## the identifier
|
||||
ident: NimIdent ## the identifier
|
||||
of nnkSym:
|
||||
symbol: PNimrodSymbol ## the symbol (after symbol lookup phase)
|
||||
symbol: NimSymbol ## the symbol (after symbol lookup phase)
|
||||
else:
|
||||
sons: seq[PNimrodNode] ## the node's sons (or children)
|
||||
sons: seq[NimNode] ## the node's sons (or children)
|
||||
|
||||
For the ``PNimrodNode`` type, the ``[]`` operator has been overloaded:
|
||||
For the ``NimNode`` type, the ``[]`` operator has been overloaded:
|
||||
``n[i]`` is ``n``'s ``i``-th child.
|
||||
|
||||
To specify the AST for the different Nim constructs, the notation
|
||||
@@ -73,10 +73,7 @@ Nim expression corresponding AST
|
||||
----------------- ---------------------------------------------
|
||||
|
||||
Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes
|
||||
get transferred into ``nnkSym`` nodes. However, a macro receives an AST that
|
||||
has not been checked for semantics and thus the identifiers have not been
|
||||
looked up. Macros should deal with ``nnkIdent`` nodes and do not need to deal
|
||||
with ``nnkSym`` nodes.
|
||||
get transferred into ``nnkSym`` nodes.
|
||||
|
||||
|
||||
Calls/expressions
|
||||
@@ -171,13 +168,13 @@ AST:
|
||||
nnkStrLit("hallo"))
|
||||
|
||||
|
||||
Dereference operator ``^``
|
||||
--------------------------
|
||||
Dereference operator ``[]``
|
||||
---------------------------
|
||||
|
||||
Concrete syntax:
|
||||
|
||||
.. code-block:: nim
|
||||
x^
|
||||
x[]
|
||||
|
||||
AST:
|
||||
|
||||
@@ -573,4 +570,3 @@ Other node kinds are especially designed to make AST manipulations easier.
|
||||
These are explained here.
|
||||
|
||||
To be written.
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ The JavaScript target doesn't have any further interfacing considerations
|
||||
since it also has garbage collection, but the C targets require you to
|
||||
initialize Nim's internals, which is done calling a ``NimMain`` function.
|
||||
Also, C code requires you to specify a forward declaration for functions or
|
||||
the compiler will asume certain types for the return value and parameters
|
||||
the compiler will assume certain types for the return value and parameters
|
||||
which will likely make your program crash at runtime.
|
||||
|
||||
The Nim compiler can generate a C interface header through the ``--header``
|
||||
@@ -427,7 +427,7 @@ Custom data types
|
||||
-----------------
|
||||
|
||||
Just like strings, custom data types that are to be shared between Nim and
|
||||
the backend will need careful consideration of who controlls who. If you want
|
||||
the backend will need careful consideration of who controls who. If you want
|
||||
to hand a Nim reference to C code, you will need to use `GC_ref
|
||||
<system.html#GC_ref>`_ to mark the reference as used, so it does not get
|
||||
freed. And for the C backend you will need to expose the `GC_unref
|
||||
|
||||
@@ -6,7 +6,6 @@ Command:
|
||||
//compile, c compile project with default code generator (C)
|
||||
//doc generate the documentation for inputfile
|
||||
//doc2 generate the documentation for the whole project
|
||||
//i start Nim in interactive mode (limited)
|
||||
|
||||
Arguments:
|
||||
arguments are passed to the program being run (if --run option is selected)
|
||||
@@ -14,7 +13,6 @@ Options:
|
||||
-p, --path:PATH add path to search paths
|
||||
-d, --define:SYMBOL define a conditional symbol
|
||||
-u, --undef:SYMBOL undefine a conditional symbol
|
||||
--symbol:SYMBOL declare a conditional symbol
|
||||
-f, --forceBuild force rebuilding of all modules
|
||||
--stackTrace:on|off turn stack tracing on|off
|
||||
--lineTrace:on|off turn line tracing on|off
|
||||
@@ -31,6 +29,7 @@ Options:
|
||||
--infChecks:on|off turn Inf checks on|off
|
||||
--deadCodeElim:on|off whole program dead code elimination on|off
|
||||
--opt:none|speed|size optimize not at all or for speed|size
|
||||
--debugger:native|endb use native debugger (gdb) | ENDB (experimental)
|
||||
--app:console|gui|lib|staticlib
|
||||
generate a console app|GUI app|DLL|static library
|
||||
-r, --run run the compiled program with given arguments
|
||||
|
||||
@@ -87,14 +87,14 @@ is triggered.
|
||||
Time measurement
|
||||
----------------
|
||||
|
||||
The GC's way of measing time uses (see ``lib/system/timers.nim`` for the
|
||||
The GC's way of measuring time uses (see ``lib/system/timers.nim`` for the
|
||||
implementation):
|
||||
|
||||
1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows.
|
||||
2) ``mach_absolute_time`` on Mac OS X.
|
||||
3) ``gettimeofday`` on Posix systems.
|
||||
|
||||
As such it supports a resolution of nano seconds internally; however the API
|
||||
As such it supports a resolution of nanoseconds internally; however the API
|
||||
uses microseconds for convenience.
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ integrations <https://github.com/Araq/Nim/wiki/Editor-Support>`_
|
||||
already available.
|
||||
|
||||
|
||||
Idetools invokation
|
||||
Idetools invocation
|
||||
===================
|
||||
|
||||
Specifying the location of the query
|
||||
@@ -35,7 +35,7 @@ Specifying the location of the query
|
||||
|
||||
All of the available idetools commands require you to specify a
|
||||
query location through the ``--track`` or ``--trackDirty`` switches.
|
||||
The general idetools invokations are::
|
||||
The general idetools invocations are::
|
||||
|
||||
nim idetools --track:FILE,LINE,COL <switches> proj.nim
|
||||
|
||||
@@ -129,7 +129,7 @@ the suggestions sorted first by scope (from innermost to outermost)
|
||||
and then by item name.
|
||||
|
||||
|
||||
Invokation context
|
||||
Invocation context
|
||||
------------------
|
||||
|
||||
The ``--context`` idetools switch is very similar to the suggestions
|
||||
@@ -163,7 +163,7 @@ running/debugged user project.
|
||||
Compiler as a service (CAAS)
|
||||
============================
|
||||
|
||||
The ocasional use of idetools is acceptable for things like
|
||||
The occasional use of idetools is acceptable for things like
|
||||
definitions, where the user puts the cursor on a symbol or double
|
||||
clicks it and after a second or two the IDE displays where that
|
||||
symbol is defined. Such latencies would be terrible for features
|
||||
@@ -533,10 +533,10 @@ run it manually. First you have to compile the tester::
|
||||
Running the ``caasdriver`` without parameters will attempt to process
|
||||
all the test cases in all three operation modes. If a test succeeds
|
||||
nothing will be printed and the process will exit with zero. If any
|
||||
test fails, the specific line of the test preceeding the failure
|
||||
test fails, the specific line of the test preceding the failure
|
||||
and the failure itself will be dumped to stdout, along with a final
|
||||
indicator of the success state and operation mode. You can pass the
|
||||
parameter ``verbose`` to force all output even on successfull tests.
|
||||
parameter ``verbose`` to force all output even on successful tests.
|
||||
|
||||
The normal operation mode is called ``ProcRun`` and it involves
|
||||
starting a process for each command or query, similar to running
|
||||
|
||||
@@ -236,7 +236,7 @@ too. Type converters fall into this category:
|
||||
|
||||
If in the above example module ``B`` is re-compiled, but ``A`` is not then
|
||||
``B`` needs to be aware of ``toBool`` even though ``toBool`` is not referenced
|
||||
in ``B`` *explicitely*.
|
||||
in ``B`` *explicitly*.
|
||||
|
||||
Both the multi method and the type converter problems are solved by storing
|
||||
them in special sections in the ROD file that are loaded *unconditionally*
|
||||
@@ -370,7 +370,7 @@ needed as the data structures needs to be rebuilt periodically anyway.
|
||||
|
||||
Complete traversal is done in this way::
|
||||
|
||||
for each page decriptor d:
|
||||
for each page descriptor d:
|
||||
for each bit in d:
|
||||
if bit == 1:
|
||||
traverse the pointer belonging to this bit
|
||||
@@ -406,7 +406,7 @@ The generated code looks roughly like this:
|
||||
setRef(&r->left)
|
||||
}
|
||||
|
||||
Note that for systems with a continous stack (which most systems have)
|
||||
Note that for systems with a continuous stack (which most systems have)
|
||||
the check whether the ref is on the stack is very cheap (only two
|
||||
comparisons).
|
||||
|
||||
|
||||
14
doc/lib.txt
14
doc/lib.txt
@@ -185,10 +185,19 @@ Math libraries
|
||||
* `complex <complex.html>`_
|
||||
This module implements complex numbers and their mathematical operations.
|
||||
|
||||
* `rationals <rationals.html>`_
|
||||
This module implements rational numbers and their mathematical operations.
|
||||
|
||||
* `fenv <fenv.html>`_
|
||||
Floating-point environment. Handling of floating-point rounding and
|
||||
exceptions (overflow, zero-devide, etc.).
|
||||
|
||||
* `basic2d <basic2d.html>`_
|
||||
Basic 2d support with vectors, points, matrices and some basic utilities.
|
||||
|
||||
* `basic3d <basic3d.html>`_
|
||||
Basic 3d support with vectors, points, matrices and some basic utilities.
|
||||
|
||||
|
||||
Internet Protocols and Support
|
||||
------------------------------
|
||||
@@ -218,9 +227,6 @@ Internet Protocols and Support
|
||||
* `smtp <smtp.html>`_
|
||||
This module implement a simple SMTP client.
|
||||
|
||||
* `irc <irc.html>`_
|
||||
This module implements an asynchronous IRC client.
|
||||
|
||||
* `ftpclient <ftpclient.html>`_
|
||||
This module implements an FTP client.
|
||||
|
||||
@@ -367,7 +373,7 @@ Miscellaneous
|
||||
-------------
|
||||
|
||||
* `events <events.html>`_
|
||||
This module implements an event system that is not dependant on external
|
||||
This module implements an event system that is not dependent on external
|
||||
graphical toolkits.
|
||||
|
||||
* `oids <oids.html>`_
|
||||
|
||||
@@ -25,9 +25,9 @@ with ``'``. An example::
|
||||
|
||||
ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
|
||||
|
||||
The binary ``^*`` operator is used as a shorthand for 0 or more occurances
|
||||
The binary ``^*`` operator is used as a shorthand for 0 or more occurrences
|
||||
separated by its second argument; likewise ``^+`` means 1 or more
|
||||
occurances: ``a ^+ b`` is short for ``a (b a)*``
|
||||
occurrences: ``a ^+ b`` is short for ``a (b a)*``
|
||||
and ``a ^* b`` is short for ``(a (b a)*)?``. Example::
|
||||
|
||||
arrayConstructor = '[' expr ^* ',' ']'
|
||||
|
||||
@@ -12,10 +12,8 @@ Binary operators have 11 different levels of precedence.
|
||||
Associativity
|
||||
-------------
|
||||
|
||||
Binary operators whose first character is ``^`` or its last character
|
||||
is ``>`` are right-associative, all other binary operators are left-associative.
|
||||
|
||||
Exception: The single "greater than" ``>`` operator is left-associative too.
|
||||
Binary operators whose first character is ``^`` are right-associative, all
|
||||
other binary operators are left-associative.
|
||||
|
||||
Operators ending in ``>`` but longer than a single character are
|
||||
called `arrow like`:idx:.
|
||||
@@ -61,7 +59,7 @@ Precedence level Operators First charact
|
||||
Strong spaces
|
||||
-------------
|
||||
|
||||
The number of spaces preceeding a non-keyword operator affects precedence
|
||||
The number of spaces preceding a non-keyword operator affects precedence
|
||||
if the experimental parser directive ``#!strongSpaces`` is used. Indentation
|
||||
is not used to determine the number of spaces. If 2 or more operators have the
|
||||
same number of preceding spaces the precedence table applies, so ``1 + 3 * 4``
|
||||
|
||||
@@ -25,7 +25,7 @@ For the purposes of code generation, all static params are treated as
|
||||
generic params - the proc will be compiled separately for each unique
|
||||
supplied value (or combination of values).
|
||||
|
||||
Furthermore, the system module defines a `semistatic[T]` type than can be
|
||||
Furthermore, the system module defines a `semistatic[T]` type that can be
|
||||
used to declare procs accepting both static and run-time values, which can
|
||||
optimize their body according to the supplied param using the `isStatic(p)`
|
||||
predicate:
|
||||
|
||||
@@ -1142,7 +1142,7 @@ modules like `db_sqlite <db_sqlite.html>`_.
|
||||
Void type
|
||||
---------
|
||||
|
||||
The ``void`` type denotes the absense of any type. Parameters of
|
||||
The ``void`` type denotes the absence of any type. Parameters of
|
||||
type ``void`` are treated as non-existent, ``void`` as a return type means that
|
||||
the procedure does not return a value:
|
||||
|
||||
|
||||
943
doc/nimc.txt
943
doc/nimc.txt
File diff suppressed because it is too large
Load Diff
@@ -25,9 +25,9 @@ Compile nimgrep with the command::
|
||||
And copy the executable somewhere in your ``$PATH``.
|
||||
|
||||
|
||||
Command line switches
|
||||
=====================
|
||||
|
||||
Command line switches
|
||||
=====================
|
||||
|
||||
Usage:
|
||||
nimgrep [options] [pattern] [replacement] (file/directory)*
|
||||
Options:
|
||||
@@ -37,7 +37,7 @@ Options:
|
||||
--re pattern is a regular expression (default); extended
|
||||
syntax for the regular expression is always turned on
|
||||
--recursive process directories recursively
|
||||
--confirm confirm each occurence/replacement; there is a chance
|
||||
--confirm confirm each occurrence/replacement; there is a chance
|
||||
to abort any time without touching the file
|
||||
--stdin read pattern from stdin (to avoid the shell's confusing
|
||||
quoting rules)
|
||||
|
||||
@@ -190,6 +190,6 @@ Real world example
|
||||
The installers for the Nim compiler itself are generated by niminst. Have a
|
||||
look at its configuration file:
|
||||
|
||||
.. include:: compiler/nim.ini
|
||||
.. include:: compiler/installer.ini
|
||||
:literal:
|
||||
|
||||
|
||||
@@ -749,7 +749,8 @@ Forward declarations
|
||||
--------------------
|
||||
|
||||
Every variable, procedure, etc. needs to be declared before it can be used.
|
||||
(The reason for this is compilation efficiency.)
|
||||
(The reason for this is that it is non-trivial to do better than that in a
|
||||
language that supports meta programming as extensively as Nim does.)
|
||||
However, this cannot be done for mutually recursive procedures:
|
||||
|
||||
.. code-block:: nim
|
||||
@@ -767,7 +768,7 @@ introduced to the compiler before it is completely defined. The syntax for
|
||||
such a forward declaration is simple: just omit the ``=`` and the
|
||||
procedure's body.
|
||||
|
||||
Later versions of the language may get rid of the need for forward
|
||||
Later versions of the language will weaken the requirements for forward
|
||||
declarations.
|
||||
|
||||
The example also shows that a proc's body can consist of a single expression
|
||||
|
||||
14
doc/tut2.txt
14
doc/tut2.txt
@@ -37,7 +37,7 @@ Object Oriented Programming
|
||||
While Nim's support for object oriented programming (OOP) is minimalistic,
|
||||
powerful OOP techniques can be used. OOP is seen as *one* way to design a
|
||||
program, not *the only* way. Often a procedural approach leads to simpler
|
||||
and more efficient code. In particular, prefering composition over inheritance
|
||||
and more efficient code. In particular, preferring composition over inheritance
|
||||
is often the better design.
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ An example:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
# This is an example how an abstract syntax tree could be modeled in Nim
|
||||
# This is an example how an abstract syntax tree could be modelled in Nim
|
||||
type
|
||||
NodeKind = enum # the different node types
|
||||
nkInt, # a leaf with an integer value
|
||||
@@ -335,7 +335,7 @@ As the example demonstrates, invocation of a multi-method cannot be ambiguous:
|
||||
Collide 2 is preferred over collide 1 because the resolution works from left to
|
||||
right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``.
|
||||
|
||||
**Perfomance note**: Nim does not produce a virtual method table, but
|
||||
**Performance note**: Nim does not produce a virtual method table, but
|
||||
generates dispatch trees. This avoids the expensive indirect branch for method
|
||||
calls and enables inlining. However, other optimizations like compile time
|
||||
evaluation or dead code elimination do not work with methods.
|
||||
@@ -735,14 +735,6 @@ regular expressions:
|
||||
return tkUnknown
|
||||
|
||||
|
||||
Term rewriting macros
|
||||
---------------------
|
||||
|
||||
Term rewriting macros can be used to enhance the compilation process
|
||||
with user defined optimizations; see this `document <trmacros.html>`_ for
|
||||
further information.
|
||||
|
||||
|
||||
Building your first macro
|
||||
-------------------------
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ just declared as a native method which will be resolved at runtime. The scripts
|
||||
nimbuild.sh and jnibuild.sh are in charge of building the Nim code and
|
||||
generating the jni bridge from the java code respectively. Finally, the
|
||||
ndk-build command from the android ndk tools has to be run to build the binary
|
||||
libary which will be installed along the final apk.
|
||||
library which will be installed along the final apk.
|
||||
|
||||
All these steps are wrapped in the ant build script through the customization
|
||||
of the -post-compile rule. If you have the android ndk tools installed and you
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
[self.bText resignFirstResponder];
|
||||
}
|
||||
|
||||
/** Custom loadView method for backwards compatiblity.
|
||||
/** Custom loadView method for backwards compatibility.
|
||||
* Unfortunately I've been unable to coerce Xcode 4.4 to generate nib files
|
||||
* which are compatible with my trusty iOS 3.0 ipod touch so in order to be
|
||||
* fully compatible for all devices we have to build the interface manually in
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Nimrod configuration file.
|
||||
# The file is used only to add the path of the backend to the compiler options.
|
||||
|
||||
path="../nimrod_backend"
|
||||
path="../nim_backend"
|
||||
@@ -21,7 +21,7 @@ type
|
||||
cmdParams, # Two valid parameters were provided
|
||||
cmdInteractive # No parameters were provided, run interactive mode
|
||||
|
||||
TParamConfig = object of TObject
|
||||
TParamConfig = object of RootObj
|
||||
action: TCommand # store the type of operation
|
||||
paramA, paramB: int # possibly store the valid parameters
|
||||
|
||||
@@ -63,7 +63,7 @@ proc parseCmdLine(): TParamConfig =
|
||||
stdout.write USAGE
|
||||
quit "Unexpected option: " & key, 2
|
||||
of cmdEnd: break
|
||||
except EInvalidValue:
|
||||
except ValueError:
|
||||
stdout.write USAGE
|
||||
quit "Invalid value " & val & " for parameter " & key, 3
|
||||
|
||||
@@ -85,7 +85,7 @@ proc parseUserInput(question: string): int =
|
||||
try:
|
||||
result = input.parseInt
|
||||
break
|
||||
except EInvalidValue:
|
||||
except ValueError:
|
||||
if input.len < 1: quit "Blank line detected, quitting.", 0
|
||||
echo "Sorry, `$1' doesn't seem to be a valid integer" % input
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
In this directory you will find the nimrod commandline version of the
|
||||
In this directory you will find the nim commandline version of the
|
||||
cross-calculator sample.
|
||||
|
||||
The commandline interface can be used non interactively through switches, or
|
||||
interactively when running the command without parameters.
|
||||
|
||||
Compilation is fairly easy despite having the source split in different
|
||||
directories. Thanks to the nimrod.cfg file, which adds the ../nimrod_backend
|
||||
directories. Thanks to the nim.cfg file, which adds the ../nim_backend
|
||||
directory as a search path, you can compile and run the example just fine from
|
||||
the command line with 'nimrod c -r nimcalculator.nim'.
|
||||
the command line with 'nim c -r nimcalculator.nim'.
|
||||
@@ -13,7 +13,7 @@ type
|
||||
text*: string ## Description of the task to do.
|
||||
priority*: int ## The priority can be any user defined integer.
|
||||
isDone*: bool ## Done todos are still kept marked.
|
||||
modificationDate: TTime ## The modification time can't be modified from
|
||||
modificationDate: Time ## The modification time can't be modified from
|
||||
## outside of this module, use the
|
||||
## getModificationDate accessor.
|
||||
|
||||
@@ -64,7 +64,7 @@ proc openDatabase*(path: string): TDbConn =
|
||||
# - Procs related to TTodo objects
|
||||
#
|
||||
proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
|
||||
modificationDate: TTime): TTodo =
|
||||
modificationDate: Time): TTodo =
|
||||
## Returns an initialized TTodo object created from database parameters.
|
||||
##
|
||||
## The proc assumes all values are right. Note this proc is NOT exported.
|
||||
@@ -81,7 +81,7 @@ proc getId*(todo: TTodo): int64 =
|
||||
return todo.id
|
||||
|
||||
|
||||
proc getModificationDate*(todo: TTodo): TTime =
|
||||
proc getModificationDate*(todo: TTodo): Time =
|
||||
## Returns the last modification date of a TTodo entry.
|
||||
return todo.modificationDate
|
||||
|
||||
@@ -91,7 +91,7 @@ proc update*(todo: var TTodo; conn: TDbConn): bool =
|
||||
##
|
||||
## Use this method if you (or another entity) have modified the database and
|
||||
## want to update the object you have with whatever the database has stored.
|
||||
## Returns true if the update suceeded, or false if the object was not found
|
||||
## Returns true if the update succeeded, or false if the object was not found
|
||||
## in the database any more, in which case you should probably get rid of the
|
||||
## TTodo object.
|
||||
assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
|
||||
@@ -99,14 +99,14 @@ proc update*(todo: var TTodo; conn: TDbConn): bool =
|
||||
FROM Todos WHERE id = ?"""
|
||||
|
||||
try:
|
||||
let rows = conn.GetAllRows(query, $todo.id)
|
||||
let rows = conn.getAllRows(query, $todo.id)
|
||||
if len(rows) < 1:
|
||||
return
|
||||
assert(1 == len(rows), "Woah, didn't expect so many rows")
|
||||
todo.text = rows[0][0]
|
||||
todo.priority = rows[0][1].parseInt
|
||||
todo.isDone = rows[0][2].parseBool
|
||||
todo.modificationDate = TTime(rows[0][3].parseInt)
|
||||
todo.modificationDate = Time(rows[0][3].parseInt)
|
||||
result = true
|
||||
except:
|
||||
echo("Something went wrong selecting for id " & $todo.id)
|
||||
@@ -202,12 +202,12 @@ proc getPagedTodos*(conn: TDbConn; params: TPagedParams;
|
||||
#echo("Query " & string(query))
|
||||
#echo("args: " & args.join(", "))
|
||||
|
||||
var newId: biggestInt
|
||||
var newId: BiggestInt
|
||||
for row in conn.fastRows(query, args):
|
||||
let numChars = row[0].parseBiggestInt(newId)
|
||||
assert(numChars > 0, "Huh, couldn't parse identifier from database?")
|
||||
result.add(initFromDB(int64(newId), row[1], row[2].parseInt,
|
||||
row[3].parseBool, TTime(row[4].parseInt)))
|
||||
row[3].parseBool, Time(row[4].parseInt)))
|
||||
|
||||
|
||||
proc getTodo*(conn: TDbConn; todoId: int64): ref TTodo =
|
||||
@@ -1,4 +1,4 @@
|
||||
This directory contains the nimrod backend code for the todo cross platform
|
||||
This directory contains the nim backend code for the todo cross platform
|
||||
example.
|
||||
|
||||
Unlike the cross platform calculator example, this backend features more code,
|
||||
@@ -8,7 +8,7 @@ The test is not embedded directly in the backend.nim file to avoid being able
|
||||
to access internal data types and procs not exported and replicate the
|
||||
environment of client code.
|
||||
|
||||
In a bigger project with several people you could run `nimrod doc backend.nim`
|
||||
In a bigger project with several people you could run `nim doc backend.nim`
|
||||
(or use the doc2 command for a whole project) and provide the generated html
|
||||
documentation to another programer for her to implement an interface without
|
||||
having to look at the source code.
|
||||
@@ -1,4 +1,4 @@
|
||||
# Nimrod configuration file.
|
||||
# The file is used only to add the path of the backend to the compiler options.
|
||||
|
||||
path="../nimrod_backend"
|
||||
path="../nim_backend"
|
||||
@@ -69,11 +69,11 @@ template parseTodoIdAndSetCommand(newCommand: TCommand): stmt =
|
||||
## Helper to parse a big todo identifier into todoId and set command.
|
||||
try:
|
||||
let numChars = val.parseBiggestInt(newId)
|
||||
if numChars < 1: raise newException(EInvalidValue, "Empty string?")
|
||||
if numChars < 1: raise newException(ValueError, "Empty string?")
|
||||
result.command = newCommand
|
||||
result.todoId = newId
|
||||
except EOverflow:
|
||||
raise newException(EInvalidValue, "Value $1 too big" % val)
|
||||
except OverflowError:
|
||||
raise newException(ValueError, "Value $1 too big" % val)
|
||||
|
||||
|
||||
template verifySingleCommand(actions: stmt): stmt =
|
||||
@@ -111,7 +111,7 @@ proc parseCmdLine(): TParamConfig =
|
||||
usesListParams = false
|
||||
p = initOptParser()
|
||||
key, val: TaintedString
|
||||
newId: biggestInt
|
||||
newId: BiggestInt
|
||||
|
||||
result.initDefaults
|
||||
|
||||
@@ -178,7 +178,7 @@ proc parseCmdLine(): TParamConfig =
|
||||
abort("Unexpected option '$1'." % [key], 6)
|
||||
of cmdEnd:
|
||||
break
|
||||
except EInvalidValue:
|
||||
except ValueError:
|
||||
abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7)
|
||||
|
||||
if not specifiedCommand:
|
||||
@@ -14,7 +14,7 @@ template optRe{re(x)}(x: string{lit}): Regex =
|
||||
g
|
||||
|
||||
template `=~`(s: string, pattern: Regex): bool =
|
||||
when not definedInScope(matches):
|
||||
when not declaredInScope(matches):
|
||||
var matches {.inject.}: array[maxSubPatterns, string]
|
||||
match(s, pattern, matches)
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user