Merge branch 'devel' into warning-for-result

This commit is contained in:
Simon Hafner 2015-03-05 14:44:54 -06:00
commit 70eaf92ff0
356 changed files with 6122 additions and 3809 deletions

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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, ~" ")

View file

@ -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)

View file

@ -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.}

View file

@ -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:

View file

@ -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

View file

@ -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)

View file

@ -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))

View file

@ -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

View file

@ -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")

View file

@ -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):

View file

@ -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``.

View file

@ -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
View 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)

View file

@ -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"

View file

@ -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

View file

@ -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(): ...

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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":

View file

@ -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)

View file

@ -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:

View file

@ -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:

View file

@ -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

View file

@ -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)

View file

@ -2,7 +2,7 @@
# gc:markAndSweep
hint[XDeclaredButNotUsed]:off
path:"$projectPath/../.."
path:"$projectPath/.."
path:"$lib/packages/docutils"
path:"$nim/compiler"

View file

@ -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()

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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: "/",

View file

@ -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)

View file

@ -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:"):

View file

@ -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)

View file

@ -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

View file

@ -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:

View file

@ -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:

View file

@ -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)

View file

@ -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,

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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])

View file

@ -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

View file

@ -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:

View file

@ -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,

View file

@ -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:

View file

@ -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:

View file

@ -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

View file

@ -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)

View file

@ -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:

View file

@ -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

View file

@ -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):

View file

@ -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])

View file

@ -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)

View file

@ -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

View file

@ -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))

View file

@ -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)

View file

@ -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)