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! # XXX put this into an include file to avoid this issue!
tyNone, tyBool, tyChar, tyNone, tyBool, tyChar,
tyEmpty, tyArrayConstr, tyNil, tyExpr, tyStmt, tyTypeDesc, 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 tyGenericBody, # ``T[a, b, body]`` last parameter is the body
tyGenericInst, # ``T[a, b, realInstance]`` instantiated generic type tyGenericInst, # ``T[a, b, realInstance]`` instantiated generic type
# realInstance will be a concrete type like tyObject # realInstance will be a concrete type like tyObject
@ -377,7 +377,7 @@ type
tyFromExpr #\ tyFromExpr #\
# This is a type representing an expression that depends # 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 # It will be converted to a real type only during generic
# instantiation and prior to this it has the potential to # instantiation and prior to this it has the potential to
# be any type. # be any type.
@ -459,7 +459,7 @@ type
tfNeedsInit, # type constains a "not nil" constraint somewhere or some tfNeedsInit, # type constains a "not nil" constraint somewhere or some
# other type so that it requires inititalization # 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 tfHasMeta, # type contains "wildcard" sub-types such as generic params
# or other type classes # or other type classes
tfHasGCedMem, # type contains GC'ed memory tfHasGCedMem, # type contains GC'ed memory
@ -522,7 +522,7 @@ const
skError* = skUnknown skError* = skUnknown
# type flags that are essential for type equality: # type flags that are essential for type equality:
eqTypeFlags* = {tfIterator, tfShared, tfNotNil} eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr}
type type
TMagic* = enum # symbols that require compiler magic: TMagic* = enum # symbols that require compiler magic:
@ -655,7 +655,6 @@ type
locGlobalVar, # location is a global variable locGlobalVar, # location is a global variable
locParam, # location is a parameter locParam, # location is a parameter
locField, # location is a record field locField, # location is a record field
locArrayElem, # location is an array element
locExpr, # "location" is really an expression locExpr, # "location" is really an expression
locProc, # location is a proc (an address of a procedure) locProc, # location is a proc (an address of a procedure)
locData, # location is a constant locData, # location is a constant
@ -669,14 +668,15 @@ type
lfDynamicLib, # link symbol to dynamic library lfDynamicLib, # link symbol to dynamic library
lfExportLib, # export symbol for dynamic library generation lfExportLib, # export symbol for dynamic library generation
lfHeader, # include header file for symbol 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 TStorageLoc* = enum
OnUnknown, # location is unknown (stack, heap or static) OnUnknown, # location is unknown (stack, heap or static)
OnStack, # location is on hardware stack OnStack, # location is on hardware stack
OnHeap # location is on heap or global OnHeap # location is on heap or global
# (reference counting needed) # (reference counting needed)
TLocFlags* = set[TLocFlag] TLocFlags* = set[TLocFlag]
TLoc*{.final.} = object TLoc* = object
k*: TLocKind # kind of location k*: TLocKind # kind of location
s*: TStorageLoc s*: TStorageLoc
flags*: TLocFlags # location's flags flags*: TLocFlags # location's flags
@ -859,7 +859,7 @@ const
OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator, OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator,
skConverter, skModule, skTemplate, skMacro} skConverter, skModule, skTemplate, skMacro}
GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody, GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
tyGenericParam} tyGenericParam}
StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray, StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray,
@ -918,50 +918,6 @@ const
# only used when 'gCmd == cmdPretty': Indicates that the symbol has been # only used when 'gCmd == cmdPretty': Indicates that the symbol has been
# imported via 'importc: "fullname"' and no format string. # 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 = proc isCallExpr*(n: PNode): bool =
result = n.kind in nkCallKinds result = n.kind in nkCallKinds
@ -989,6 +945,60 @@ template `{}`*(n: PNode, i: int): expr = n[i -| n]
template `{}=`*(n: PNode, i: int, s: PNode): stmt = template `{}=`*(n: PNode, i: int, s: PNode): stmt =
n.sons[i -| n] = s 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) var emptyNode* = newNode(nkEmpty)
# There is a single empty node that is shared! Do not overwrite it! # 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 GrowthFactor* = 2 # must be power of 2, > 0
StartSize* = 8 # 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 dest.counter = src.counter
if isNil(src.data): return if isNil(src.data): return
setLen(dest.data, len(src.data)) setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] 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 dest.counter = src.counter
if isNil(src.data): return if isNil(src.data): return
newSeq(dest.data, len(src.data)) newSeq(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] 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 dest.counter = src.counter
if isNil(src.data): return if isNil(src.data): return
setLen(dest.data, len(src.data)) setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] 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 dest.counter = src.counter
if isNil(src.data): return if isNil(src.data): return
setLen(dest.data, len(src.data)) setLen(dest.data, len(src.data))
for i in countup(0, high(src.data)): dest.data[i] = src.data[i] 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 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 = proc withInfo*(n: PNode, info: TLineInfo): PNode =
n.info = info n.info = info
return n return n
proc newIdentNode(ident: PIdent, info: TLineInfo): PNode = proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode =
result = newNode(nkIdent) result = newNode(nkIdent)
result.ident = ident result.ident = ident
result.info = info result.info = info
proc newSymNode(sym: PSym): PNode = proc newSymNode*(sym: PSym): PNode =
result = newNode(nkSym) result = newNode(nkSym)
result.sym = sym result.sym = sym
result.typ = sym.typ result.typ = sym.typ
@ -1116,7 +1089,7 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode =
result.typ = sym.typ result.typ = sym.typ
result.info = info result.info = info
proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode = proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode =
new(result) new(result)
result.kind = kind result.kind = kind
result.info = info result.info = info
@ -1155,11 +1128,16 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[],
writeStackTrace() writeStackTrace()
inc gNodeId inc gNodeId
proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result = newNode(kind) result = newNode(kind)
result.info = info result.info = info
result.typ = typ 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) var emptyParams = newNode(nkFormalParams)
emptyParams.addSon(emptyNode) emptyParams.addSon(emptyNode)
@ -1181,7 +1159,7 @@ proc `$`*(x: TLockLevel): string =
elif x.ord == UnknownLockLevel.ord: result = "<unknown>" elif x.ord == UnknownLockLevel.ord: result = "<unknown>"
else: result = $int16(x) else: result = $int16(x)
proc newType(kind: TTypeKind, owner: PSym): PType = proc newType*(kind: TTypeKind, owner: PSym): PType =
new(result) new(result)
result.kind = kind result.kind = kind
result.owner = owner result.owner = owner
@ -1202,7 +1180,37 @@ proc mergeLoc(a: var TLoc, b: TLoc) =
if a.r == nil: a.r = b.r if a.r == nil: a.r = b.r
#if a.a == 0: a.a = b.a #if a.a == 0: a.a = b.a
proc assignType(dest, src: PType) = proc 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 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.kind = src.kind
dest.flags = src.flags dest.flags = src.flags
dest.callConv = src.callConv dest.callConv = src.callConv
@ -1223,7 +1231,7 @@ proc assignType(dest, src: PType) =
newSons(dest, sonsLen(src)) newSons(dest, sonsLen(src))
for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i] 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) result = newType(t.kind, owner)
assignType(result, t) assignType(result, t)
if keepId: if keepId:
@ -1232,7 +1240,7 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType =
when debugIds: registerId(result) when debugIds: registerId(result)
result.sym = t.sym # backend-info should not be copied 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 = newSym(s.kind, s.name, s.owner, s.info)
#result.ast = nil # BUGFIX; was: s.ast which made problems #result.ast = nil # BUGFIX; was: s.ast which made problems
result.typ = s.typ 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! # XXX once usedGenerics is used, ensure module aliases keep working!
assert s.usedGenerics == nil assert s.usedGenerics == nil
proc newSym(symKind: TSymKind, name: PIdent, owner: PSym, proc initStrTable*(x: var TStrTable) =
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) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
@ -1294,46 +1285,28 @@ proc initTable(x: var TTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
proc initIdTable(x: var TIdTable) = proc initIdTable*(x: var TIdTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) 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 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
proc initIdNodeTable(x: var TIdNodeTable) = proc initIdNodeTable*(x: var TIdNodeTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) newSeq(x.data, StartSize)
proc initNodeTable(x: var TNodeTable) = proc initNodeTable*(x: var TNodeTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) 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 = proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
## Used throughout the compiler code to test whether a type tree contains or ## 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 ## 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) = proc propagateToOwner*(owner, elem: PType) =
const HaveTheirOwnEmpty = {tySequence, tySet} 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 tfNotNil in elem.flags:
if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}: if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}:
owner.flags.incl tfNotNil owner.flags.incl tfNotNil
elif owner.kind notin HaveTheirOwnEmpty: elif owner.kind notin HaveTheirOwnEmpty:
owner.flags.incl tfNeedsInit owner.flags.incl tfNeedsInit
@ -1359,9 +1332,6 @@ proc propagateToOwner*(owner, elem: PType) =
if owner.kind in HaveTheirOwnEmpty: discard if owner.kind in HaveTheirOwnEmpty: discard
else: owner.flags.incl tfNeedsInit else: owner.flags.incl tfNeedsInit
if tfShared in elem.flags:
owner.flags.incl tfHasShared
if elem.isMetaType: if elem.isMetaType:
owner.flags.incl tfHasMeta owner.flags.incl tfHasMeta
@ -1374,22 +1344,17 @@ proc rawAddSon*(father, son: PType) =
add(father.sons, son) add(father.sons, son)
if not son.isNil: propagateToOwner(father, 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) = proc addSonNilAllowed*(father, son: PNode) =
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
add(father.sons, son) add(father.sons, son)
proc delSon(father: PNode, idx: int) = proc delSon*(father: PNode, idx: int) =
if isNil(father.sons): return if isNil(father.sons): return
var length = sonsLen(father) var length = sonsLen(father)
for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1] for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1]
setLen(father.sons, length - 1) setLen(father.sons, length - 1)
proc copyNode(src: PNode): PNode = proc copyNode*(src: PNode): PNode =
# does not copy its sons! # does not copy its sons!
if src == nil: if src == nil:
return nil return nil
@ -1426,7 +1391,7 @@ proc shallowCopy*(src: PNode): PNode =
of nkStrLit..nkTripleStrLit: result.strVal = src.strVal of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
else: newSeq(result.sons, sonsLen(src)) else: newSeq(result.sons, sonsLen(src))
proc copyTree(src: PNode): PNode = proc copyTree*(src: PNode): PNode =
# copy a whole syntax tree; performs deep copying # copy a whole syntax tree; performs deep copying
if src == nil: if src == nil:
return nil return nil
@ -1448,13 +1413,7 @@ proc copyTree(src: PNode): PNode =
for i in countup(0, sonsLen(src) - 1): for i in countup(0, sonsLen(src) - 1):
result.sons[i] = copyTree(src.sons[i]) result.sons[i] = copyTree(src.sons[i])
proc lastSon(n: PNode): PNode = proc hasSonWith*(n: PNode, kind: TNodeKind): bool =
result = n.sons[sonsLen(n) - 1]
proc lastSon(n: PType): PType =
result = n.sons[sonsLen(n) - 1]
proc hasSonWith(n: PNode, kind: TNodeKind): bool =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind == kind: if n.sons[i].kind == kind:
return true return true
@ -1476,7 +1435,7 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if n.kind in kinds or containsNode(n.sons[i], kinds): return true 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 case n.kind
of nkEmpty..nkNilLit: result = n.kind == kind of nkEmpty..nkNilLit: result = n.kind == kind
else: else:

View file

@ -130,8 +130,8 @@ proc skipConvAndClosure*(n: PNode): PNode =
proc sameValue*(a, b: PNode): bool = proc sameValue*(a, b: PNode): bool =
result = false result = false
case a.kind case a.kind
of nkCharLit..nkInt64Lit: of nkCharLit..nkUInt64Lit:
if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat64Lit:
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
@ -145,8 +145,8 @@ proc leValue*(a, b: PNode): bool =
# a <= b? # a <= b?
result = false result = false
case a.kind case a.kind
of nkCharLit..nkInt64Lit: of nkCharLit..nkUInt32Lit:
if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat64Lit:
if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
@ -387,6 +387,9 @@ proc debugType(n: PType, maxRecDepth=100): PRope =
if n.sym != nil: if n.sym != nil:
app(result, " ") app(result, " ")
app(result, n.sym.name.s) 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: if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0:
app(result, "(") app(result, "(")
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
@ -445,21 +448,21 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int;
proc debug(n: PSym) = proc debug(n: PSym) =
if n == nil: if n == nil:
writeln(stdout, "null") msgWriteln("null")
elif n.kind == skUnknown: elif n.kind == skUnknown:
writeln(stdout, "skUnknown") msgWriteln("skUnknown")
else: else:
#writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) #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, n.name.s, $n.id, flagsToStr(n.flags).ropeToStr,
flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr, flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr,
$n.kind]) $n.kind])
proc debug(n: PType) = proc debug(n: PType) =
writeln(stdout, ropeToStr(debugType(n))) msgWriteln(ropeToStr(debugType(n)))
proc debug(n: PNode) = proc debug(n: PNode) =
writeln(stdout, ropeToStr(debugTree(n, 0, 100))) msgWriteln(ropeToStr(debugTree(n, 0, 100)))
const const
EmptySeq = @[] EmptySeq = @[]
@ -678,9 +681,8 @@ proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym =
else: result = nextIdentIter(ti, tab) else: result = nextIdentIter(ti, tab)
proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
var h, start: THash var h = ti.h and high(tab.data)
h = ti.h and high(tab.data) var start = h
start = h
result = tab.data[h] result = tab.data[h]
while result != nil: while result != nil:
if result.name.id == ti.name.id: break 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) c.hashSym(t.sym)
case t.kind case t.kind
of tyGenericBody, tyGenericInst, tyGenericInvokation: of tyGenericBody, tyGenericInst, tyGenericInvocation:
for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)): for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)):
c.hashType t.sons[i] c.hashType t.sons[i]
of tyUserTypeClass: of tyUserTypeClass:
internalAssert t.sym != nil and t.sym.owner != nil 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 genAssignment(p, d, tmp, {}) # no need for deep copying
else: else:
app(pl, ~")") app(pl, ~")")
if d.k == locNone: getTemp(p, typ.sons[0], d) if p.module.compileToCpp and lfSingleUse in d.flags:
assert(d.t != nil) # generate an assignment to d: # do not generate spurious temporaries for C++! For C we're better off
var list: TLoc # with them to prevent undefined behaviour and because the codegen
initLoc(list, locCall, d.t, OnUnknown) # is free to emit expressions multiple times!
list.r = pl d.k = locCall
genAssignment(p, d, list, {}) # no need for deep copying 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: else:
app(pl, ~");$n") app(pl, ~");$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
@ -90,7 +98,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
of tyOpenArray, tyVarargs, tyArray, tyArrayConstr: of tyOpenArray, tyVarargs, tyArray, tyArrayConstr:
"($1)+($2), ($3)-($2)+1" "($1)+($2), ($3)-($2)+1"
of tyString, tySequence: 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" "(*$1)->data+($2), ($3)-($2)+1"
else: else:
"$1->data+($2), ($3)-($2)+1" "$1->data+($2), ($3)-($2)+1"
@ -102,7 +111,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope =
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
result = ropef("$1, $1Len0", [rdLoc(a)]) result = ropef("$1, $1Len0", [rdLoc(a)])
of tyString, tySequence: of tyString, tySequence:
if skipTypes(n.typ, abstractInst).kind == tyVar: if skipTypes(n.typ, abstractInst).kind == tyVar and
not compileToCpp(p.module):
result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)]) result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)])
else: else:
result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)]) result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)])
@ -115,7 +125,7 @@ proc genArgStringToCString(p: BProc, n: PNode): PRope {.inline.} =
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
result = ropef("$1->data", [a.rdLoc]) 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 var a: TLoc
if n.kind == nkStringToCString: if n.kind == nkStringToCString:
result = genArgStringToCString(p, n) result = genArgStringToCString(p, n)
@ -125,8 +135,20 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope =
elif ccgIntroducedPtr(param): elif ccgIntroducedPtr(param):
initLocExpr(p, n, a) initLocExpr(p, n, a)
result = addrLoc(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: else:
initLocExpr(p, n, a) initLocExprSingleUse(p, n, a)
result = rdLoc(a) result = rdLoc(a)
proc genArgNoParam(p: BProc, n: PNode): PRope = proc genArgNoParam(p: BProc, n: PNode): PRope =
@ -134,7 +156,7 @@ proc genArgNoParam(p: BProc, n: PNode): PRope =
if n.kind == nkStringToCString: if n.kind == nkStringToCString:
result = genArgStringToCString(p, n) result = genArgStringToCString(p, n)
else: else:
initLocExpr(p, n, a) initLocExprSingleUse(p, n, a)
result = rdLoc(a) result = rdLoc(a)
proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = 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 params != nil: app(params, ~", ")
if i < sonsLen(typ): if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym) 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: else:
app(params, genArgNoParam(p, ri.sons[i])) app(params, genArgNoParam(p, ri.sons[i]))
fixupCall(p, le, ri, d, op.r, params) 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)) assert(sonsLen(typ) == sonsLen(typ.n))
if i < sonsLen(typ): if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym) 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: else:
app(pl, genArgNoParam(p, ri.sons[i])) app(pl, genArgNoParam(p, ri.sons[i]))
if i < length - 1: app(pl, ~", ") 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) assert(typ.n.sons[i].kind == nkSym)
# if the parameter is lying (tyVar) and thus we required an additional deref, # if the parameter is lying (tyVar) and thus we required an additional deref,
# skip the deref: # skip the deref:
var ri = ri[i]
while ri.kind == nkObjDownConv: ri = ri[0]
if typ.sons[i].kind == tyVar: if typ.sons[i].kind == tyVar:
let x = if ri[i].kind == nkHiddenAddr: ri[i][0] else: ri[i] let x = if ri.kind == nkHiddenAddr: ri[0] else: ri
if x.kind in {nkHiddenDeref, nkDerefExpr}: if x.typ.kind == tyPtr:
result = genArgNoParam(p, x[0])
result.app("->")
elif x.typ.kind in {tyVar, tyPtr}:
result = genArgNoParam(p, x) result = genArgNoParam(p, x)
result.app("->") result.app("->")
elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr:
result = genArgNoParam(p, x[0])
result.app("->")
else: else:
result = genArgNoParam(p, x) result = genArgNoParam(p, x)
result.app(".") result.app(".")
elif typ.sons[i].kind == tyPtr: elif typ.sons[i].kind == tyPtr:
if ri.sons[i].kind in {nkAddr, nkHiddenAddr}: if ri.kind in {nkAddr, nkHiddenAddr}:
result = genArgNoParam(p, ri.sons[i][0]) result = genArgNoParam(p, ri[0])
result.app(".") result.app(".")
else: else:
result = genArgNoParam(p, ri.sons[i]) result = genArgNoParam(p, ri)
result.app("->") result.app("->")
else: else:
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) result = genArgNoParam(p, ri) #, typ.n.sons[i].sym)
result.app(".") result.app(".")
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope = 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: # simpler version of 'fixupCall' that works with the pl+params combination:
var typ = skipTypes(ri.sons[0].typ, abstractInst) var typ = skipTypes(ri.sons[0].typ, abstractInst)
if typ.sons[0] != nil: if typ.sons[0] != nil:
if d.k == locNone: getTemp(p, typ.sons[0], d) if p.module.compileToCpp and lfSingleUse in d.flags:
assert(d.t != nil) # generate an assignment to d: # do not generate spurious temporaries for C++! For C we're better off
var list: TLoc # with them to prevent undefined behaviour and because the codegen
initLoc(list, locCall, d.t, OnUnknown) # is free to emit expressions multiple times!
list.r = pl d.k = locCall
genAssignment(p, d, list, {}) # no need for deep copying 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: else:
app(pl, ~";$n") app(pl, ~";$n")
line(p, cpsStmts, pl) line(p, cpsStmts, pl)
@ -399,14 +431,26 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
var length = sonsLen(ri) var length = sonsLen(ri)
assert(sonsLen(typ) == sonsLen(typ.n)) assert(sonsLen(typ) == sonsLen(typ.n))
if length > 1: # don't call 'ropeToStr' here for efficiency:
app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym)) let pat = ri.sons[0].sym.loc.r.data
app(pl, ~" ") internalAssert pat != nil
app(pl, op.r) var start = 3
if length > 2: if ' ' in pat:
app(pl, ~": ") start = 1
app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym)) app(pl, op.r)
for i in countup(3, length-1): 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)) assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ): if i >= sonsLen(typ):
internalError(ri.info, "varargs for objective C method?") 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, ~" ")
app(pl, param.name.s) app(pl, param.name.s)
app(pl, ~": ") 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 typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]): if isInvalidReturnType(typ.sons[0]):
if sonsLen(ri) > 1: app(pl, ~" ") 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 case skipTypes(ty, abstractVarRange).kind
of tyChar, tyNil: of tyChar, tyNil:
result = intLiteral(n.intVal) 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: of tyBool:
if n.intVal != 0: result = ~"NIM_TRUE" if n.intVal != 0: result = ~"NIM_TRUE"
else: result = ~"NIM_FALSE" else: result = ~"NIM_FALSE"
@ -83,7 +78,9 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope =
else: else:
result = toRope("NIM_NIL") result = toRope("NIM_NIL")
of nkStrLit..nkTripleStrLit: 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) var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
if id == gBackendId: if id == gBackendId:
# string literal not found in the cache: # string literal not found in the cache:
@ -662,9 +659,14 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8), ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
getSimpleTypeDesc(p.module, e.typ)])) getSimpleTypeDesc(p.module, e.typ)]))
proc 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) = proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
let mt = mapType(e.sons[0].typ) 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 # XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then? # simply wrap them in a struct? --> Losing auto vectorization then?
#if e[0].kind != nkBracketExpr: #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) expr(p, e.sons[0], d)
else: else:
var a: TLoc var a: TLoc
initLocExpr(p, e.sons[0], a) initLocExprSingleUse(p, e.sons[0], a)
case skipTypes(a.t, abstractInst).kind let typ = skipTypes(a.t, abstractInst)
case typ.kind
of tyRef: of tyRef:
d.s = OnHeap d.s = OnHeap
of tyVar: of tyVar:
d.s = OnUnknown 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: of tyPtr:
d.s = OnUnknown # BUGFIX! d.s = OnUnknown # BUGFIX!
else: internalError(e.info, "genDeref " & $a.t.kind) else: internalError(e.info, "genDeref " & $a.t.kind)
@ -698,7 +705,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[0], a) initLocExpr(p, e.sons[0], a)
putIntoDest(p, d, e.typ, con("&", a.r)) putIntoDest(p, d, e.typ, con("&", a.r))
#Message(e.info, warnUser, "HERE NEW &") #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) expr(p, e.sons[0], d)
else: else:
var a: TLoc var a: TLoc
@ -916,6 +923,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
L: TLabel L: TLabel
tmp: TLoc tmp: TLoc
getTemp(p, e.typ, tmp) # force it into a temp! getTemp(p, e.typ, tmp) # force it into a temp!
inc p.splitDecls
expr(p, e.sons[1], tmp) expr(p, e.sons[1], tmp)
L = getLabel(p) L = getLabel(p)
if m == mOr: if m == mOr:
@ -928,6 +936,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
d = tmp d = tmp
else: else:
genAssignment(p, d, tmp, {}) # no need for deep copying genAssignment(p, d, tmp, {}) # no need for deep copying
dec p.splitDecls
proc genEcho(p: BProc, n: PNode) = proc genEcho(p: BProc, n: PNode) =
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)`` # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
@ -938,7 +947,7 @@ proc genEcho(p: BProc, n: PNode) =
var a: TLoc var a: TLoc
for i in countup(0, n.len-1): for i in countup(0, n.len-1):
initLocExpr(p, n.sons[i], a) initLocExpr(p, n.sons[i], a)
appf(args, ", ($1)->data", [rdLoc(a)]) appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)])
linefmt(p, cpsStmts, "printf($1$2);$n", linefmt(p, cpsStmts, "printf($1$2);$n",
makeCString(repeatStr(n.len, "%s") & tnl), args) makeCString(repeatStr(n.len, "%s") & tnl), args)
@ -1236,7 +1245,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
var t = skipTypes(a.t, abstractInst) var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyPtr, tyRef}: while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r 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) t = skipTypes(t.lastSon, typedescInst)
if not p.module.compileToCpp: if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil: while t.kind == tyObject and t.sons[0] != nil:
@ -1375,7 +1385,7 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) =
genAssignment(p, b, tmp, {}) genAssignment(p, b, tmp, {})
proc rdSetElemLoc(a: TLoc, setType: PType): PRope = 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 # before the set operation
result = rdCharLoc(a) result = rdCharLoc(a)
assert(setType.kind == tySet) assert(setType.kind == tySet)
@ -1863,7 +1873,8 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
var t = skipTypes(a.t, abstractInst) var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyPtr, tyRef}: while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r 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) t = skipTypes(t.lastSon, abstractInst)
if not p.module.compileToCpp: if not p.module.compileToCpp:
while t.kind == tyObject and t.sons[0] != nil: while t.kind == tyObject and t.sons[0] != nil:
@ -2073,8 +2084,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
genAsgn(p, n, fastAsgn=p.prc != nil) genAsgn(p, n, fastAsgn=p.prc != nil)
of nkDiscardStmt: of nkDiscardStmt:
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
var a: TLoc
genLineDir(p, n) genLineDir(p, n)
var a: TLoc
initLocExpr(p, n.sons[0], a) initLocExpr(p, n.sons[0], a)
of nkAsmStmt: genAsmStmt(p, n) of nkAsmStmt: genAsmStmt(p, n)
of nkTryStmt: of nkTryStmt:
@ -2092,16 +2103,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkPragma: genPragma(p, n) of nkPragma: genPragma(p, n)
of nkPragmaBlock: expr(p, n.lastSon, d) of nkPragmaBlock: expr(p, n.lastSon, d)
of nkProcDef, nkMethodDef, nkConverterDef: of nkProcDef, nkMethodDef, nkConverterDef:
if (n.sons[genericParamsPos].kind == nkEmpty): if n.sons[genericParamsPos].kind == nkEmpty:
var prc = n.sons[namePos].sym var prc = n.sons[namePos].sym
# due to a bug/limitation in the lambda lifting, unused inner procs # due to a bug/limitation in the lambda lifting, unused inner procs
# are not transformed correctly. We work around this issue (#411) here # are not transformed correctly. We work around this issue (#411) here
# by ensuring it's no inner proc (owner is a module): # by ensuring it's no inner proc (owner is a module):
# if prc.skipGenericOwner.kind == skModule:
# 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 (optDeadCodeElim notin gGlobalOptions and if (optDeadCodeElim notin gGlobalOptions and
sfDeadCodeElim notin getModule(prc).flags) or sfDeadCodeElim notin getModule(prc).flags) or
({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or
@ -2159,7 +2166,7 @@ proc genConstExpr(p: BProc, n: PNode): PRope =
var cs: TBitSet var cs: TBitSet
toBitSet(n, cs) toBitSet(n, cs)
result = genRawSetData(cs, int(getSize(n.typ))) result = genRawSetData(cs, int(getSize(n.typ)))
of nkBracket, nkPar, nkClosure: of nkBracket, nkPar, nkClosure, nkObjConstr:
var t = skipTypes(n.typ, abstractInst) var t = skipTypes(n.typ, abstractInst)
if t.kind == tySequence: if t.kind == tySequence:
result = genConstSeq(p, n, t) 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 "typeInfo": readIntSet(L, m.typeInfoMarker)
of "labels": m.labels = decodeVInt(L.buf, L.bufpos) of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0 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): when not defined(nimhygiene):
{.pragma: inject.} {.pragma: inject.}

View file

@ -48,7 +48,7 @@ proc genVarTuple(p: BProc, n: PNode) =
return return
genLineDir(p, n) genLineDir(p, n)
initLocExpr(p, n.sons[L-1], tup) initLocExpr(p, n.sons[L-1], tup)
var t = tup.t var t = tup.t.getUniqueType
for i in countup(0, L-3): for i in countup(0, L-3):
var v = n.sons[i].sym var v = n.sons[i].sym
if sfCompileTime in v.flags: continue if sfCompileTime in v.flags: continue
@ -202,8 +202,20 @@ proc genSingleVar(p: BProc, a: PNode) =
genVarPrototypeAux(generatedHeader, v) genVarPrototypeAux(generatedHeader, v)
registerGcRoot(p, v) registerGcRoot(p, v)
else: 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) assignLocalVar(p, v)
initLocalVar(p, v, isAssignedImmediately(a.sons[2])) initLocalVar(p, v, imm)
if a.sons[2].kind != nkEmpty: if a.sons[2].kind != nkEmpty:
genLineDir(targetProc, a) genLineDir(targetProc, a)
@ -242,15 +254,6 @@ proc genConstStmt(p: BProc, t: PNode) =
elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and
c.ast.len != 0: c.ast.len != 0:
if not emitLazily(c): requestConstImpl(p, c) 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) = proc genIf(p: BProc, n: PNode, d: var TLoc) =
# #
@ -275,17 +278,22 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
let it = n.sons[i] let it = n.sons[i]
if it.len == 2: if it.len == 2:
when newScopeForIf: startBlock(p) when newScopeForIf: startBlock(p)
initLocExpr(p, it.sons[0], a) initLocExprSingleUse(p, it.sons[0], a)
lelse = getLabel(p) lelse = getLabel(p)
inc(p.labels) inc(p.labels)
lineFF(p, cpsStmts, "if (!$1) goto $2;$n", lineF(p, cpsStmts, "if (!$1) goto $2;$n",
"br i1 $1, label %LOC$3, label %$2$nLOC$3: $n", [rdLoc(a), lelse])
[rdLoc(a), lelse, toRope(p.labels)])
when not newScopeForIf: startBlock(p) 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) endBlock(p)
if sonsLen(n) > 1: 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) fixLabel(p, lelse)
elif it.len == 1: elif it.len == 1:
startBlock(p) startBlock(p)
@ -344,7 +352,7 @@ proc genReturnStmt(p: BProc, t: PNode) =
# consume it before we return. # consume it before we return.
var safePoint = p.finallySafePoints[p.finallySafePoints.len-1] var safePoint = p.finallySafePoints[p.finallySafePoints.len-1]
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint) 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) = proc genComputedGoto(p: BProc; n: PNode) =
# first pass: Generate array of computed labels: # first pass: Generate array of computed labels:

View file

@ -28,16 +28,6 @@ proc isKeyword(w: PIdent): bool =
proc mangleName(s: PSym): PRope = proc mangleName(s: PSym): PRope =
result = s.loc.r result = s.loc.r
if result == nil: 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")
when oKeepVariableNames: when oKeepVariableNames:
let keepOrigName = s.kind in skLocalVars - {skForVar} and let keepOrigName = s.kind in skLocalVars - {skForVar} and
{sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and
@ -103,13 +93,11 @@ proc typeName(typ: PType): PRope =
else: ~"TY" else: ~"TY"
proc getTypeName(typ: PType): PRope = proc getTypeName(typ: PType): PRope =
if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}:
(gCmd != cmdCompileToLLVM):
result = typ.sym.loc.r result = typ.sym.loc.r
else: else:
if typ.loc.r == nil: if typ.loc.r == nil:
typ.loc.r = if gCmd != cmdCompileToLLVM: con(typ.typeName, typ.id.toRope) typ.loc.r = con(typ.typeName, typ.id.toRope)
else: con([~"%", typ.typeName, typ.id.toRope])
result = typ.loc.r result = typ.loc.r
if result == nil: internalError("getTypeName: " & $typ.kind) if result == nil: internalError("getTypeName: " & $typ.kind)
@ -162,6 +150,12 @@ proc mapReturnType(typ: PType): TCTypeKind =
if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
else: result = mapType(typ) else: result = mapType(typ)
proc 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 getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope
proc needsComplexAssignment(typ: PType): bool = proc needsComplexAssignment(typ: PType): bool =
result = containsGarbageCollectedRef(typ) result = containsGarbageCollectedRef(typ)
@ -183,6 +177,7 @@ proc isInvalidReturnType(rettype: PType): bool =
{tyVar, tyRef, tyPtr}) {tyVar, tyRef, tyPtr})
of ctStruct: of ctStruct:
let t = skipTypes(rettype, typedescInst) let t = skipTypes(rettype, typedescInst)
if rettype.isImportedCppType or t.isImportedCppType: return false
result = needsComplexAssignment(t) or result = needsComplexAssignment(t) or
(t.kind == tyObject and not isObjLackingTypeField(t)) (t.kind == tyObject and not isObjLackingTypeField(t))
else: result = false else: result = false
@ -193,9 +188,6 @@ const
"N_SYSCALL", # this is probably not correct for all platforms, "N_SYSCALL", # this is probably not correct for all platforms,
# but one can #define it to what one wants # but one can #define it to what one wants
"N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"] "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 = proc cacheGetType(tab: TIdTable, key: PType): PRope =
# returns nil if we need to declare this type # returns nil if we need to declare this type
@ -234,77 +226,8 @@ proc fillResult(param: PSym) =
incl(param.loc.flags, lfIndirect) incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown param.loc.s = OnUnknown
proc getParamTypeDesc(m: BModule, t: PType, check: var 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 = 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) result = getTypeName(t)
else: else:
result = toRope(literal) result = toRope(literal)
@ -342,6 +265,9 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope =
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
else: result = nil else: result = nil
proc pushType(m: BModule, typ: PType) =
add(m.typeStack, typ)
proc getTypePre(m: BModule, typ: PType): PRope = proc getTypePre(m: BModule, typ: PType): PRope =
if typ == nil: result = toRope("void") if typ == nil: result = toRope("void")
else: else:
@ -369,6 +295,81 @@ proc getTypeForward(m: BModule, typ: PType): PRope =
idTablePut(m.forwTypeCache, typ, result) idTablePut(m.forwTypeCache, typ, result)
else: internalError("getTypeForward(" & $typ.kind & ')') 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 = proc mangleRecFieldName(field: PSym, rectype: PType): PRope =
if (rectype.sym != nil) and if (rectype.sym != nil) and
({sfImportc, sfExportc} * rectype.sym.flags != {}): ({sfImportc, sfExportc} * rectype.sym.flags != {}):
@ -421,14 +422,18 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname]) if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname])
else: ae = sname else: ae = sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown) fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
let fieldType = field.loc.t.skipTypes(abstractInst) # for importcpp'ed objects, we only need to set field.loc, but don't
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: # have to recurse via 'getTypeDescAux'. And not doing so prevents problems
appf(result, "$1 $2[SEQ_DECL_SIZE];$n", # with heavily templatized C++ code:
[getTypeDescAux(m, fieldType.elemType, check), sname]) if not isImportedCppType(rectype):
else: let fieldType = field.loc.t.skipTypes(abstractInst)
# don't use fieldType here because we need the if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
# tyGenericInst for C++ template support appf(result, "$1 $2[SEQ_DECL_SIZE];$n",
appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) [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()") else: internalError(n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = 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) else: app(result, desc)
app(result, "};" & tnl) app(result, "};" & tnl)
proc pushType(m: BModule, typ: PType) =
add(m.typeStack, typ)
proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
# returns only the type's name # returns only the type's name
var t = getUniqueType(typ) var t = getUniqueType(typ)
@ -494,12 +496,15 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope =
result = getTypePre(m, t) result = getTypePre(m, t)
if result != nil: return 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)) internalError("cannot generate C type for: " & typeToString(typ))
# XXX: this BUG is hard to fix -> we need to introduce helper structs, # 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 # 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. # C type generation into an analysis and a code generation phase somehow.
case t.kind 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 et = t.lastSon
var etB = et.skipTypes(abstractInst) var etB = et.skipTypes(abstractInst)
if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: 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` # ``var set[char]`` in `getParamTypeDesc`
et = elemType(etB) et = elemType(etB)
etB = et.skipTypes(abstractInst) etB = et.skipTypes(abstractInst)
star[0] = '*'
case etB.kind case etB.kind
of tyObject, tyTuple: of tyObject, tyTuple:
if isImportedCppType(etB) and et.kind == tyGenericInst: if isImportedCppType(etB) and et.kind == tyGenericInst:
result = con(getTypeDescAux(m, et, check), "*") result = con(getTypeDescAux(m, et, check), star)
else: else:
# no restriction! We have a forward declaration for structs # no restriction! We have a forward declaration for structs
let x = getUniqueType(etB) let x = getUniqueType(etB)
let name = getTypeForward(m, x) let name = getTypeForward(m, x)
result = con(name, "*") result = con(name, star)
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
pushType(m, x) pushType(m, x)
of tySequence: of tySequence:
# no restriction! We have a forward declaration for structs # no restriction! We have a forward declaration for structs
let x = getUniqueType(etB) let x = getUniqueType(etB)
let name = getTypeForward(m, x) let name = getTypeForward(m, x)
result = con(name, "**") result = con(name, "*" & star)
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
pushType(m, x) pushType(m, x)
else: else:
# else we have a strong dependency :-( # else we have a strong dependency :-(
result = con(getTypeDescAux(m, et, check), "*") result = con(getTypeDescAux(m, et, check), star)
idTablePut(m.typeCache, t, result) idTablePut(m.typeCache, t, result)
of tyOpenArray, tyVarargs: of tyOpenArray, tyVarargs:
result = con(getTypeDescAux(m, t.sons[0], check), "*") result = con(getTypeDescAux(m, t.sons[0], check), "*")
@ -670,7 +676,7 @@ proc genProcHeader(m: BModule, prc: PSym): PRope =
rettype, params: PRope rettype, params: PRope
genCLineDir(result, prc.info) genCLineDir(result, prc.info)
# using static is needed for inline procs # 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: if m.isHeaderFile:
result.app "N_LIB_IMPORT " result.app "N_LIB_IMPORT "
else: else:
@ -696,16 +702,7 @@ proc getNimNode(m: BModule): PRope =
result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)]) result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)])
inc(m.typeNodes) inc(m.typeNodes)
when false: proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) =
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) =
var nimtypeKind: int var nimtypeKind: int
#allocMemTI(m, typ, name) #allocMemTI(m, typ, name)
if isObjLackingTypeField(typ): if isObjLackingTypeField(typ):
@ -715,6 +712,7 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) =
var size: PRope var size: PRope
if tfIncompleteStruct in typ.flags: size = toRope"void*" if tfIncompleteStruct in typ.flags: size = toRope"void*"
elif m.compileToCpp: size = getTypeDesc(m, origType)
else: size = getTypeDesc(m, typ) else: size = getTypeDesc(m, typ)
appf(m.s[cfsTypeInit3], appf(m.s[cfsTypeInit3],
"$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", "$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", appf(m.s[cfsVars], "TNimType $1; /* $2 */$n",
[name, toRope(typeToString(typ))]) [name, toRope(typeToString(typ))])
proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) = proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) =
var base: PRope var base: PRope
if (sonsLen(typ) > 0) and (typ.sons[0] != nil): if (sonsLen(typ) > 0) and (typ.sons[0] != nil):
base = genTypeInfo(m, typ.sons[0]) base = genTypeInfo(m, typ.sons[0])
else: else:
base = toRope("0") base = toRope("0")
genTypeInfoAuxBase(m, typ, name, base) genTypeInfoAuxBase(m, typ, origType, name, base)
proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope = proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope =
# bugfix: we need to search the type that contains the discriminator: # 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)]) field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)])
else: internalError(n.info, "genObjectFields") else: internalError(n.info, "genObjectFields")
proc genObjectInfo(m: BModule, typ: PType, name: PRope) = proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) =
if typ.kind == tyObject: genTypeInfoAux(m, typ, name) if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name)
else: genTypeInfoAuxBase(m, typ, name, toRope("0")) else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0"))
var tmp = getNimNode(m) 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]) appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp])
var t = typ.sons[0] var t = typ.sons[0]
while t != nil: while t != nil:
@ -827,7 +826,7 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) =
t = t.sons[0] t = t.sons[0]
proc genTupleInfo(m: BModule, typ: PType, name: PRope) = 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 expr = getNimNode(m)
var length = sonsLen(typ) var length = sonsLen(typ)
if length > 0: 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 # optimizations here: The ``typ`` field is never set, as it is redundant
# anyway. We generate a cstring array and a loop over it. Exceptional # anyway. We generate a cstring array and a loop over it. Exceptional
# positions will be reset after the loop. # positions will be reset after the loop.
genTypeInfoAux(m, typ, name) genTypeInfoAux(m, typ, typ, name)
var nodePtrs = getTempName() var nodePtrs = getTempName()
var length = sonsLen(typ.n) var length = sonsLen(typ.n)
appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$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) = proc genSetInfo(m: BModule, typ: PType, name: PRope) =
assert(typ.sons[0] != nil) assert(typ.sons[0] != nil)
genTypeInfoAux(m, typ, name) genTypeInfoAux(m, typ, typ, name)
var tmp = getNimNode(m) var tmp = getNimNode(m)
appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n",
[tmp, toRope(firstOrd(typ)), name]) [tmp, toRope(firstOrd(typ)), name])
proc genArrayInfo(m: BModule, typ: PType, name: PRope) = 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 = proc fakeClosureType(owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]] # we generate the same RTTI as for a tuple[pointer, ref tuple[]]
@ -946,22 +945,22 @@ proc genTypeInfo(m: BModule, t: PType): PRope =
case t.kind case t.kind
of tyEmpty: result = toRope"0" of tyEmpty: result = toRope"0"
of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar: of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar:
genTypeInfoAuxBase(m, t, result, toRope"0") genTypeInfoAuxBase(m, t, t, result, toRope"0")
of tyProc: of tyProc:
if t.callConv != ccClosure: if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, result, toRope"0") genTypeInfoAuxBase(m, t, t, result, toRope"0")
else: else:
genTupleInfo(m, fakeClosureType(t.owner), result) genTupleInfo(m, fakeClosureType(t.owner), result)
of tySequence, tyRef: of tySequence, tyRef:
genTypeInfoAux(m, t, result) genTypeInfoAux(m, t, t, result)
if gSelectedGC >= gcMarkAndSweep: if gSelectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, t, tiNew) let markerProc = genTraverseProc(m, t, tiNew)
appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc]) 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 tyArrayConstr, tyArray: genArrayInfo(m, t, result)
of tySet: genSetInfo(m, t, result) of tySet: genSetInfo(m, t, result)
of tyEnum: genEnumInfo(m, t, result) of tyEnum: genEnumInfo(m, t, result)
of tyObject: genObjectInfo(m, t, result) of tyObject: genObjectInfo(m, t, origType, result)
of tyTuple: of tyTuple:
# if t.n != nil: genObjectInfo(m, t, result) # if t.n != nil: genObjectInfo(m, t, result)
# else: # else:

View file

@ -70,6 +70,19 @@ when false:
for i in countup(low(TTypeKind), high(TTypeKind)): for i in countup(low(TTypeKind), high(TTypeKind)):
echo i, " ", gTypeTable[i].counter 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 = proc getUniqueType*(key: PType): PType =
# this is a hotspot in the compiler! # this is a hotspot in the compiler!
if key == nil: return if key == nil: return
@ -86,7 +99,7 @@ proc getUniqueType*(key: PType): PType =
gCanonicalTypes[k] = key gCanonicalTypes[k] = key
result = key result = key
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor: of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
internalError("GetUniqueType") internalError("getUniqueType")
of tyDistinct: of tyDistinct:
if key.deepCopy != nil: result = key if key.deepCopy != nil: result = key
else: result = getUniqueType(lastSon(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": #if obj.sym != nil and obj.sym.name.s == "TOption":
# echo "for ", typeToString(key), " I returned " # echo "for ", typeToString(key), " I returned "
# debug result # 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, tyOpenArray, tyArray, tySet, tyRange, tyTuple,
tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar: tySequence, tyForward, tyVarargs, tyProxy:
# 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'.
# we have to do a slow linear search because types may need # we have to do a slow linear search because types may need
# to be compared by their structure: # to be compared by their structure:
if idTableHasObjectAsKey(gTypeTable[k], key): return key result = slowSearch(key, k)
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
of tyObject: of tyObject:
if tfFromGeneric notin key.flags: if tfFromGeneric notin key.flags:
# fast case; lookup per id suffices: # fast case; lookup per id suffices:
@ -125,7 +135,7 @@ proc getUniqueType*(key: PType): PType =
if idTableHasObjectAsKey(gTypeTable[k], key): return key 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) var t = PType(gTypeTable[k].data[h].key)
if t != nil and sameType(t, key): if t != nil and sameBackendType(t, key):
return t return t
idTablePut(gTypeTable[k], key, key) idTablePut(gTypeTable[k], key, key)
result = key result = key
@ -139,13 +149,7 @@ proc getUniqueType*(key: PType): PType =
result = key result = key
else: else:
# ugh, we need the canon here: # ugh, we need the canon here:
if idTableHasObjectAsKey(gTypeTable[k], key): return key result = slowSearch(key, k)
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 tableGetType*(tab: TIdTable, key: PType): RootRef = proc tableGetType*(tab: TIdTable, key: PType): RootRef =
# returns nil if we need to declare this type # returns nil if we need to declare this type

View file

@ -25,15 +25,6 @@ when options.hasTinyCBackend:
var var
generatedHeader: BModule 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) = proc addForwardedProc(m: BModule, prc: PSym) =
m.forwardedProcs.add(prc) m.forwardedProcs.add(prc)
inc(gForwardedProcsCounter) inc(gForwardedProcsCounter)
@ -137,79 +128,8 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope =
if i - 1 >= start: if i - 1 >= start:
app(result, substr(frmt, start, i - 1)) app(result, substr(frmt, start, i - 1))
const compileTimeRopeFmt = false template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr =
ropecg(m, fmt, args)
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)
proc appcg(m: BModule, c: var PRope, frmt: TFormatStr, proc appcg(m: BModule, c: var PRope, frmt: TFormatStr,
args: varargs[PRope]) = args: varargs[PRope]) =
@ -242,24 +162,14 @@ proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr,
args: varargs[PRope]) = args: varargs[PRope]) =
app(p.s(s), indentLine(p, ropecg(p.module, frmt, args))) app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
when compileTimeRopeFmt: proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr,
template linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr, args: varargs[PRope]) =
args: varargs[PRope]) = app(p.s(s), indentLine(p, ropecg(p.module, frmt, args)))
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 appLineCg(p: BProc, r: var PRope, frmt: TFormatStr, proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr,
args: varargs[PRope]) = args: varargs[PRope]) =
app(r, indentLine(p, ropecg(p.module, frmt, args))) 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 = proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info) result = toLinenumber(info)
if result < 0: result = 0 # negative numbers are not allowed in #line 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) = proc genCLineDir(r: var PRope, filename: string, line: int) =
assert line >= 0 assert line >= 0
if optLineDir in gOptions: if optLineDir in gOptions:
appff(r, "$N#line $2 $1$N", "; line $2 \"$1\"$n", appf(r, "$N#line $2 $1$N",
[toRope(makeSingleLineCString(filename)), toRope(line)]) [toRope(makeSingleLineCString(filename)), toRope(line)])
proc genCLineDir(r: var PRope, info: TLineInfo) = proc genCLineDir(r: var PRope, info: TLineInfo) =
genCLineDir(r, info.toFullPath, info.safeLineNm) 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) = proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
inc(p.labels) inc(p.labels)
if gCmd == cmdCompileToLLVM: result.r = con("LOC", toRope(p.labels))
result.r = con("%LOC", toRope(p.labels)) linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
else:
result.r = con("LOC", toRope(p.labels))
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
result.k = locTemp result.k = locTemp
#result.a = - 1 #result.a = - 1
result.t = getUniqueType(t) result.t = getUniqueType(t)
@ -447,29 +354,6 @@ proc deinitGCFrame(p: BProc): PRope =
result = ropecg(p.module, result = ropecg(p.module,
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n") "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) = proc allocParam(p: BProc, s: PSym) =
assert(s.kind == skParam) assert(s.kind == skParam)
if lfParamCopy notin s.loc.flags: if lfParamCopy notin s.loc.flags:
@ -494,22 +378,26 @@ proc localDebugInfo(p: BProc, s: PSym) =
inc(p.maxFrameLen) inc(p.maxFrameLen)
inc p.blocks[p.blocks.len-1].frameLen inc p.blocks[p.blocks.len-1].frameLen
proc assignLocalVar(p: BProc, s: PSym) = proc localVarDecl(p: BProc; s: PSym): PRope =
#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!
if s.loc.k == locNone: if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack) fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) 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 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: #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD") # app(decl, " GC_GUARD")
if sfVolatile in s.flags: app(decl, " volatile") if sfVolatile in s.flags: app(result, " volatile")
appf(decl, " $1;$n", [s.loc.r]) app(result, " ")
app(result, s.loc.r)
else: 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) line(p, cpsLocals, decl)
localDebugInfo(p, s) localDebugInfo(p, s)
@ -552,13 +440,11 @@ proc assignGlobalVar(p: BProc, s: PSym) =
{optStackTrace, optEndb}: {optStackTrace, optEndb}:
appcg(p.module, p.module.s[cfsDebugInit], appcg(p.module, p.module.s[cfsDebugInit],
"#dbgRegisterGlobal($1, &$2, $3);$n", "#dbgRegisterGlobal($1, &$2, $3);$n",
[cstringLit(p, p.module.s[cfsDebugInit], [makeCString(normalize(s.owner.name.s & '.' & s.name.s)),
normalize(s.owner.name.s & '.' & s.name.s)),
s.loc.r, genTypeInfo(p.module, s.typ)]) s.loc.r, genTypeInfo(p.module, s.typ)])
proc assignParam(p: BProc, s: PSym) = proc assignParam(p: BProc, s: PSym) =
assert(s.loc.r != nil) assert(s.loc.r != nil)
if sfAddrTaken in s.flags and gCmd == cmdCompileToLLVM: allocParam(p, s)
localDebugInfo(p, s) localDebugInfo(p, s)
proc fillProcLoc(sym: PSym) = proc fillProcLoc(sym: PSym) =
@ -586,6 +472,11 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e.typ, OnUnknown) initLoc(result, locNone, e.typ, OnUnknown)
expr(p, e, result) expr(p, e, result)
proc 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 = proc lenField(p: BProc): PRope =
result = toRope(if p.module.compileToCpp: "len" else: "Sup.len") result = toRope(if p.module.compileToCpp: "len" else: "Sup.len")
@ -647,7 +538,6 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
let isCall = isGetProcAddr(lib) let isCall = isGetProcAddr(lib)
var extname = sym.loc.r var extname = sym.loc.r
if not isCall: loadDynamicLib(m, lib) if not isCall: loadDynamicLib(m, lib)
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
var tmp = mangleDynLibProc(sym) var tmp = mangleDynLibProc(sym)
sym.loc.r = tmp # from now on we only need the internal name sym.loc.r = tmp # from now on we only need the internal name
sym.typ.sym = nil # generate a new name sym.typ.sym = nil # generate a new name
@ -663,7 +553,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
params.app(", ") params.app(", ")
let load = ropef("\t$1 = ($2) ($3$4));$n", let load = ropef("\t$1 = ($2) ($3$4));$n",
[tmp, getTypeDesc(m, sym.typ), [tmp, getTypeDesc(m, sym.typ),
params, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))]) params, makeCString(ropeToStr(extname))])
var last = lastSon(n) var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last.sons[1] if last.kind == nkHiddenStdConv: last = last.sons[1]
internalAssert(last.kind == nkStrLit) internalAssert(last.kind == nkStrLit)
@ -678,10 +568,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
appcg(m, m.s[cfsDynLibInit], appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n", "\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ), [tmp, getTypeDesc(m, sym.typ),
lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))]) lib.name, makeCString(ropeToStr(extname))])
appff(m.s[cfsVars], "$2 $1;$n", appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)])
"$1 = linkonce global $2 zeroinitializer$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)])
proc varInDynamicLib(m: BModule, sym: PSym) = proc varInDynamicLib(m: BModule, sym: PSym) =
var lib = sym.annex var lib = sym.annex
@ -694,7 +582,7 @@ proc varInDynamicLib(m: BModule, sym: PSym) =
appcg(m, m.s[cfsDynLibInit], appcg(m, m.s[cfsDynLibInit],
"$1 = ($2*) #nimGetProcAddr($3, $4);$n", "$1 = ($2*) #nimGetProcAddr($3, $4);$n",
[tmp, getTypeDesc(m, sym.typ), [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", appf(m.s[cfsVars], "$2* $1;$n",
[sym.loc.r, getTypeDesc(m, sym.loc.t)]) [sym.loc.r, getTypeDesc(m, sym.loc.t)])
@ -796,16 +684,17 @@ proc genProcAux(m: BModule, prc: PSym) =
app(generatedProc, initGCFrame(p)) app(generatedProc, initGCFrame(p))
if optStackTrace in prc.options: if optStackTrace in prc.options:
app(generatedProc, p.s(cpsLocals)) 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)) app(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
else: else:
app(generatedProc, p.s(cpsLocals)) app(generatedProc, p.s(cpsLocals))
if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): if optProfiler in prc.options:
# invoke at proc entry for recursion: # invoke at proc entry for recursion:
appcg(p, cpsInit, "\t#nimProfile();$n", []) appcg(p, cpsInit, "\t#nimProfile();$n", [])
if p.beforeRetNeeded: app(generatedProc, "{")
app(generatedProc, p.s(cpsInit)) app(generatedProc, p.s(cpsInit))
app(generatedProc, p.s(cpsStmts)) app(generatedProc, p.s(cpsStmts))
if p.beforeRetNeeded: app(generatedProc, ~"\tBeforeRet: ;$n") if p.beforeRetNeeded: app(generatedProc, ~"\t}BeforeRet: ;$n")
app(generatedProc, deinitGCFrame(p)) app(generatedProc, deinitGCFrame(p))
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p)) if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
app(generatedProc, returnStmt) app(generatedProc, returnStmt)
@ -825,7 +714,6 @@ proc genProcPrototype(m: BModule, sym: PSym) =
not containsOrIncl(m.declaredThings, sym.id): not containsOrIncl(m.declaredThings, sym.id):
app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n", app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym))) getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
elif not containsOrIncl(m.declaredProtos, sym.id): elif not containsOrIncl(m.declaredProtos, sym.id):
var header = genProcHeader(m, sym) var header = genProcHeader(m, sym)
if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym):
@ -923,21 +811,17 @@ proc addIntTypes(result: var PRope) {.inline.} =
proc getCopyright(cfile: string): PRope = proc getCopyright(cfile: string): PRope =
if optCompileOnly in gGlobalOptions: 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" & "/* (c) 2015 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N", "/* The generated code is subject to the original license. */$N",
"; Generated by Nim Compiler v$1$N" & [toRope(VersionAsString)])
"; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)])
else: else:
result = ropeff("/* Generated by Nim Compiler v$1 */$N" & result = ropef("/* Generated by Nim Compiler v$1 */$N" &
"/* (c) 2015 Andreas Rumpf */$N" & "/* (c) 2015 Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N" & "/* The generated code is subject to the original license. */$N" &
"/* Compiled for: $2, $3, $4 */$N" & "/* Compiled for: $2, $3, $4 */$N" &
"/* Command for C compiler:$n $5 */$N", "/* Command for C compiler:$n $5 */$N",
"; Generated by Nim Compiler v$1$N" & [toRope(VersionAsString),
"; (c) 2015 Andreas Rumpf$N" &
"; Compiled for: $2, $3, $4$N" &
"; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString),
toRope(platform.OS[targetOS].name), toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name), toRope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.cCompiler].name), toRope(extccomp.CC[extccomp.cCompiler].name),
@ -1088,13 +972,11 @@ proc registerModuleToMain(m: PSym) =
var var
init = m.getInitName init = m.getInitName
datInit = m.getDatInitName datInit = m.getDatInitName
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
"declare void $1() noinline$N", [init]) appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N",
"declare void $1() noinline$N", [datInit])
if sfSystemModule notin m.flags: if sfSystemModule notin m.flags:
appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit]) appf(mainDatInit, "\t$1();$N", [datInit])
let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init]) let initCall = ropef("\t$1();$N", [init])
if sfMainModule in m.flags: if sfMainModule in m.flags:
app(mainModInit, initCall) app(mainModInit, initCall)
else: else:
@ -1102,8 +984,7 @@ proc registerModuleToMain(m: PSym) =
proc genInitCode(m: BModule) = proc genInitCode(m: BModule) =
var initname = getInitName(m.module) var initname = getInitName(m.module)
var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", var prc = ropef("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", [initname])
"define void $1() noinline {$n", [initname])
if m.typeNodes > 0: if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
[m.typeNodesName, toRope(m.typeNodes)]) [m.typeNodesName, toRope(m.typeNodes)])
@ -1124,7 +1005,7 @@ proc genInitCode(m: BModule) =
# declare it nevertheless: # declare it nevertheless:
m.frameDeclared = true m.frameDeclared = true
if not m.preventStackTrace: 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)) app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
else: else:
app(prc, ~"\tTFrame F; F.len = 0;$N") app(prc, ~"\tTFrame F; F.len = 0;$N")
@ -1145,8 +1026,8 @@ proc genInitCode(m: BModule) =
app(prc, deinitGCFrame(m.initProc)) app(prc, deinitGCFrame(m.initProc))
appf(prc, "}$N$N") appf(prc, "}$N$N")
prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", prc.appf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
"define void $1() noinline {$n", [getDatInitName(m.module)]) [getDatInitName(m.module)])
for i in cfsTypeInit1..cfsDynLibInit: for i in cfsTypeInit1..cfsDynLibInit:
app(prc, genSectionStart(i)) app(prc, genSectionStart(i))

View file

@ -82,6 +82,9 @@ type
maxFrameLen*: int # max length of frame descriptor maxFrameLen*: int # max length of frame descriptor
module*: BModule # used to prevent excessive parameter passing module*: BModule # used to prevent excessive parameter passing
withinLoop*: int # > 0 if we are within a loop 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 gcFrameId*: Natural # for the GC stack marking
gcFrameType*: PRope # the struct {} we put the GC markers into 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 const
HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" &
"Copyright (c) 2006-2014 by Andreas Rumpf\n" "Copyright (c) 2006-2015 by Andreas Rumpf\n"
const const
Usage = slurp"doc/basicopt.txt".replace("//", "") 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)) if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch))
proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
info: TLineInfo) = info: TLineInfo; orig: string) =
var id = "" # arg = "X]:on|off" var id = "" # arg = "X]:on|off"
var i = 0 var i = 0
var n = hintMin var n = hintMin
@ -149,17 +149,17 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass,
add(id, arg[i]) add(id, arg[i])
inc(i) inc(i)
if i < len(arg) and (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) if i < len(arg) and (arg[i] in {':', '='}): inc(i)
else: invalidCmdLineOption(pass, arg, info) else: invalidCmdLineOption(pass, orig, info)
if state == wHint: if state == wHint:
var x = findStr(msgs.HintsToStr, id) var x = findStr(msgs.HintsToStr, id)
if x >= 0: n = TNoteKind(x + ord(hintMin)) if x >= 0: n = TNoteKind(x + ord(hintMin))
else: invalidCmdLineOption(pass, arg, info) else: localError(info, "unknown hint: " & id)
else: else:
var x = findStr(msgs.WarningsToStr, id) var x = findStr(msgs.WarningsToStr, id)
if x >= 0: n = TNoteKind(x + ord(warnMin)) if x >= 0: n = TNoteKind(x + ord(warnMin))
else: invalidCmdLineOption(pass, arg, info) else: localError(info, "unknown warning: " & id)
case whichKeyword(substr(arg, i)) case whichKeyword(substr(arg, i))
of wOn: incl(gNotes, n) of wOn: incl(gNotes, n)
of wOff: excl(gNotes, n) of wOff: excl(gNotes, n)
@ -368,16 +368,26 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) =
defineSymbol("nogc") defineSymbol("nogc")
else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) else: localError(info, errNoneBoehmRefcExpectedButXFound, arg)
of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info) of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info)
of "warning": processSpecificNote(arg, wWarning, pass, info) of "warning": processSpecificNote(arg, wWarning, pass, info, switch)
of "hint": processSpecificNote(arg, wHint, pass, info) of "hint": processSpecificNote(arg, wHint, pass, info, switch)
of "hints": processOnOffSwitch({optHints}, arg, pass, info) of "hints": processOnOffSwitch({optHints}, arg, pass, info)
of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info) of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info)
of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info) of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info)
of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info) of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info)
of "debugger": of "debugger":
processOnOffSwitch({optEndb}, arg, pass, info) case arg.normalize
if optEndb in gOptions: defineSymbol("endb") of "on", "endb":
else: undefSymbol("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": of "profiler":
processOnOffSwitch({optProfiler}, arg, pass, info) processOnOffSwitch({optProfiler}, arg, pass, info)
if optProfiler in gOptions: defineSymbol("profiler") if optProfiler in gOptions: defineSymbol("profiler")

View file

@ -89,6 +89,7 @@ proc initDefines*() =
defineSymbol("nimparsebiggestfloatmagic") defineSymbol("nimparsebiggestfloatmagic")
defineSymbol("nimalias") defineSymbol("nimalias")
defineSymbol("nimlocks") defineSymbol("nimlocks")
defineSymbol("nimnode")
# add platform specific symbols: # add platform specific symbols:
for c in low(CPU)..high(CPU): 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 if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
var idx = getVarIdx(varnames, id) var idx = getVarIdx(varnames, id)
if idx >= 0: app(result, varvalues[idx]) if idx >= 0: app(result, varvalues[idx])
else: rawMessage(errUnkownSubstitionVar, id) else: rawMessage(errUnknownSubstitionVar, id)
of '{': of '{':
var id = "" var id = ""
inc(i) inc(i)
@ -138,7 +138,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string],
# search for the variable: # search for the variable:
var idx = getVarIdx(varnames, id) var idx = getVarIdx(varnames, id)
if idx >= 0: app(result, varvalues[idx]) if idx >= 0: app(result, varvalues[idx])
else: rawMessage(errUnkownSubstitionVar, id) else: rawMessage(errUnknownSubstitionVar, id)
else: internalError("ropeFormatNamedVars") else: internalError("ropeFormatNamedVars")
var start = i var start = i
while i < L: 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 ## 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 ## 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 ## 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 ## If you modify the output of this proc, please update the anchor generation
## section of ``doc/docgen.txt``. ## section of ``doc/docgen.txt``.

View file

@ -380,7 +380,7 @@ proc setCC*(ccname: string) =
cCompiler = nameToCC(ccname) cCompiler = nameToCC(ccname)
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname) if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
compileOptions = getConfigVar(cCompiler, ".options.always") compileOptions = getConfigVar(cCompiler, ".options.always")
linkOptions = getConfigVar(cCompiler, ".options.linker") linkOptions = ""
ccompilerpath = getConfigVar(cCompiler, ".path") ccompilerpath = getConfigVar(cCompiler, ".path")
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name) for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[cCompiler].name) defineSymbol(CC[cCompiler].name)
@ -390,7 +390,7 @@ proc addOpt(dest: var string, src: string) =
add(dest, src) add(dest, src)
proc addLinkOption*(option: string) = proc addLinkOption*(option: string) =
if find(linkOptions, option, 0) < 0: addOpt(linkOptions, option) addOpt(linkOptions, option)
proc addCompileOption*(option: string) = proc addCompileOption*(option: string) =
if strutils.find(compileOptions, option, 0) < 0: 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) for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[cCompiler].name) defineSymbol(CC[cCompiler].name)
addCompileOption(getConfigVar(cCompiler, ".options.always")) addCompileOption(getConfigVar(cCompiler, ".options.always"))
addLinkOption(getConfigVar(cCompiler, ".options.linker")) #addLinkOption(getConfigVar(cCompiler, ".options.linker"))
if len(ccompilerpath) == 0: if len(ccompilerpath) == 0:
ccompilerpath = getConfigVar(cCompiler, ".path") ccompilerpath = getConfigVar(cCompiler, ".path")
@ -428,13 +428,17 @@ proc addFileToLink*(filename: string) =
prependStr(toLink, filename) prependStr(toLink, filename)
# BUGFIX: was ``appendStr`` # BUGFIX: was ``appendStr``
proc execExternalProgram*(cmd: string, prettyCmd = "") = proc execWithEcho(cmd: string, prettyCmd = ""): int =
if optListCmd in gGlobalOptions or gVerbosity > 0: if optListCmd in gGlobalOptions or gVerbosity > 0:
if prettyCmd != "": if prettyCmd != "":
msgWriteln(prettyCmd) msgWriteln(prettyCmd)
else: else:
msgWriteln(cmd) 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) = proc generateScript(projectFile: string, script: PRope) =
let (dir, name, ext) = splitFile(projectFile) let (dir, name, ext) = splitFile(projectFile)
@ -549,13 +553,13 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string =
cfile = quoteShell(cfile) cfile = quoteShell(cfile)
result = quoteShell(compilePattern % [ result = quoteShell(compilePattern % [
"file", cfile, "objfile", objfile, "options", options, "file", cfile, "objfile", objfile, "options", options,
"include", includeCmd, "nimrod", getPrefixDir(), "include", includeCmd, "nim", getPrefixDir(),
"nim", getPrefixDir(), "lib", libpath]) "nim", getPrefixDir(), "lib", libpath])
add(result, ' ') add(result, ' ')
addf(result, CC[c].compileTmpl, [ addf(result, CC[c].compileTmpl, [
"file", cfile, "objfile", objfile, "file", cfile, "objfile", objfile,
"options", options, "include", includeCmd, "options", options, "include", includeCmd,
"nimrod", quoteShell(getPrefixDir()), "nim", quoteShell(getPrefixDir()),
"nim", quoteShell(getPrefixDir()), "nim", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)]) "lib", quoteShell(libpath)])
@ -622,15 +626,17 @@ proc callCCompiler*(projectfile: string) =
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors() if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
var res = 0 var res = 0
if gNumberOfProcessors <= 1: if gNumberOfProcessors <= 1:
for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res) for i in countup(0, high(cmds)):
res = execWithEcho(cmds[i])
if res != 0: rawMessage(errExecutionOfProgramFailed, [])
elif optListCmd in gGlobalOptions or gVerbosity > 1: elif optListCmd in gGlobalOptions or gVerbosity > 1:
res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams}, res = execProcesses(cmds, {poEchoCmd, poUsePath, poParentStreams},
gNumberOfProcessors) gNumberOfProcessors)
elif gVerbosity == 1: elif gVerbosity == 1:
res = execProcesses(cmds, {poUseShell, poParentStreams}, res = execProcesses(cmds, {poUsePath, poParentStreams},
gNumberOfProcessors, prettyCb) gNumberOfProcessors, prettyCb)
else: else:
res = execProcesses(cmds, {poUseShell, poParentStreams}, res = execProcesses(cmds, {poUsePath, poParentStreams},
gNumberOfProcessors) gNumberOfProcessors)
if res != 0: if res != 0:
if gNumberOfProcessors <= 1: if gNumberOfProcessors <= 1:
@ -673,15 +679,16 @@ proc callCCompiler*(projectfile: string) =
if not exefile.isAbsolute(): if not exefile.isAbsolute():
exefile = joinPath(splitFile(projectfile).dir, exefile) exefile = joinPath(splitFile(projectfile).dir, exefile)
exefile = quoteShell(exefile) exefile = quoteShell(exefile)
let linkOptions = getLinkOptions() let linkOptions = getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker")
linkCmd = quoteShell(linkCmd % ["builddll", builddll, linkCmd = quoteShell(linkCmd % ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
"exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath]) "exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
linkCmd.add ' ' linkCmd.add ' '
addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll, addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions, "buildgui", buildgui, "options", linkOptions,
"objfiles", objfiles, "exefile", exefile, "objfiles", objfiles, "exefile", exefile,
"nimrod", quoteShell(getPrefixDir()), "nim", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)]) "lib", quoteShell(libpath)])
if optCompileOnly notin gGlobalOptions: if optCompileOnly notin gGlobalOptions:
if gVerbosity == 1: if gVerbosity == 1:
@ -710,7 +717,8 @@ proc writeMapping*(gSymbolMapping: PRope) =
app(code, strutils.escape(getCompileOptions())) app(code, strutils.escape(getCompileOptions()))
app(code, "\n[Linker]\nFlags=") 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, "\n[Environment]\nlibpath=")
app(code, strutils.escape(libpath)) 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: "*.ini"
Files: "koch.nim" Files: "koch.nim"
Files: "icons/nimrod.ico" Files: "icons/nim.ico"
Files: "icons/nimrod.rc" Files: "icons/nim.rc"
Files: "icons/nimrod.res" Files: "icons/nim.res"
Files: "icons/nimrod_icon.o" Files: "icons/nim_icon.o"
Files: "icons/koch.ico" Files: "icons/koch.ico"
Files: "icons/koch.rc" Files: "icons/koch.rc"
Files: "icons/koch.res" Files: "icons/koch.res"

View file

@ -148,7 +148,7 @@ proc mapType(typ: PType): TJSTypeKind =
tyVarargs: tyVarargs:
result = etyObject result = etyObject
of tyNil: result = etyNull of tyNil: result = etyNull
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor, tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses: tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses:
result = etyNone result = etyNone

View file

@ -15,7 +15,7 @@ import
discard """ discard """
The basic approach is that captured vars need to be put on the heap and 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 = proc a =
var v = 0 var v = 0
@ -583,7 +583,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) =
elif it.kind == nkIdentDefs: elif it.kind == nkIdentDefs:
var L = sonsLen(it) var L = sonsLen(it)
if it.sons[0].kind == nkSym: 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': # transformed it into 'env.varName':
env.vars.incl(it.sons[0].sym.id) env.vars.incl(it.sons[0].sym.id)
searchForInnerProcs(o, it.sons[L-1], env) searchForInnerProcs(o, it.sons[L-1], env)
@ -999,7 +999,7 @@ proc liftForLoop*(body: PNode): PNode =
# proc invoke(iter: iterator(): int) = # proc invoke(iter: iterator(): int) =
# for x in iter(): echo x # 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 """ discard """
for i in foo(): ... for i in foo(): ...

View file

@ -107,7 +107,7 @@ type
TToken* = object # a Nim token TToken* = object # a Nim token
tokType*: TTokType # the type of the token tokType*: TTokType # the type of the token
indent*: int # the indentation; != -1 if the token has been indent*: int # the indentation; != -1 if the token has been
# preceeded with indentation # preceded with indentation
ident*: PIdent # the parsed identifier ident*: PIdent # the parsed identifier
iNumber*: BiggestInt # the parsed integer literal iNumber*: BiggestInt # the parsed integer literal
fNumber*: BiggestFloat # the parsed floating point literal fNumber*: BiggestFloat # the parsed floating point literal
@ -181,10 +181,8 @@ proc prettyTok*(tok: TToken): string =
else: result = tokToStr(tok) else: result = tokToStr(tok)
proc printTok*(tok: TToken) = proc printTok*(tok: TToken) =
write(stdout, tok.line, ":", tok.col, "\t") msgWriteln($tok.line & ":" & $tok.col & "\t" &
write(stdout, TokTypeToStr[tok.tokType]) TokTypeToStr[tok.tokType] & " " & tokToStr(tok))
write(stdout, " ")
writeln(stdout, tokToStr(tok))
var dummyIdent: PIdent var dummyIdent: PIdent
@ -679,7 +677,7 @@ proc getOperator(L: var TLexer, tok: var TToken) =
inc(pos) inc(pos)
endOperator(L, tok, pos, h) endOperator(L, tok, pos, h)
# advance pos but don't store it in L.bufpos so the next token (which might # 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 tok.strongSpaceB = 0
while buf[pos] == ' ': while buf[pos] == ' ':
inc pos inc pos

View file

@ -30,47 +30,32 @@ type
PLLStream* = ref TLLStream PLLStream* = ref TLLStream
proc llStreamOpen*(data: string): PLLStream 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 =
new(result) new(result)
result.s = data result.s = data
result.kind = llsString result.kind = llsString
proc llStreamOpen(f: var File): PLLStream = proc llStreamOpen*(f: File): PLLStream =
new(result) new(result)
result.f = f result.f = f
result.kind = llsFile result.kind = llsFile
proc llStreamOpen(filename: string, mode: FileMode): PLLStream = proc llStreamOpen*(filename: string, mode: FileMode): PLLStream =
new(result) new(result)
result.kind = llsFile result.kind = llsFile
if not open(result.f, filename, mode): result = nil if not open(result.f, filename, mode): result = nil
proc llStreamOpen(): PLLStream = proc llStreamOpen*(): PLLStream =
new(result) new(result)
result.kind = llsNone result.kind = llsNone
proc llStreamOpenStdIn(): PLLStream = proc llStreamOpenStdIn*(): PLLStream =
new(result) new(result)
result.kind = llsStdIn result.kind = llsStdIn
result.s = "" result.s = ""
result.lineOffset = -1 result.lineOffset = -1
proc llStreamClose(s: PLLStream) = proc llStreamClose*(s: PLLStream) =
case s.kind case s.kind
of llsNone, llsString, llsStdIn: of llsNone, llsString, llsStdIn:
discard discard
@ -130,7 +115,7 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int =
copyMem(buf, addr(s.s[s.rd]), result) copyMem(buf, addr(s.s[s.rd]), result)
inc(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 case s.kind
of llsNone: of llsNone:
result = 0 result = 0
@ -144,7 +129,7 @@ proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int =
of llsStdIn: of llsStdIn:
result = llReadFromStdin(s, buf, bufLen) result = llReadFromStdin(s, buf, bufLen)
proc llStreamReadLine(s: PLLStream, line: var string): bool = proc llStreamReadLine*(s: PLLStream, line: var string): bool =
setLen(line, 0) setLen(line, 0)
case s.kind case s.kind
of llsNone: of llsNone:
@ -168,7 +153,7 @@ proc llStreamReadLine(s: PLLStream, line: var string): bool =
of llsStdIn: of llsStdIn:
result = readLine(stdin, line) result = readLine(stdin, line)
proc llStreamWrite(s: PLLStream, data: string) = proc llStreamWrite*(s: PLLStream, data: string) =
case s.kind case s.kind
of llsNone, llsStdIn: of llsNone, llsStdIn:
discard discard
@ -178,11 +163,11 @@ proc llStreamWrite(s: PLLStream, data: string) =
of llsFile: of llsFile:
write(s.f, data) write(s.f, data)
proc llStreamWriteln(s: PLLStream, data: string) = proc llStreamWriteln*(s: PLLStream, data: string) =
llStreamWrite(s, data) llStreamWrite(s, data)
llStreamWrite(s, "\n") llStreamWrite(s, "\n")
proc llStreamWrite(s: PLLStream, data: char) = proc llStreamWrite*(s: PLLStream, data: char) =
var c: char var c: char
case s.kind case s.kind
of llsNone, llsStdIn: of llsNone, llsStdIn:
@ -194,7 +179,7 @@ proc llStreamWrite(s: PLLStream, data: char) =
c = data c = data
discard writeBuffer(s.f, addr(c), sizeof(c)) 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 case s.kind
of llsNone, llsStdIn: of llsNone, llsStdIn:
discard discard
@ -206,7 +191,7 @@ proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) =
of llsFile: of llsFile:
discard writeBuffer(s.f, buf, buflen) discard writeBuffer(s.f, buf, buflen)
proc llStreamReadAll(s: PLLStream): string = proc llStreamReadAll*(s: PLLStream): string =
const const
bufSize = 2048 bufSize = 2048
case s.kind case s.kind

View file

@ -176,7 +176,7 @@ proc addInterfaceDeclAux(c: PContext, sym: PSym) =
if sfExported in sym.flags: if sfExported in sym.flags:
# add to interface: # add to interface:
if c.module != nil: strTableAdd(c.module.tab, sym) 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) = proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
addDeclAt(scope, sym) addDeclAt(scope, sym)

View file

@ -62,7 +62,7 @@ proc commandCompileToC =
compileProject() compileProject()
cgenWriteModules() cgenWriteModules()
if gCmd != cmdRun: if gCmd != cmdRun:
extccomp.callCCompiler(changeFileExt(gProjectFull, "")) extccomp.callCCompiler(if gProjectName == "-": "stdinfile" else: changeFileExt(gProjectFull, ""))
if isServing: if isServing:
# caas will keep track only of the compilation commands # caas will keep track only of the compilation commands
@ -251,7 +251,6 @@ proc mainCommand* =
commandCompileToC() commandCompileToC()
of "cpp", "compiletocpp": of "cpp", "compiletocpp":
gCmd = cmdCompileToCpp gCmd = cmdCompileToCpp
if cCompiler == ccGcc: setCC("gcc")
defineSymbol("cpp") defineSymbol("cpp")
commandCompileToC() commandCompileToC()
of "objc", "compiletooc": of "objc", "compiletooc":

View file

@ -116,7 +116,7 @@ proc newModule(fileIdx: int32): PSym =
result.kind = skModule result.kind = skModule
let filename = fileIdx.toFullPath let filename = fileIdx.toFullPath
result.name = getIdent(splitFile(filename).name) result.name = getIdent(splitFile(filename).name)
if not isNimIdentifier(result.name.s): if result.name.s != "-" and not isNimIdentifier(result.name.s):
rawMessage(errInvalidModuleName, result.name.s) rawMessage(errInvalidModuleName, result.name.s)
result.info = newLineInfo(fileIdx, 1, 1) result.info = newLineInfo(fileIdx, 1, 1)

View file

@ -69,7 +69,7 @@ type
errInvalidOrderInArrayConstructor, errInvalidOrderInArrayConstructor,
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
errOptionExpected, errXisNoLabel, errNotAllCasesCovered, errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
errUnkownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
@ -89,7 +89,7 @@ type
errTIsNotAConcreteType, errTIsNotAConcreteType,
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely, errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
errOnlyACallOpCanBeDelegator, errUsingNoSymbol, errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
errMacroBodyDependsOnGenericTypes, errMacroBodyDependsOnGenericTypes,
errDestructorNotGenericEnough, errDestructorNotGenericEnough,
@ -113,7 +113,7 @@ type
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported, warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored, warnFieldXNotSupported, warnCommentXIgnored,
warnNilStatement, warnAnalysisLoophole, warnNilStatement, warnTypelessParam,
warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode, warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode,
warnEachIdentIsTuple, warnShadowIdent, warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
@ -280,7 +280,7 @@ const
errOptionExpected: "option expected, but found \'$1\'", errOptionExpected: "option expected, but found \'$1\'",
errXisNoLabel: "\'$1\' is not a label", errXisNoLabel: "\'$1\' is not a label",
errNotAllCasesCovered: "not all cases are covered", errNotAllCasesCovered: "not all cases are covered",
errUnkownSubstitionVar: "unknown substitution variable: \'$1\'", errUnknownSubstitionVar: "unknown substitution variable: \'$1\'",
errComplexStmtRequiresInd: "complex statement requires indentation", errComplexStmtRequiresInd: "complex statement requires indentation",
errXisNotCallable: "\'$1\' is not callable", errXisNotCallable: "\'$1\' is not callable",
errNoPragmasAllowedForX: "no pragmas allowed for $1", errNoPragmasAllowedForX: "no pragmas allowed for $1",
@ -312,7 +312,7 @@ const
errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", errXOnlyAtModuleScope: "\'$1\' is only allowed at top level",
errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
errTemplateInstantiationTooNested: "template/macro instantiation too nested", errTemplateInstantiationTooNested: "template/macro instantiation too nested",
errInstantiationFrom: "instantiation from here", errInstantiationFrom: "template/generic instantiation from here",
errInvalidIndexValueForTuple: "invalid index value for tuple subscript", errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
errCommandExpectsFilename: "command expects a filename argument", errCommandExpectsFilename: "command expects a filename argument",
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
@ -326,12 +326,12 @@ const
errXisNoValidIndexFile: "\'$1\' is no valid index file", errXisNoValidIndexFile: "\'$1\' is no valid index file",
errCannotRenderX: "cannot render reStructuredText element \'$1\'", errCannotRenderX: "cannot render reStructuredText element \'$1\'",
errVarVarTypeNotAllowed: "type \'var var\' is not allowed", errVarVarTypeNotAllowed: "type \'var var\' is not allowed",
errInstantiateXExplicitely: "instantiate '$1' explicitely", errInstantiateXExplicitly: "instantiate '$1' explicitly",
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " & errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
"because the parameter '$1' has a generic type", "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", "A destructor must be associated will all instantiations of a generic type",
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " & errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
"templates, macros and other inline iterators", "templates, macros and other inline iterators",
@ -360,7 +360,7 @@ const
errCannotInferReturnType: "cannot infer the return type of the proc", errCannotInferReturnType: "cannot infer the return type of the proc",
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " & errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
"it is used as an operand to another routine and the types " & "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", errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target",
errUser: "$1", errUser: "$1",
warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]", warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]",
@ -377,7 +377,7 @@ const
warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]", warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]",
warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]", warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]",
warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]", warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]",
warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]", warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]",
warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]", warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]",
warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]", warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]",
warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]", warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]",
@ -420,7 +420,7 @@ const
"RedefinitionOfLabel", "UnknownSubstitutionX", "RedefinitionOfLabel", "UnknownSubstitutionX",
"LanguageXNotSupported", "FieldXNotSupported", "LanguageXNotSupported", "FieldXNotSupported",
"CommentXIgnored", "NilStmt", "CommentXIgnored", "NilStmt",
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap", "TypelessParam", "DifferentHeaps", "WriteToForeignHeap",
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent", "UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "Destructor", "LockLevel", "User"] "GcMem", "Destructor", "LockLevel", "User"]
@ -445,7 +445,7 @@ type
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
TNoteKinds* = set[TNoteKind] TNoteKinds* = set[TNoteKind]
TFileInfo*{.final.} = object TFileInfo* = object
fullPath: string # This is a canonical full filesystem path fullPath: string # This is a canonical full filesystem path
projPath*: string # This is relative to the project's root projPath*: string # This is relative to the project's root
shortName*: string # short name of the module shortName*: string # short name of the module
@ -460,9 +460,9 @@ type
# and parsed; usually 'nil' but is used # and parsed; usually 'nil' but is used
# for 'nimsuggest' # 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 # 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. # two int16 and an int32.
# On 64 bit and on 32 bit systems this is # On 64 bit and on 32 bit systems this is
# only 8 bytes. # only 8 bytes.
@ -495,7 +495,7 @@ proc toCChar*(c: char): string =
proc makeCString*(s: string): PRope = proc makeCString*(s: string): PRope =
# BUGFIX: We have to split long strings into many ropes. Otherwise # 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. # further information.
const const
MaxLineLength = 64 MaxLineLength = 64
@ -524,7 +524,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
if optEmbedOrigSrc in gGlobalOptions or true: if optEmbedOrigSrc in gGlobalOptions or true:
result.lines = @[] result.lines = @[]
proc fileInfoIdx*(filename: string): int32 = proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 =
var var
canon: string canon: string
pseudoPath = false pseudoPath = false
@ -541,11 +541,16 @@ proc fileInfoIdx*(filename: string): int32 =
if filenameToIndexTbl.hasKey(canon): if filenameToIndexTbl.hasKey(canon):
result = filenameToIndexTbl[canon] result = filenameToIndexTbl[canon]
else: else:
isKnownFile = false
result = fileInfos.len.int32 result = fileInfos.len.int32
fileInfos.add(newFileInfo(canon, if pseudoPath: filename fileInfos.add(newFileInfo(canon, if pseudoPath: filename
else: canon.shortenDir)) else: canon.shortenDir))
filenameToIndexTbl[canon] = result filenameToIndexTbl[canon] = result
proc fileInfoIdx*(filename: string): int32 =
var dummy: bool
result = fileInfoIdx(filename, dummy)
proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo = proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo =
result.fileIndex = fileInfoIdx result.fileIndex = fileInfoIdx
result.line = int16(line) result.line = int16(line)
@ -693,7 +698,9 @@ proc msgWriteln*(s: string) =
#if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return #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) if eStdErr in errorOutputs: writeln(stderr, s)
else: else:
if eStdOut in errorOutputs: writeln(stdout, s) if eStdOut in errorOutputs: writeln(stdout, s)
@ -717,7 +724,10 @@ type
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
template quit = template quit =
if defined(debug) or gVerbosity >= 3 or msg == errInternal: 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 quit 1
if msg >= fatalMin and msg <= fatalMax: if msg >= fatalMin and msg <= fatalMax:

View file

@ -9,9 +9,9 @@
when defined(gcc) and defined(windows): when defined(gcc) and defined(windows):
when defined(x86): when defined(x86):
{.link: "icons/nimrod.res".} {.link: "icons/nim.res".}
else: else:
{.link: "icons/nimrod_icon.o".} {.link: "icons/nim_icon.o".}
import import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
@ -61,6 +61,8 @@ proc handleCmdLine() =
if gCmd == cmdRun: if gCmd == cmdRun:
tccgen.run(commands.arguments) tccgen.run(commands.arguments)
if optRun in gGlobalOptions: if optRun in gGlobalOptions:
if gProjectName == "-":
gProjectFull = "stdinfile"
if gCmd == cmdCompileToJS: if gCmd == cmdCompileToJS:
var ex: string var ex: string
if options.outFile.len > 0: if options.outFile.len > 0:

View file

@ -33,7 +33,7 @@ proc `<.`(a, b: string): bool =
while true: while true:
let ii = parseInt(a, verA, i) let ii = parseInt(a, verA, i)
let jj = parseInt(b, verB, j) 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 ii <= 0 or jj <= 0: return jj > 0
if verA < verB: return true if verA < verB: return true
elif verA > verB: return false elif verA > verB: return false

View file

@ -11,10 +11,10 @@
import import
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer, llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
options, idents, wordrecg options, idents, wordrecg, strtabs
# ---------------- configuration file parser ----------------------------- # ---------------- 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) = proc ppGetTok(L: var TLexer, tok: var TToken) =
# simple filter # simple filter
@ -82,17 +82,17 @@ proc doElif(L: var TLexer, tok: var TToken) =
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) =
var nestedIfs = 0 var nestedIfs = 0
while true: while true:
if (tok.ident != nil) and (tok.ident.s == "@"): if tok.ident != nil and tok.ident.s == "@":
ppGetTok(L, tok) ppGetTok(L, tok)
case whichKeyword(tok.ident) case whichKeyword(tok.ident)
of wIf: of wIf:
inc(nestedIfs) inc(nestedIfs)
of wElse: of wElse:
if (dest == jdElseEndif) and (nestedIfs == 0): if dest == jdElseEndif and nestedIfs == 0:
doElse(L, tok) doElse(L, tok)
break break
of wElif: of wElif:
if (dest == jdElseEndif) and (nestedIfs == 0): if dest == jdElseEndif and nestedIfs == 0:
doElif(L, tok) doElif(L, tok)
break break
of wEnd: of wEnd:
@ -121,7 +121,8 @@ proc parseDirective(L: var TLexer, tok: var TToken) =
of wEnd: doEnd(L, tok) of wEnd: doEnd(L, tok)
of wWrite: of wWrite:
ppGetTok(L, tok) ppGetTok(L, tok)
msgs.msgWriteln(tokToStr(tok)) msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars,
{useEnvironment, useKey}))
ppGetTok(L, tok) ppGetTok(L, tok)
else: else:
case tok.ident.s.normalize case tok.ident.s.normalize
@ -157,7 +158,7 @@ proc checkSymbol(L: TLexer, tok: TToken) =
proc parseAssignment(L: var TLexer, tok: var TToken) = proc parseAssignment(L: var TLexer, tok: var TToken) =
if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id: if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id:
confTok(L, tok) # skip unnecessary prefix 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) checkSymbol(L, tok)
var s = tokToStr(tok) var s = tokToStr(tok)
confTok(L, tok) # skip symbol confTok(L, tok) # skip symbol
@ -178,9 +179,10 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
if tok.tokType == tkBracketRi: confTok(L, tok) if tok.tokType == tkBracketRi: confTok(L, tok)
else: lexMessage(L, errTokenExpected, "']'") else: lexMessage(L, errTokenExpected, "']'")
add(val, ']') 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, ':') if len(val) > 0: add(val, ':')
confTok(L, tok) # skip ':' or '=' confTok(L, tok) # skip ':' or '=' or '%'
checkSymbol(L, tok) checkSymbol(L, tok)
add(val, tokToStr(tok)) add(val, tokToStr(tok))
confTok(L, tok) # skip symbol confTok(L, tok) # skip symbol
@ -189,7 +191,11 @@ proc parseAssignment(L: var TLexer, tok: var TToken) =
checkSymbol(L, tok) checkSymbol(L, tok)
add(val, tokToStr(tok)) add(val, tokToStr(tok))
confTok(L, 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) = proc readConfigFile(filename: string) =
var var
@ -246,6 +252,11 @@ proc loadConfigs*(cfg: string) =
if gProjectName.len != 0: if gProjectName.len != 0:
# new project wide config file: # new project wide config file:
let projectConfig = changeFileExt(gProjectFull, "nim.cfg") var projectConfig = changeFileExt(gProjectFull, "nimcfg")
if fileExists(projectConfig): readConfigFile(projectConfig) if not fileExists(projectConfig):
else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg")) 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 # gc:markAndSweep
hint[XDeclaredButNotUsed]:off hint[XDeclaredButNotUsed]:off
path:"$projectPath/../.." path:"$projectPath/.."
path:"$lib/packages/docutils" path:"$lib/packages/docutils"
path:"$nim/compiler" path:"$nim/compiler"

View file

@ -87,8 +87,9 @@ proc action(cmd: string) =
i += skipWhile(cmd, seps, i) i += skipWhile(cmd, seps, i)
i += parseInt(cmd, col, i) i += parseInt(cmd, col, i)
var isKnownFile = true
if orig.len == 0: err() if orig.len == 0: err()
let dirtyIdx = orig.fileInfoIdx let dirtyIdx = orig.fileInfoIdx(isKnownFile)
if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile) if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile)
else: msgs.setDirtyFile(dirtyIdx, nil) else: msgs.setDirtyFile(dirtyIdx, nil)
@ -99,7 +100,10 @@ proc action(cmd: string) =
gTrackPos = newLineInfo(dirtyIdx, line, col) gTrackPos = newLineInfo(dirtyIdx, line, col)
#echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx
gErrorCounter = 0 gErrorCounter = 0
compileProject() if not isKnownFile:
compileProject(dirtyIdx)
else:
compileProject()
proc serve() = proc serve() =
# do not stop after the first error: # do not stop after the first error:
@ -116,13 +120,17 @@ proc serve() =
server.bindAddr(gPort, gAddress) server.bindAddr(gPort, gAddress)
var inp = "".TaintedString var inp = "".TaintedString
server.listen() server.listen()
var stdoutSocket = newSocket()
msgs.writelnHook = proc (line: string) =
stdoutSocket.send(line & "\c\L")
while true: while true:
var stdoutSocket = newSocket()
msgs.writelnHook = proc (line: string) =
stdoutSocket.send(line & "\c\L")
accept(server, stdoutSocket) accept(server, stdoutSocket)
stdoutSocket.readLine(inp) stdoutSocket.readLine(inp)
action inp.string action inp.string
stdoutSocket.send("\c\L") stdoutSocket.send("\c\L")
stdoutSocket.close() stdoutSocket.close()

View file

@ -283,7 +283,7 @@ when noTimeMachine:
var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir]) var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
discard p.waitForExit discard p.waitForExit
p.close p.close
except E_Base, EOS: except Exception:
discard discard
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =

View file

@ -198,8 +198,8 @@ proc isSigilLike(tok: TToken): bool {.inline.} =
proc isRightAssociative(tok: TToken): bool {.inline.} = proc isRightAssociative(tok: TToken): bool {.inline.} =
## Determines whether the token is right assocative. ## Determines whether the token is right assocative.
result = tok.tokType == tkOpr and (tok.ident.s[0] == '^' or result = tok.tokType == tkOpr and tok.ident.s[0] == '^'
(let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>')) # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>'))
proc getPrecedence(tok: TToken, strongSpaces: bool): int = proc getPrecedence(tok: TToken, strongSpaces: bool): int =
## Calculates the precedence of the given token. ## Calculates the precedence of the given token.
@ -1597,6 +1597,7 @@ proc parseEnum(p: var TParser): PNode =
optInd(p, result) optInd(p, result)
while true: while true:
var a = parseSymbol(p) var a = parseSymbol(p)
if a.kind == nkEmpty: return
if p.tok.indent >= 0 and p.tok.indent <= p.currInd: if p.tok.indent >= 0 and p.tok.indent <= p.currInd:
add(result, a) add(result, a)
break break

View file

@ -170,7 +170,11 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
openPasses(a, module) openPasses(a, module)
if stream == nil: if stream == nil:
let filename = fileIdx.toFullPathConsiderDirty 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: if s == nil:
rawMessage(errCannotOpenFile, filename) rawMessage(errCannotOpenFile, filename)
return 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: if arg != rs and aliases.isPartOf(rs, arg) == arYes:
ok = true ok = true
break break
# constraint not fullfilled: # constraint not fulfilled:
if not ok: return nil if not ok: return nil
of aqNoAlias: of aqNoAlias:
# it MUST not alias with any other param: # 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: if arg != rs and aliases.isPartOf(rs, arg) != arNo:
ok = false ok = false
break break
# constraint not fullfilled: # constraint not fulfilled:
if not ok: return nil if not ok: return nil
markUsed(n.info, s) markUsed(n.info, s)

View file

@ -138,7 +138,7 @@ const
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}), props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
(name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", (name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\", objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\",
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".",
props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}), props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}),
(name: "JS", parDir: "..", (name: "JS", parDir: "..",
dllFrmt: "lib$1.so", altDirSep: "/", 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) incl(sym.flags, sfProcvar)
if sym.typ != nil: incl(sym.typ.flags, tfThread) if sym.typ != nil: incl(sym.typ.flags, tfThread)
of wGcSafe: of wGcSafe:
if optThreadAnalysis in gGlobalOptions: noVal(it)
noVal(it) if sym.kind != skType: incl(sym.flags, sfThread)
if sym.kind != skType: incl(sym.flags, sfThread) if sym.typ != nil: incl(sym.typ.flags, tfGcSafe)
if sym.typ != nil: incl(sym.typ.flags, tfGcSafe) else: invalidPragma(it)
else: invalidPragma(it)
of wPacked: of wPacked:
noVal(it) noVal(it)
if sym.typ == nil: invalidPragma(it) if sym.typ == nil: invalidPragma(it)

View file

@ -666,7 +666,7 @@ proc newRodReader(modfilename: string, crc: TCrc32,
r.readerIndex = readerIndex r.readerIndex = readerIndex
r.filename = modfilename r.filename = modfilename
initIdTable(r.syms) 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: # is safe:
r.s = cast[cstring](r.memfile.mem) r.s = cast[cstring](r.memfile.mem)
if startsWith(r.s, "NIM:"): if startsWith(r.s, "NIM:"):

View file

@ -200,7 +200,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
return return
# we need no surrounding [] here because the type is in a line of its own # we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: internalError("encodeType: tyForward") 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: # can easily be disambiguated:
add(result, '[') add(result, '[')
encodeVInt(ord(t.kind), result) encodeVInt(ord(t.kind), result)

View file

@ -52,7 +52,7 @@
# Note that the left and right pointers are not needed for leaves. # Note that the left and right pointers are not needed for leaves.
# Leaves have relatively high memory overhead (~30 bytes on a 32 # 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 # 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. # To cache them they are inserted in a `cache` array.
import import

View file

@ -95,15 +95,6 @@ proc inferWithMetatype(c: PContext, formal: PType,
var commonTypeBegin = PType(kind: tyExpr) var commonTypeBegin = PType(kind: tyExpr)
proc isEmptyContainer(t: PType): bool =
case t.kind
of tyExpr, tyNil: result = true
of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty
of tySet, tySequence, tyOpenArray, tyVarargs:
result = t.sons[0].kind == tyEmpty
of tyGenericInst: result = isEmptyContainer(t.lastSon)
else: result = false
proc commonType*(x, y: PType): PType = proc commonType*(x, y: PType): PType =
# new type relation that is used for array constructors, # new type relation that is used for array constructors,
# if expressions, etc.: # if expressions, etc.:
@ -130,9 +121,11 @@ proc commonType*(x, y: PType): PType =
elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len: elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len:
var nt: PType var nt: PType
for i in 0.. <a.len: 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) 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 if not nt.isNil: result = nt
#elif b.sons[idx].kind == tyEmpty: return x #elif b.sons[idx].kind == tyEmpty: return x
elif a.kind == tyRange and b.kind == tyRange: elif a.kind == tyRange and b.kind == tyRange:

View file

@ -184,7 +184,7 @@ proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) =
of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt, 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)) internalError(c.info, "assignment requested for type: " & typeToString(t))
of tyDistinct, tyOrdinal, tyRange, of tyDistinct, tyOrdinal, tyRange,
tyGenericInst, tyFieldAccessor, tyStatic, tyVar: tyGenericInst, tyFieldAccessor, tyStatic, tyVar:

View file

@ -42,7 +42,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
errors: var CandidateErrors) = errors: var CandidateErrors) =
var o: TOverloadIter var o: TOverloadIter
var sym = initOverloadIter(o, c, headSymbol) var sym = initOverloadIter(o, c, headSymbol)
var symScope = o.lastOverloadScope let symScope = o.lastOverloadScope
var z: TCandidate var z: TCandidate
@ -56,6 +56,9 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode,
determineType(c, sym) determineType(c, sym)
initCandidate(c, z, sym, initialBinding, o.lastOverloadScope) initCandidate(c, z, sym, initialBinding, o.lastOverloadScope)
z.calleeSym = sym z.calleeSym = sym
#if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140:
# gDebug = true
matches(c, n, orig, z) matches(c, n, orig, z)
if errors != nil: if errors != nil:
errors.safeAdd(sym) 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 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 elif cmp == 0: alt = z # x is as good as the best so far
else: discard 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) # echo "Matches ", n.info, " ", typeToString(sym.typ)
# debug sym
# writeMatches(z) # writeMatches(z)
# for i in 1 .. <len(z.call):
# z.call[i].typ.debug
# quit 1
sym = nextOverloadIter(o, c, headSymbol) sym = nextOverloadIter(o, c, headSymbol)
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
@ -264,7 +271,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
instGenericConvertersArg(c, result, m) instGenericConvertersArg(c, result, m)
if result != nil: if result != nil:
# This almost exactly replicates the steps taken by the compiler during # 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 # type jugling, but it's the price to pay for consistency and correctness
result.typ = generateTypeInstance(c, m.bindings, arg.info, result.typ = generateTypeInstance(c, m.bindings, arg.info,
formal.skipTypes({tyCompositeTypeClass})) formal.skipTypes({tyCompositeTypeClass}))
@ -315,6 +322,8 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
var r = resolveOverloads(c, n, nOrig, filter, errors) var r = resolveOverloads(c, n, nOrig, filter, errors)
if r.state == csMatch: result = semResolvedCall(c, n, r) if r.state == csMatch: result = semResolvedCall(c, n, r)
else: else:
# get rid of the deref again for a better error message:
n.sons[1] = n.sons[1].sons[0]
notFoundError(c, n, errors) notFoundError(c, n, errors)
else: else:
notFoundError(c, n, errors) 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 = proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
result = newTypeS(tyFromExpr, c) result = newTypeS(tyFromExpr, c)
assert n != nil
result.n = n result.n = n
proc newTypeWithSons*(c: PContext, kind: TTypeKind, 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) = proc doDestructorStuff(c: PContext, s: PSym, n: PNode) =
var t = s.typ.sons[1].skipTypes({tyVar}) var t = s.typ.sons[1].skipTypes({tyVar})
if t.kind == tyGenericInvokation: if t.kind == tyGenericInvocation:
for i in 1 .. <t.sonsLen: for i in 1 .. <t.sonsLen:
if t.sons[i].kind != tyGenericParam: if t.sons[i].kind != tyGenericParam:
localError(n.info, errDestructorNotGenericEnough) 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) result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, n, s, flags) of skMacro: result = semMacroExpr(c, n, n, s, flags)
of skTemplate: result = semTemplateExpr(c, 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) markUsed(n.info, s)
styleCheckUse(n.info, s) styleCheckUse(n.info, s)
# if a proc accesses a global variable, it is not side effect free: # if a proc accesses a global variable, it is not side effect free:
if sfGlobal in s.flags: if sfGlobal in s.flags:
incl(c.p.owner.flags, sfSideEffect) incl(c.p.owner.flags, sfSideEffect)
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) result = newSymNode(s, n.info)
# We cannot check for access to outer vars for example because it's still # We cannot check for access to outer vars for example because it's still
# not sure the symbol really ends up being used: # 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 + var typ = skipTypes(n.sons[1].typ, abstractVarRange +
{tyTypeDesc, tyFieldAccessor}) {tyTypeDesc, tyFieldAccessor})
case typ.kind case typ.kind
of tySequence, tyString, tyOpenArray, tyVarargs: of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
n.typ = getSysType(tyInt) n.typ = getSysType(tyInt)
of tyArrayConstr, tyArray: of tyArrayConstr, tyArray:
n.typ = typ.sons[0] # indextype n.typ = typ.sons[0] # indextype
@ -445,25 +448,30 @@ proc changeType(n: PNode, newType: PType, check: bool) =
let tup = newType.skipTypes({tyGenericInst}) let tup = newType.skipTypes({tyGenericInst})
if tup.kind != tyTuple: if tup.kind != tyTuple:
internalError(n.info, "changeType: no tuple type for constructor") internalError(n.info, "changeType: no tuple type for constructor")
elif newType.n == nil: discard
elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr:
# named tuple?
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i].sons[0] var m = n.sons[i].sons[0]
if m.kind != nkSym: if m.kind != nkSym:
internalError(m.info, "changeType(): invalid tuple constr") internalError(m.info, "changeType(): invalid tuple constr")
return return
var f = getSymFromList(newType.n, m.sym.name) if tup.n != nil:
if f == nil: var f = getSymFromList(newType.n, m.sym.name)
internalError(m.info, "changeType(): invalid identifier") if f == nil:
return internalError(m.info, "changeType(): invalid identifier")
changeType(n.sons[i].sons[1], f.typ, check) return
changeType(n.sons[i].sons[1], f.typ, check)
else:
changeType(n.sons[i].sons[1], tup.sons[i], check)
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var m = n.sons[i] changeType(n.sons[i], tup.sons[i], check)
var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i]) when false:
addSon(a, newSymNode(newType.n.sons[i].sym)) var m = n.sons[i]
addSon(a, m) var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i])
changeType(m, tup.sons[i], check) addSon(a, newSymNode(newType.n.sons[i].sym))
addSon(a, m)
changeType(m, tup.sons[i], check)
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
if check: if check:
let value = n.intVal let value = n.intVal
@ -579,7 +587,8 @@ proc isAssignable(c: PContext, n: PNode): TAssignableResult =
result = parampatterns.isAssignable(c.p.owner, n) result = parampatterns.isAssignable(c.p.owner, n)
proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = proc newHiddenAddrTaken(c: PContext, n: PNode): PNode =
if n.kind == nkHiddenDeref: if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or
sfCompileToCpp in c.module.flags):
checkSonsLen(n, 1) checkSonsLen(n, 1)
result = n.sons[0] result = n.sons[0]
else: else:
@ -677,7 +686,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
# implicit statics. # implicit statics.
if n.len > 1: if n.len > 1:
for i in 1 .. <n.len: 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 break maybeLabelAsStatic
n.typ = newTypeWithSons(c, tyStatic, @[n.typ]) n.typ = newTypeWithSons(c, tyStatic, @[n.typ])
n.typ.flags.incl tfUnresolved n.typ.flags.incl tfUnresolved
@ -745,6 +756,9 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
else: else:
if callee.kind in skIterators and callee.id == c.p.owner.id: if callee.kind in skIterators and callee.id == c.p.owner.id:
localError(n.info, errRecursiveDependencyX, callee.name.s) localError(n.info, errRecursiveDependencyX, callee.name.s)
# 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 sfNoSideEffect notin callee.flags:
if {sfImportc, sfSideEffect} * callee.flags != {}: if {sfImportc, sfSideEffect} * callee.flags != {}:
incl(c.p.owner.flags, sfSideEffect) 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: if x.typ.kind == tyVar and x.kind == nkSym and x.sym.kind == skResult:
n.sons[0] = x # 'result[]' --> 'result' n.sons[0] = x # 'result[]' --> 'result'
n.sons[1] = takeImplicitAddr(c, ri) n.sons[1] = takeImplicitAddr(c, ri)
x.typ.flags.incl tfVarIsPtr
template resultTypeIsInferrable(typ: PType): expr = template resultTypeIsInferrable(typ: PType): expr =
typ.isMetaType and typ.kind != tyTypeDesc 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 if c.p.owner.kind notin {skMacro, skTemplate} and
c.p.resultSym != nil and c.p.resultSym.typ.isMetaType: 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) 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 # Preserve the magic symbol in order to be handled in evals.nim
internalAssert n.sons[0].sym.magic == mExpandToAst 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 result = n
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, 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) result = semDirectOp(c, n, flags)
proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType = 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, magicsys.getCompilerProc("FlowVar").typ)
addSonSkipIntLit(result, t) addSonSkipIntLit(result, t)
result = instGenericContainer(c, info, result, allowMetaTypes = false) 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) it.sons[0] = newSymNode(f)
e = fitNode(c, f.typ, e) e = fitNode(c, f.typ, e)
# small hack here in a nkObjConstr the ``nkExprColonExpr`` node can have # 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: if check != nil:
check.sons[0] = it.sons[0] check.sons[0] = it.sons[0]
it.add(check) it.add(check)
@ -1984,7 +2006,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if result.kind == nkSym: if result.kind == nkSym:
markIndirect(c, result.sym) markIndirect(c, result.sym)
# if isGenericRoutine(result.sym): # if isGenericRoutine(result.sym):
# localError(n.info, errInstantiateXExplicitely, s.name.s) # localError(n.info, errInstantiateXExplicitly, s.name.s)
of nkSym: of nkSym:
# because of the changed symbol binding, this does not mean that we # because of the changed symbol binding, this does not mean that we
# don't have to check the symbol for semantics here again! # 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 nkCurly: result = semSetConstr(c, n)
of nkBracket: result = semArrayConstr(c, n, flags) of nkBracket: result = semArrayConstr(c, n, flags)
of nkObjConstr: result = semObjConstr(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 nkDerefExpr: result = semDeref(c, n)
of nkAddr: of nkAddr:
result = n result = n

View file

@ -19,12 +19,13 @@ type
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
case n.kind case n.kind
of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
of nkIdent: of nkIdent, nkSym:
result = n result = n
let ident = considerQuotedIdent(n)
var L = sonsLen(forLoop) var L = sonsLen(forLoop)
if c.replaceByFieldName: 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 let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
@ -32,7 +33,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
return return
# other fields: # other fields:
for i in ord(c.replaceByFieldName)..L-3: 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 call = forLoop.sons[L-2]
var tupl = call.sons[i+1-ord(c.replaceByFieldName)] var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
if c.field.isNil: if c.field.isNil:
@ -155,7 +156,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
dec(c.p.nestedLoopCounter) dec(c.p.nestedLoopCounter)
# for TR macros this 'while true: ...; break' loop is pretty bad, so # for TR macros this 'while true: ...; break' loop is pretty bad, so
# we avoid it now if we can: # we avoid it now if we can:
if hasSonWith(stmts, nkBreakStmt): if containsNode(stmts, {nkBreakStmt}):
var b = newNodeI(nkBreakStmt, n.info) var b = newNodeI(nkBreakStmt, n.info)
b.add(ast.emptyNode) b.add(ast.emptyNode)
stmts.add(b) stmts.add(b)

View file

@ -665,8 +665,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mLow: of mLow:
result = newIntNodeT(firstOrd(n.sons[1].typ), n) result = newIntNodeT(firstOrd(n.sons[1].typ), n)
of mHigh: of mHigh:
if skipTypes(n.sons[1].typ, abstractVar).kind notin if skipTypes(n.sons[1].typ, abstractVar).kind notin
{tyOpenArray, tyVarargs, tySequence, tyString}: {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
else: else:
var a = getArrayConstr(m, n.sons[1]) var a = getArrayConstr(m, n.sons[1])

View file

@ -243,7 +243,7 @@ proc semGenericStmt(c: PContext, n: PNode,
elif fn.kind == nkDotExpr: elif fn.kind == nkDotExpr:
result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext) result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext)
first = 1 first = 1
# Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)' # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)'
# in threads.nim: the subtle preprocessing here binds 'globalsSlot' which # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which
# is not exported and yet the generic 'threadProcWrapper' works correctly. # is not exported and yet the generic 'threadProcWrapper' works correctly.
let flags = if mixinContext: flags+{withinMixin} else: flags 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: elif t.kind == tyGenericParam:
localError(a.info, errCannotInstantiateX, q.name.s) localError(a.info, errCannotInstantiateX, q.name.s)
t = errorType(c) t = errorType(c)
elif t.kind == tyGenericInvokation: elif t.kind == tyGenericInvocation:
#t = instGenericContainer(c, a, t) #t = instGenericContainer(c, a, t)
t = generateTypeInstance(c, pt, a, t) t = generateTypeInstance(c, pt, a, t)
#t = ReplaceTypeVarsT(cl, t) #t = ReplaceTypeVarsT(cl, t)
@ -77,11 +77,12 @@ proc removeDefaultParamValues(n: PNode) =
proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) = proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) =
# we need to create a fresh set of gensym'ed symbols: # we need to create a fresh set of gensym'ed symbols:
if n.kind == nkSym and sfGenSym in n.sym.flags: 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: if x == nil:
x = copySym(n.sym, false) x = copySym(s, false)
x.owner = owner x.owner = owner
idTablePut(symMap, n.sym, x) idTablePut(symMap, s, x)
n.sym = x n.sym = x
else: else:
for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap) 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) 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: if n.sons[bodyPos].kind != nkEmpty:
inc c.inGenericInst inc c.inGenericInst
# add it here, so that recursive generic procs are possible: # add it here, so that recursive generic procs are possible:
var b = n.sons[bodyPos] var b = n.sons[bodyPos]
var symMap: TIdTable var symMap: TIdTable
initIdTable symMap 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) freshGenSyms(b, result, symMap)
b = semProcBody(c, b) b = semProcBody(c, b)
b = hloBody(c, b) b = hloBody(c, b)
@ -122,7 +128,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
openScope(c) openScope(c)
var n = oldPrc.ast var n = oldPrc.ast
n.sons[bodyPos] = copyTree(s.getBody) n.sons[bodyPos] = copyTree(s.getBody)
instantiateBody(c, n, oldPrc) instantiateBody(c, n, nil, oldPrc)
closeScope(c) closeScope(c)
popInfoContext() popInfoContext()
@ -169,17 +175,27 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
result.n = originalParams.shallowCopy result.n = originalParams.shallowCopy
for i in 1 .. <result.len: 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]) result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
propagateToOwner(result, result.sons[i]) propagateToOwner(result, result.sons[i])
let param = replaceTypeVarsN(cl, originalParams[i]) internalAssert originalParams[i].kind == nkSym
result.n.sons[i] = param when true:
if param.kind == nkSym: let oldParam = originalParams[i].sym
# XXX: this won't be true for void params let param = copySym(oldParam)
# implement pass-through of void params and param.owner = prc
# the "sort by distance to point" container 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 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.sons[0] = replaceTypeVarsT(cl, result.sons[0])
result.n.sons[0] = originalParams[0].copyTree 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) pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
if isNil(n.sons[bodyPos]): if isNil(n.sons[bodyPos]):
n.sons[bodyPos] = copyTree(fn.getBody) n.sons[bodyPos] = copyTree(fn.getBody)
instantiateBody(c, n, result) instantiateBody(c, n, fn.typ.n, result)
sideEffectsCheck(c, result) sideEffectsCheck(c, result)
paramsTypeCheck(c, result.typ) paramsTypeCheck(c, result.typ)
else: else:

View file

@ -23,7 +23,7 @@ import
# Predefined effects: # Predefined effects:
# io, time (time dependent), gc (performs GC'ed allocation), exceptions, # io, time (time dependent), gc (performs GC'ed allocation), exceptions,
# side effect (accesses global), store (stores into *type*), # 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, # load (loads from *type*), recursive (recursive call), unsafe,
# endless (has endless loops), --> user effects are defined over *patterns* # endless (has endless loops), --> user effects are defined over *patterns*
# --> a TR macro can annotate the proc with user defined annotations # --> a TR macro can annotate the proc with user defined annotations
@ -194,6 +194,9 @@ proc warnAboutGcUnsafe(n: PNode) =
#assert false #assert false
message(n.info, warnGcUnsafe, renderTree(n)) message(n.info, warnGcUnsafe, renderTree(n))
template markGcUnsafe(a: PEffects) =
a.gcUnsafe = true
proc useVar(a: PEffects, n: PNode) = proc useVar(a: PEffects, n: PNode) =
let s = n.sym let s = n.sym
if isLocalVar(a, s): 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 if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and
tfGcSafe notin s.typ.flags: tfGcSafe notin s.typ.flags:
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
a.gcUnsafe = true markGcUnsafe(a)
type type
TIntersection = seq[tuple[id, count: int]] # a simple count table TIntersection = seq[tuple[id, count: int]] # a simple count table
@ -230,7 +233,7 @@ proc getEbase(): PType =
proc excType(n: PNode): PType = proc excType(n: PNode): PType =
# reraise is like raising E_Base: # reraise is like raising E_Base:
let t = if n.kind == nkEmpty: getEbase() else: n.typ let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ
result = skipTypes(t, skipPtrs) result = skipTypes(t, skipPtrs)
proc createRaise(n: PNode): PNode = 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 notGcSafe(s.typ) and sfImportc notin s.flags:
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true markGcUnsafe(tracked)
mergeLockLevels(tracked, n, s.getLockLevel) mergeLockLevels(tracked, n, s.getLockLevel)
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = 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: # assume GcUnsafe unless in its type; 'forward' does not matter:
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner): if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true markGcUnsafe(tracked)
else: else:
mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n)
if notGcSafe(op): if notGcSafe(op):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
tracked.gcUnsafe = true markGcUnsafe(tracked)
notNilCheck(tracked, n, paramType) notNilCheck(tracked, n, paramType)
proc breaksBlock(n: PNode): bool = proc breaksBlock(n: PNode): bool =
@ -656,7 +659,7 @@ proc track(tracked: PEffects, n: PNode) =
# and it's not a recursive call: # and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner): if not (a.kind == nkSym and a.sym == tracked.owner):
warnAboutGcUnsafe(n) warnAboutGcUnsafe(n)
tracked.gcUnsafe = true markGcUnsafe(tracked)
for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i)) for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i))
if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}: if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}:
# may not look like an assignment, but it is: # may not look like an assignment, but it is:
@ -849,19 +852,20 @@ proc trackProc*(s: PSym, body: PNode) =
# after the check, use the formal spec: # after the check, use the formal spec:
effects.sons[tagEffects] = tagsSpec effects.sons[tagEffects] = tagsSpec
if optThreadAnalysis in gGlobalOptions: if sfThread in s.flags and t.gcUnsafe:
if sfThread in s.flags and t.gcUnsafe: if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
if optThreads in gGlobalOptions: localError(s.info, "'$1' is not GC-safe" % s.name.s)
localError(s.info, "'$1' is not GC-safe" % s.name.s) else:
else: localError(s.info, warnGcUnsafe2, s.name.s)
localError(s.info, warnGcUnsafe2, s.name.s) if not t.gcUnsafe:
if not t.gcUnsafe: s.typ.flags.incl tfGcSafe s.typ.flags.incl tfGcSafe
if s.typ.lockLevel == UnspecifiedLockLevel: if s.typ.lockLevel == UnspecifiedLockLevel:
s.typ.lockLevel = t.maxLockLevel s.typ.lockLevel = t.maxLockLevel
elif t.maxLockLevel > s.typ.lockLevel: elif t.maxLockLevel > s.typ.lockLevel:
localError(s.info, #localError(s.info,
"declared lock level is $1, but real lock level is $2" % message(s.info, warnLockLevel,
[$s.typ.lockLevel, $t.maxLockLevel]) "declared lock level is $1, but real lock level is $2" %
[$s.typ.lockLevel, $t.maxLockLevel])
proc trackTopLevelStmt*(module: PSym; n: PNode) = proc trackTopLevelStmt*(module: PSym; n: PNode) =
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,

View file

@ -359,13 +359,17 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
var def: PNode var def: PNode
if a.sons[length-1].kind != nkEmpty: if a.sons[length-1].kind != nkEmpty:
def = semExprWithType(c, a.sons[length-1], {efAllowDestructor}) def = semExprWithType(c, a.sons[length-1], {efAllowDestructor})
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 != nil:
if typ.isMetaType: if typ.isMetaType:
def = inferWithMetatype(c, typ, def) def = inferWithMetatype(c, typ, def)
typ = def.typ typ = def.typ
else: else:
# BUGFIX: ``fitNode`` is needed here! # 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) def = fitNode(c, typ, def)
#changeType(def.skipConv, typ, check=true) #changeType(def.skipConv, typ, check=true)
else: else:
@ -666,8 +670,8 @@ proc checkForMetaFields(n: PNode) =
let t = n.sym.typ let t = n.sym.typ
case t.kind case t.kind
of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef, of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef,
tyProc, tyGenericInvokation, tyGenericInst: tyProc, tyGenericInvocation, tyGenericInst:
let start = ord(t.kind in {tyGenericInvokation, tyGenericInst}) let start = ord(t.kind in {tyGenericInvocation, tyGenericInst})
for i in start .. <t.sons.len: for i in start .. <t.sons.len:
checkMeta(t.sons[i]) checkMeta(t.sons[i])
else: else:
@ -756,7 +760,8 @@ proc lookupMacro(c: PContext, n: PNode): PSym =
else: else:
result = searchInScopes(c, considerQuotedIdent(n), {skMacro, skTemplate}) 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] var n = prc.sons[pragmasPos]
if n == nil or n.kind == nkEmpty: return if n == nil or n.kind == nkEmpty: return
for i in countup(0, <n.len): 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(it.sons[1])
x.add(prc) x.add(prc)
# recursion assures that this works for multiple macro annotations too: # recursion assures that this works for multiple macro annotations too:
return semStmt(c, x) 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 = proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
# XXX semProcAux should be good enough for this now, we will eventually # XXX semProcAux should be good enough for this now, we will eventually
# remove semLambda # remove semLambda
result = semProcAnnotation(c, n) result = semProcAnnotation(c, n, lambdaPragmas)
if result != nil: return result if result != nil: return result
result = n result = n
checkSonsLen(n, bodyPos + 1) 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: # we have a list of implicit type parameters:
n.sons[genericParamsPos] = gp n.sons[genericParamsPos] = gp
else: else:
s.typ = newTypeS(tyProc, c) s.typ = newProcType(c, n.info)
rawAddSon(s.typ, nil)
if n.sons[pragmasPos].kind != nkEmpty: if n.sons[pragmasPos].kind != nkEmpty:
pragma(c, s, n.sons[pragmasPos], lambdaPragmas) pragma(c, s, n.sons[pragmasPos], lambdaPragmas)
s.options = gOptions 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): if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags):
pushProcCon(c, s) pushProcCon(c, s)
addResult(c, s.typ.sons[0], n.info, skProc) addResult(c, s.typ.sons[0], n.info, skProc)
addResultNode(c, n)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, s) n.sons[bodyPos] = transformBody(c.module, semBody, s)
addResultNode(c, n)
popProcCon(c) popProcCon(c)
elif efOperand notin flags: elif efOperand notin flags:
localError(n.info, errGenericLambdaNotAllowed) localError(n.info, errGenericLambdaNotAllowed)
@ -842,6 +852,13 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode =
popOwner() popOwner()
result.typ = s.typ 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 = proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
var n = n var n = n
@ -857,9 +874,9 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
addParams(c, n.typ.n, skProc) addParams(c, n.typ.n, skProc)
pushProcCon(c, s) pushProcCon(c, s)
addResult(c, n.typ.sons[0], n.info, skProc) addResult(c, n.typ.sons[0], n.info, skProc)
addResultNode(c, n)
let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym) n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym)
addResultNode(c, n)
popProcCon(c) popProcCon(c)
popOwner() popOwner()
closeScope(c) 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) var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst)
while true: while true:
if t.kind == tyGenericBody: t = t.lastSon 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 else: break
if t.kind in {tyObject, tyDistinct, tyEnum}: if t.kind in {tyObject, tyDistinct, tyEnum}:
if t.deepCopy.isNil: t.deepCopy = s if t.deepCopy.isNil: t.deepCopy = s
@ -936,7 +953,7 @@ proc isForwardDecl(s: PSym): bool =
proc semProcAux(c: PContext, n: PNode, kind: TSymKind, proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
validPragmas: TSpecialWords, validPragmas: TSpecialWords,
phase = stepRegisterSymbol): PNode = phase = stepRegisterSymbol): PNode =
result = semProcAnnotation(c, n) result = semProcAnnotation(c, n, validPragmas)
if result != nil: return result if result != nil: return result
result = n result = n
checkSonsLen(n, bodyPos + 1) checkSonsLen(n, bodyPos + 1)
@ -991,8 +1008,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
# check for semantics again: # check for semantics again:
# semParamList(c, n.sons[ParamsPos], nil, s) # semParamList(c, n.sons[ParamsPos], nil, s)
else: else:
s.typ = newTypeS(tyProc, c) s.typ = newProcType(c, n.info)
rawAddSon(s.typ, nil)
if n.sons[patternPos].kind != nkEmpty: if n.sons[patternPos].kind != nkEmpty:
n.sons[patternPos] = semPattern(c, n.sons[patternPos]) n.sons[patternPos] = semPattern(c, n.sons[patternPos])
if s.kind in skIterators: if s.kind in skIterators:

View file

@ -436,7 +436,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode =
of nkEmpty, nkSym..nkNilLit: of nkEmpty, nkSym..nkNilLit:
discard discard
else: 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 # so we use the generic code for nkDotExpr too
if n.kind == nkDotExpr or n.kind == nkAccQuoted: if n.kind == nkDotExpr or n.kind == nkAccQuoted:
let s = qualifiedLookUp(c.c, n, {}) let s = qualifiedLookUp(c.c, n, {})
@ -494,7 +494,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
semParamList(c, n.sons[paramsPos], gp, s) semParamList(c, n.sons[paramsPos], gp, s)
# a template's parameters are not gensym'ed even if that was originally the # 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 # 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: for i in 1 .. s.typ.n.len-1:
s.typ.n.sons[i].sym.flags.excl sfGenSym s.typ.n.sons[i].sym.flags.excl sfGenSym
if sonsLen(gp) > 0: if sonsLen(gp) > 0:
@ -640,7 +640,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
result.sons[i] = semPatternBody(c, n.sons[i]) result.sons[i] = semPatternBody(c, n.sons[i])
else: 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 # so we use the generic code for nkDotExpr too
case n.kind case n.kind
of nkDotExpr, nkAccQuoted: of nkDotExpr, nkAccQuoted:

View file

@ -332,10 +332,15 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
if result.typ.kind != tyGenericParam: if result.typ.kind != tyGenericParam:
# XXX get rid of this hack! # XXX get rid of this hack!
var oldInfo = n.info var oldInfo = n.info
when defined(useNodeIds):
let oldId = n.id
reset(n[]) reset(n[])
when defined(useNodeIds):
n.id = oldId
n.kind = nkSym n.kind = nkSym
n.sym = result n.sym = result
n.info = oldInfo n.info = oldInfo
n.typ = result.typ
else: else:
localError(n.info, errIdentifierExpected) localError(n.info, errIdentifierExpected)
result = errorSym(c, n) result = errorSym(c, n)
@ -447,6 +452,7 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode,
proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
covered: var BiggestInt) = covered: var BiggestInt) =
for i in countup(0, sonsLen(branch) - 2): for i in countup(0, sonsLen(branch) - 2):
var b = branch.sons[i] var b = branch.sons[i]
if b.kind == nkRange: if b.kind == nkRange:
@ -456,8 +462,11 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
else: else:
# constant sets and arrays are allowed: # constant sets and arrays are allowed:
var r = semConstExpr(c, b) var r = semConstExpr(c, b)
# for ``{}`` we want to trigger the type mismatch in ``fitNode``: if r.kind in {nkCurly, nkBracket} and len(r) == 0 and sonsLen(branch)==2:
if r.kind notin {nkCurly, nkBracket} or len(r) == 0: # discarding ``{}`` and ``[]`` branches silently
delSon(branch, 0)
return
elif r.kind notin {nkCurly, nkBracket} or len(r) == 0:
checkMinSonsLen(t, 1) checkMinSonsLen(t, 1)
branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r)) branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r))
inc(covered) inc(covered)
@ -609,9 +618,9 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
inc(pos) inc(pos)
else: internalError(n.info, "addInheritedFieldsAux()") else: internalError(n.info, "addInheritedFieldsAux()")
proc skipGenericInvokation(t: PType): PType {.inline.} = proc skipGenericInvocation(t: PType): PType {.inline.} =
result = t result = t
if result.kind == tyGenericInvokation: if result.kind == tyGenericInvocation:
result = result.sons[0] result = result.sons[0]
if result.kind == tyGenericBody: if result.kind == tyGenericBody:
result = lastSon(result) result = lastSon(result)
@ -620,7 +629,7 @@ proc addInheritedFields(c: PContext, check: var IntSet, pos: var int,
obj: PType) = obj: PType) =
assert obj.kind == tyObject assert obj.kind == tyObject
if (sonsLen(obj) > 0) and (obj.sons[0] != nil): if (sonsLen(obj) > 0) and (obj.sons[0] != nil):
addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvokation) addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvocation)
addInheritedFieldsAux(c, check, pos, obj.n) addInheritedFieldsAux(c, check, pos, obj.n)
proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
@ -632,7 +641,7 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
checkSonsLen(n, 3) 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) base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs)
var concreteBase = skipGenericInvokation(base).skipTypes(skipPtrs) var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs)
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
addInheritedFields(c, check, pos, concreteBase) addInheritedFields(c, check, pos, concreteBase)
else: else:
@ -672,8 +681,9 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
elif param.typ.kind == tyTypeDesc: elif param.typ.kind == tyTypeDesc:
addDecl(c, param) addDecl(c, param)
else: else:
# within a macro, every param has the type PNimrodNode! # within a macro, every param has the type NimNode!
let nn = getSysSym"PNimrodNode" let nn = if getCompilerProc("NimNode") != nil: getSysSym"NimNode"
else: getSysSym"PNimrodNode"
var a = copySym(param) var a = copySym(param)
a.typ = nn.typ a.typ = nn.typ
addDecl(c, a) addDecl(c, a)
@ -777,13 +787,14 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
result = paramType result = paramType
of tyGenericBody: of tyGenericBody:
result = newTypeS(tyGenericInvokation, c) result = newTypeS(tyGenericInvocation, c)
result.rawAddSon(paramType) result.rawAddSon(paramType)
for i in 0 .. paramType.sonsLen - 2: for i in 0 .. paramType.sonsLen - 2:
let dummyType = if paramType.sons[i].kind == tyStatic: tyUnknown if paramType.sons[i].kind == tyStatic:
else: tyAnything result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnknown'
result.rawAddSon newTypeS(dummyType, c) else:
result.rawAddSon newTypeS(tyAnything, c)
if paramType.lastSon.kind == tyUserTypeClass: if paramType.lastSon.kind == tyUserTypeClass:
result.kind = tyUserTypeClassInst result.kind = tyUserTypeClassInst
@ -822,7 +833,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
result = liftBody result = liftBody
result.shouldHaveMeta result.shouldHaveMeta
of tyGenericInvokation: of tyGenericInvocation:
for i in 1 .. <paramType.sonsLen: for i in 1 .. <paramType.sonsLen:
let lifted = liftingWalk(paramType.sons[i]) let lifted = liftingWalk(paramType.sons[i])
if lifted != nil: paramType.sons[i] = lifted if lifted != nil: paramType.sons[i] = lifted
@ -856,25 +867,25 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
else: else:
result = semTypeNode(c, n, nil) result = semTypeNode(c, n, nil)
proc semProcTypeNode(c: PContext, n, genericParams: PNode, proc newProcType(c: PContext; info: TLineInfo; prev: PType = nil): PType =
prev: PType, kind: TSymKind; isType=false): PType =
# for historical reasons (code grows) this is invoked for parameter
# lists too and then 'isType' is false.
var
res: PNode
cl: IntSet
checkMinSonsLen(n, 1)
result = newOrPrevType(tyProc, prev, c) result = newOrPrevType(tyProc, prev, c)
result.callConv = lastOptionEntry(c).defaultCC result.callConv = lastOptionEntry(c).defaultCC
result.n = newNodeI(nkFormalParams, n.info) result.n = newNodeI(nkFormalParams, info)
if genericParams != nil and sonsLen(genericParams) == 0:
cl = initIntSet()
rawAddSon(result, nil) # return type rawAddSon(result, nil) # return type
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because # 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 # the effects are now stored in there too ... this is a bit hacky, but as
# usual we desperately try to save memory: # usual we desperately try to save memory:
res = newNodeI(nkEffectList, n.info) addSon(result.n, newNodeI(nkEffectList, info))
addSon(result.n, res)
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 cl: IntSet
checkMinSonsLen(n, 1)
result = newProcType(c, n.info, prev)
if genericParams != nil and sonsLen(genericParams) == 0:
cl = initIntSet()
var check = initIntSet() var check = initIntSet()
var counter = 0 var counter = 0
for i in countup(1, n.len - 1): for i in countup(1, n.len - 1):
@ -899,7 +910,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if hasDefault: if hasDefault:
def = semExprWithType(c, a.sons[length-1]) def = semExprWithType(c, a.sons[length-1])
# check type compability between def.typ and typ: # check type compatibility between def.typ and typ:
if typ == nil: if typ == nil:
typ = def.typ typ = def.typ
elif def != nil: elif def != nil:
@ -911,6 +922,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if not hasType and not hasDefault: if not hasType and not hasDefault:
if isType: localError(a.info, "':' expected") if isType: localError(a.info, "':' expected")
let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything
if tdef == tyAnything:
message(a.info, warnTypelessParam, renderTree(n))
typ = newTypeS(tdef, c) typ = newTypeS(tdef, c)
if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue
@ -956,7 +969,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# we don't need to change the return type to iter[T] # we don't need to change the return type to iter[T]
if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r]) if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r])
result.sons[0] = r result.sons[0] = r
res.typ = r result.n.typ = r
if genericParams != nil: if genericParams != nil:
for n in genericParams: for n in genericParams:
@ -988,7 +1001,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
closeScope(c) closeScope(c)
dec(c.p.nestedBlockCounter) dec(c.p.nestedBlockCounter)
proc semGenericParamInInvokation(c: PContext, n: PNode): PType = proc semGenericParamInInvocation(c: PContext, n: PNode): PType =
result = semTypeNode(c, n, nil) result = semTypeNode(c, n, nil)
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
@ -1001,7 +1014,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody: if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody:
t = t.base t = t.base
result = newOrPrevType(tyGenericInvokation, prev, c) result = newOrPrevType(tyGenericInvocation, prev, c)
addSonSkipIntLit(result, t) addSonSkipIntLit(result, t)
template addToResult(typ) = template addToResult(typ) =
@ -1012,7 +1025,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if t.kind == tyForward: if t.kind == tyForward:
for i in countup(1, sonsLen(n)-1): for i in countup(1, sonsLen(n)-1):
var elem = semGenericParamInInvokation(c, n.sons[i]) var elem = semGenericParamInInvocation(c, n.sons[i])
addToResult(elem) addToResult(elem)
return return
elif t.kind != tyGenericBody: elif t.kind != tyGenericBody:
@ -1132,7 +1145,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
case n.len case n.len
of 3: of 3:
result = semTypeNode(c, n.sons[1], prev) 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 = freshType(result, prev)
result.flags.incl(tfNotNil) result.flags.incl(tfNotNil)
else: else:
@ -1175,11 +1189,12 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
var typeExpr = semExpr(c, n) var typeExpr = semExpr(c, n)
if typeExpr.typ.kind != tyTypeDesc: if typeExpr.typ.kind != tyTypeDesc:
localError(n.info, errTypeExpected) localError(n.info, errTypeExpected)
return errorType(c) result = errorType(c)
result = typeExpr.typ.base else:
if result.isMetaType: result = typeExpr.typ.base
var preprocessed = semGenericStmt(c, n) if result.isMetaType:
return makeTypeFromExpr(c, preprocessed) var preprocessed = semGenericStmt(c, n)
result = makeTypeFromExpr(c, preprocessed.copyTree)
of nkIdent, nkAccQuoted: of nkIdent, nkAccQuoted:
var s = semTypeIdent(c, n) var s = semTypeIdent(c, n)
if s.typ == nil: if s.typ == nil:
@ -1250,6 +1265,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
else: else:
localError(n.info, errTypeExpected) localError(n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c) result = newOrPrevType(tyError, prev, c)
n.typ = result
proc setMagicType(m: PSym, kind: TTypeKind, size: int) = proc setMagicType(m: PSym, kind: TTypeKind, size: int) =
m.typ.kind = kind m.typ.kind = kind

View file

@ -61,7 +61,7 @@ proc searchInstTypes*(key: PType): PType =
if inst.sons.len < key.sons.len: if inst.sons.len < key.sons.len:
# XXX: This happens for prematurely cached # XXX: This happens for prematurely cached
# types such as TChannel[empty]. Why? # types such as TChannel[empty]. Why?
# See the notes for PActor in handleGenericInvokation # See the notes for PActor in handleGenericInvocation
return return
block matchType: block matchType:
for j in 1 .. high(key.sons): for j in 1 .. high(key.sons):
@ -223,7 +223,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
result = errorType(cl.c) result = errorType(cl.c)
# In order to prevent endless recursions, we must remember # In order to prevent endless recursions, we must remember
# this bad lookup and replace it with errorType everywhere. # 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) idTablePut(cl.typeMap, t, result)
elif result.kind == tyGenericParam and not cl.allowMetaTypes: elif result.kind == tyGenericParam and not cl.allowMetaTypes:
internalError(cl.info, "substitution with generic parameter") internalError(cl.info, "substitution with generic parameter")
@ -234,8 +234,8 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
result.flags.incl tfFromGeneric result.flags.incl tfFromGeneric
result.flags.excl tfInstClearedFlags result.flags.excl tfInstClearedFlags
proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# tyGenericInvokation[A, tyGenericInvokation[A, B]] # tyGenericInvocation[A, tyGenericInvocation[A, B]]
# is difficult to handle: # is difficult to handle:
var body = t.sons[0] var body = t.sons[0]
if body.kind != tyGenericBody: internalError(cl.info, "no generic body") if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
@ -245,7 +245,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
result = PType(idTableGet(cl.localCache, t)) result = PType(idTableGet(cl.localCache, t))
else: else:
result = searchInstTypes(t) 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): for i in countup(1, sonsLen(t) - 1):
var x = t.sons[i] var x = t.sons[i]
if x.kind == tyGenericParam: if x.kind == tyGenericParam:
@ -260,7 +260,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
if header != t: if header != t:
# search again after first pass: # search again after first pass:
result = searchInstTypes(header) result = searchInstTypes(header)
if result != nil: return if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return
else: else:
header = instCopyType(cl, t) header = instCopyType(cl, t)
@ -278,7 +278,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType =
for i in countup(1, sonsLen(t) - 1): for i in countup(1, sonsLen(t) - 1):
var x = replaceTypeVarsT(cl, t.sons[i]) var x = replaceTypeVarsT(cl, t.sons[i])
assert x.kind != tyGenericInvokation assert x.kind != tyGenericInvocation
header.sons[i] = x header.sons[i] = x
propagateToOwner(header, x) propagateToOwner(header, x)
idTablePut(cl.typeMap, body.sons[i-1], 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 #newbody.callConv = body.callConv
# This type may be a generic alias and we want to resolve it here. # This type may be a generic alias and we want to resolve it here.
# One step is enough, because the recursive nature of # One step is enough, because the recursive nature of
# handleGenericInvokation will handle the alias-to-alias-to-alias case # handleGenericInvocation will handle the alias-to-alias-to-alias case
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
rawAddSon(result, newbody) rawAddSon(result, newbody)
checkPartialConstructedType(cl.info, newbody) checkPartialConstructedType(cl.info, newbody)
@ -359,8 +359,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
if lookup != nil: return lookup if lookup != nil: return lookup
case t.kind case t.kind
of tyGenericInvokation: of tyGenericInvocation:
result = handleGenericInvokation(cl, t) result = handleGenericInvocation(cl, t)
of tyGenericBody: of tyGenericBody:
localError(cl.info, errCannotInstantiateX, typeToString(t)) localError(cl.info, errCannotInstantiateX, typeToString(t))
@ -369,6 +369,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
of tyFromExpr: of tyFromExpr:
if cl.allowMetaTypes: return if cl.allowMetaTypes: return
assert t.n.typ != t
var n = prepareNode(cl, t.n) var n = prepareNode(cl, t.n)
n = cl.c.semConstExpr(cl.c, n) n = cl.c.semConstExpr(cl.c, n)
if n.typ.kind == tyTypeDesc: if n.typ.kind == tyTypeDesc:
@ -389,9 +390,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
else: else:
result = n.typ result = n.typ
of tyInt: of tyInt, tyFloat:
result = skipIntLit(t) result = skipIntLit(t)
# XXX now there are also float literals
of tyTypeDesc: of tyTypeDesc:
let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t) 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) parseopt.next(p)
case p.kind case p.kind
of cmdEnd: break 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: of cmdArgument:
if processArgument(pass, p, argsCount): break if processArgument(pass, p, argsCount): break
if pass == passCmd2: if pass == passCmd2:

View file

@ -91,7 +91,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) =
initIdTable(c.bindings) initIdTable(c.bindings)
proc put(t: var TIdTable, key, val: PType) {.inline.} = 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, proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
binding: PNode, calleeScope = -1) = binding: PNode, calleeScope = -1) =
@ -153,12 +153,12 @@ proc sumGeneric(t: PType): int =
of tyVar: of tyVar:
# but do not make 'var T' more specific than 'T'! # but do not make 'var T' more specific than 'T'!
t = t.sons[0] t = t.sons[0]
of tyGenericInvokation, tyTuple: of tyGenericInvocation, tyTuple:
result = ord(t.kind == tyGenericInvokation) result = ord(t.kind == tyGenericInvocation)
for i in 0 .. <t.len: result += t.sons[i].sumGeneric for i in 0 .. <t.len: result += t.sons[i].sumGeneric
break break
of tyProc: of tyProc:
# proc matche proc better than 'stmt' to disambiguate 'spawn' # proc matches proc better than 'stmt' to disambiguate 'spawn'
return 1 return 1
of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break
else: return 0 else: return 0
@ -262,7 +262,7 @@ proc concreteType(c: TCandidate, t: PType): PType =
# example code that triggers it: # example code that triggers it:
# proc sort[T](cmp: proc(a, b: T): int = cmp) # proc sort[T](cmp: proc(a, b: T): int = cmp)
if result.kind != tyGenericParam: break if result.kind != tyGenericParam: break
of tyGenericInvokation: of tyGenericInvocation:
internalError("cannot resolve type: " & typeToString(t)) internalError("cannot resolve type: " & typeToString(t))
result = t result = t
else: else:
@ -418,7 +418,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags: if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
return isNone 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``! # noSideEffect implies ``tfThread``!
return isNone return isNone
elif f.flags * {tfIterator} != a.flags * {tfIterator}: elif f.flags * {tfIterator} != a.flags * {tfIterator}:
@ -461,7 +462,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate,
openScope(c) openScope(c)
inc c.inTypeClass inc c.inTypeClass
finally: defer:
dec c.inTypeClass dec c.inTypeClass
closeScope(c) closeScope(c)
@ -570,7 +571,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
assert(f != nil) assert(f != nil)
if f.kind == tyExpr: if f.kind == tyExpr:
put(c.bindings, f, aOrig) if aOrig != nil: put(c.bindings, f, aOrig)
return isGeneric return isGeneric
assert(aOrig != nil) assert(aOrig != nil)
@ -584,7 +585,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
if a.kind == tyGenericInst and if a.kind == tyGenericInst and
skipTypes(f, {tyVar}).kind notin { skipTypes(f, {tyVar}).kind notin {
tyGenericBody, tyGenericInvokation, tyGenericBody, tyGenericInvocation,
tyGenericInst, tyGenericParam} + tyTypeClasses: tyGenericInst, tyGenericParam} + tyTypeClasses:
return typeRel(c, f, lastSon(a)) 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) result = typeRel(c, ff, aa)
if result == isNone: return if result == isNone: return
if ff.kind == tyRange and result != isEqual: return isNone if ff.kind == tyRange and result != isEqual: return isNone
result = isGeneric result = isGeneric
# XXX See bug #2220. A[int] should match A[int] better than some generic X
else: else:
result = typeRel(c, lastSon(f), a) 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) let ff = lastSon(f)
if ff != nil: result = typeRel(c, ff, a) if ff != nil: result = typeRel(c, ff, a)
of tyGenericInvokation: of tyGenericInvocation:
var x = a.skipGenericAlias var x = a.skipGenericAlias
if x.kind == tyGenericInvokation or f.sons[0].kind != tyGenericBody: if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody:
#InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation") #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation")
# simply no match for now: # simply no match for now:
discard discard
elif x.kind == tyGenericInst and 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: # we steal the generic parameters from the tyGenericBody:
for i in countup(1, sonsLen(f) - 1): for i in countup(1, sonsLen(f) - 1):
var x = PType(idTableGet(c.bindings, f.sons[0].sons[i - 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!") internalError("wrong instantiated type!")
put(c.bindings, f.sons[i], x) 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) if result != isNone: put(c.bindings, f, aOrig)
else: else:
result = isNone 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: else:
result = typeRel(c, prev, aOrig) # XXX endless recursion?
#result = typeRel(c, prev, aOrig)
result = isNone
of tyTypeDesc: of tyTypeDesc:
var prev = PType(idTableGet(c.bindings, f)) var prev = PType(idTableGet(c.bindings, f))
if prev == nil: if prev == nil:
@ -1056,7 +1065,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
of tyFromExpr: of tyFromExpr:
# fix the expression, so it contains the already instantiated types # 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) let reevaluated = tryResolvingStaticExpr(c, f.n)
case reevaluated.typ.kind case reevaluated.typ.kind
of tyTypeDesc: of tyTypeDesc:
@ -1156,6 +1165,15 @@ proc isInlineIterator*(t: PType): bool =
result = t.kind == tyIter or result = t.kind == tyIter or
(t.kind == tyBuiltInTypeClass and t.base.kind == tyIter) (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, proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
argSemantized, argOrig: PNode): PNode = argSemantized, argOrig: PNode): PNode =
var var
@ -1178,8 +1196,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType,
if argType.kind == tyStatic: if argType.kind == tyStatic:
if m.callee.kind == tyGenericBody and tfGenericTypeParam notin argType.flags: if m.callee.kind == tyGenericBody and tfGenericTypeParam notin argType.flags:
result = newNodeI(nkType, argOrig.info) result = newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg))
result.typ = makeTypeFromExpr(c, arg)
return return
else: else:
var evaluated = c.semTryConstExpr(c, arg) 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) result = implicitConv(nkHiddenStdConv, f, result, m, c)
of isGeneric: of isGeneric:
inc(m.genericMatches) inc(m.genericMatches)
result = copyTree(arg) when true:
result.typ = getInstantiatedType(c, arg, m, f) if arg.typ == nil:
# BUG: f may not be the right key! result = arg
if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}: elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple:
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
# BUGFIX: use ``result.typ`` and not `f` here 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: of isFromIntLit:
# too lazy to introduce another ``*matches`` field, so we conflate # too lazy to introduce another ``*matches`` field, so we conflate
# ``isIntConv`` and ``isIntLit`` here: # ``isIntConv`` and ``isIntLit`` here:
@ -1441,13 +1471,14 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
return return
checkConstraint(n.sons[a].sons[1]) checkConstraint(n.sons[a].sons[1])
if m.baseTypeMatch: if m.baseTypeMatch:
assert(container == nil) #assert(container == nil)
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
addSon(container, arg) addSon(container, arg)
setSon(m.call, formal.position + 1, container) setSon(m.call, formal.position + 1, container)
if f != formalLen - 1: container = nil if f != formalLen - 1: container = nil
else: else:
setSon(m.call, formal.position + 1, arg) setSon(m.call, formal.position + 1, arg)
inc f
else: else:
# unnamed param # unnamed param
if f >= formalLen: if f >= formalLen:
@ -1466,7 +1497,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) n.sons[a] = prepareOperand(c, formal.typ, n.sons[a])
var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ,
n.sons[a], nOrig.sons[a]) 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) addSon(container, arg)
incrIndexType(container.typ) incrIndexType(container.typ)
else: else:
@ -1480,7 +1511,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
internalError(n.sons[a].info, "matches") internalError(n.sons[a].info, "matches")
return return
formal = m.callee.n.sons[f].sym formal = m.callee.n.sons[f].sym
if containsOrIncl(marker, formal.position): if containsOrIncl(marker, formal.position) and container.isNil:
# already in namedParams: # already in namedParams:
localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) localError(n.sons[a].info, errCannotBindXTwice, formal.name.s)
m.state = csNoMatch m.state = csNoMatch
@ -1493,17 +1524,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
m.state = csNoMatch m.state = csNoMatch
return return
if m.baseTypeMatch: if m.baseTypeMatch:
assert(container == nil) #assert(container == nil)
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) if container.isNil:
container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg))
addSon(container, arg) addSon(container, arg)
setSon(m.call, formal.position + 1, setSon(m.call, formal.position + 1,
implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) 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: else:
setSon(m.call, formal.position + 1, arg) setSon(m.call, formal.position + 1, arg)
inc(f)
container = nil
checkConstraint(n.sons[a]) checkConstraint(n.sons[a])
inc(a) inc(a)
inc(f)
proc semFinishOperands*(c: PContext, n: PNode) = proc semFinishOperands*(c: PContext, n: PNode) =
# this needs to be called to ensure that after overloading resolution every # 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 = proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
result = transformSons(c, n) result = transformSons(c, n)
if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
var n = result.PNode var n = result.PNode
case n.sons[0].kind case n.sons[0].kind
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
@ -491,7 +492,8 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
var newC = newTransCon(getCurrOwner(c)) var newC = newTransCon(getCurrOwner(c))
newC.forStmt = n newC.forStmt = n
newC.forLoopBody = loopBody 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) # generate access statements for the parameters (unless they are constant)
pushTransCon(c, newC) pushTransCon(c, newC)
for i in countup(1, sonsLen(call) - 1): for i in countup(1, sonsLen(call) - 1):

View file

@ -29,7 +29,8 @@ proc hashTree(n: PNode): THash =
if (n.floatVal >= - 1000000.0) and (n.floatVal <= 1000000.0): if (n.floatVal >= - 1000000.0) and (n.floatVal <= 1000000.0):
result = result !& toInt(n.floatVal) result = result !& toInt(n.floatVal)
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
result = result !& hash(n.strVal) if not n.strVal.isNil:
result = result !& hash(n.strVal)
else: else:
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
result = result !& hashTree(n.sons[i]) result = result !& hashTree(n.sons[i])

View file

@ -250,7 +250,7 @@ proc containsObject(t: PType): bool =
proc isObjectWithTypeFieldPredicate(t: PType): bool = proc isObjectWithTypeFieldPredicate(t: PType): bool =
result = t.kind == tyObject and t.sons[0] == nil and 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 tfFinal notin t.flags
proc analyseObjectWithTypeFieldAux(t: PType, proc analyseObjectWithTypeFieldAux(t: PType,
@ -396,7 +396,7 @@ proc rangeToStr(n: PNode): string =
const const
typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty", typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty",
"Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc", "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", "distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple",
"set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc", "set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc",
"pointer", "OpenArray[$1]", "string", "CString", "Forward", "pointer", "OpenArray[$1]", "string", "CString", "Forward",
@ -432,9 +432,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result = $t.n.intVal result = $t.n.intVal
else: else:
result = "int literal(" & $t.n.intVal & ")" result = "int literal(" & $t.n.intVal & ")"
of tyGenericBody, tyGenericInst, tyGenericInvokation: of tyGenericBody, tyGenericInst, tyGenericInvocation:
result = typeToString(t.sons[0]) & '[' 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, ", ") if i > 1: add(result, ", ")
add(result, typeToString(t.sons[i], preferGenericArg)) add(result, typeToString(t.sons[i], preferGenericArg))
add(result, ']') add(result, ']')
@ -649,7 +649,7 @@ proc lengthOrd(t: PType): BiggestInt =
type type
TDistinctCompare* = enum ## how distinct types are to be compared TDistinctCompare* = enum ## how distinct types are to be compared
dcEq, ## a and b should be the same type 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) ## or a == (distinct b)
dcEqOrDistinctOf ## a equals b or a is distinct of b dcEqOrDistinctOf ## a equals b or a is distinct of b
@ -796,7 +796,7 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} =
else: else:
# expensive structural equality test; however due to the way generic and # expensive structural equality test; however due to the way generic and
# objects work, if one of the types does **not** contain tfFromGeneric, # 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" # for the same origin and is essential because we don't want "pure"
# structural type equivalence: # 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) result = sameChildrenAux(a, b, c) and sameFlags(a, b)
if result and ExactGenericParams in c.flags: if result and ExactGenericParams in c.flags:
result = a.sym.position == b.sym.position result = a.sym.position == b.sym.position
of tyGenericInvokation, tyGenericBody, tySequence, of tyGenericInvocation, tyGenericBody, tySequence,
tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr,
tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter,
tyOrdinal, tyTypeClasses, tyFieldAccessor: tyOrdinal, tyTypeClasses, tyFieldAccessor:
@ -1038,7 +1038,9 @@ proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
discard discard
else: else:
for i in countup(0, sonsLen(n) - 1): 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 if result != nil: break
proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], 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 if taField notin flags: result = t
of tyTypeClasses: of tyTypeClasses:
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
of tyGenericBody, tyGenericParam, tyGenericInvokation, of tyGenericBody, tyGenericParam, tyGenericInvocation,
tyNone, tyForward, tyFromExpr, tyFieldAccessor: tyNone, tyForward, tyFromExpr, tyFieldAccessor:
result = t result = t
of tyNil: of tyNil:
@ -1098,7 +1100,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
result = typeAllowedAux(marker, lastSon(t), kind, flags) result = typeAllowedAux(marker, lastSon(t), kind, flags)
of tyRange: of tyRange:
if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin 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: of tyOpenArray, tyVarargs:
if kind != skParam: result = t if kind != skParam: result = t
else: result = typeAllowedAux(marker, t.sons[0], skVar, flags) 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) result = typeAllowedAux(marker, t.sons[i], kind, flags)
if result != nil: break if result != nil: break
of tyObject, tyTuple: 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} let flags = flags+{taField}
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
result = typeAllowedAux(marker, t.sons[i], kind, flags) result = typeAllowedAux(marker, t.sons[i], kind, flags)

View file

@ -123,8 +123,12 @@ proc createStrKeepNode(x: var TFullReg) =
if x.node.isNil: if x.node.isNil:
x.node = newNode(nkStrLit) x.node = newNode(nkStrLit)
elif x.node.kind == nkNilLit: elif x.node.kind == nkNilLit:
when defined(useNodeIds):
let id = x.node.id
system.reset(x.node[]) system.reset(x.node[])
x.node.kind = nkStrLit x.node.kind = nkStrLit
when defined(useNodeIds):
x.node.id = id
elif x.node.kind notin {nkStrLit..nkTripleStrLit} or elif x.node.kind notin {nkStrLit..nkTripleStrLit} or
nfAllConst in x.node.flags: nfAllConst in x.node.flags:
# XXX this is hacky; tests/txmlgen triggers it: # 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 of rkNodeAddr: x.nodeAddr = y.nodeAddr
# this seems to be the best way to model the reference semantics # 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) template asgnRef(x, y: expr) = moveConst(x, y)
proc copyValue(src: PNode): PNode = proc copyValue(src: PNode): PNode =
@ -772,10 +776,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
stackTrace(c, tos, pc, errNilAccess) stackTrace(c, tos, pc, errNilAccess)
of opcEcho: of opcEcho:
let rb = instr.regB let rb = instr.regB
for i in ra..ra+rb-1: if rb == 1:
#if regs[i].kind != rkNode: debug regs[i] msgWriteln(regs[ra].node.strVal)
write(stdout, regs[i].node.strVal) else:
writeln(stdout, "") 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: of opcContainsSet:
decodeBC(rkInt) decodeBC(rkInt)
regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode)) 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: of opcNAdd:
decodeBC(rkNode) decodeBC(rkNode)
var u = regs[rb].node 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 regs[ra].node = u
of opcNAddMultiple: of opcNAddMultiple:
decodeBC(rkNode) decodeBC(rkNode)
let x = regs[rc].node let x = regs[rc].node
var u = regs[rb].node var u = regs[rb].node
# XXX can be optimized: if u.kind notin {nkEmpty..nkNilLit}:
for i in 0.. <x.len: u.add(x.sons[i]) # 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 regs[ra].node = u
of opcNKind: of opcNKind:
decodeB(rkInt) decodeB(rkInt)
@ -1127,7 +1141,21 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
else: else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident") stackTrace(c, tos, pc, errFieldXNotFound, "ident")
of opcNGetType: 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: of opcNStrVal:
decodeB(rkNode) decodeB(rkNode)
createStr regs[ra] createStr regs[ra]
@ -1364,9 +1392,11 @@ var
globalCtx: PCtx globalCtx: PCtx
proc setupGlobalCtx(module: PSym) = proc setupGlobalCtx(module: PSym) =
if globalCtx.isNil: globalCtx = newCtx(module) if globalCtx.isNil:
else: refresh(globalCtx, module) globalCtx = newCtx(module)
registerAdditionalOps(globalCtx) registerAdditionalOps(globalCtx)
else:
refresh(globalCtx, module)
proc myOpen(module: PSym): PPassContext = proc myOpen(module: PSym): PPassContext =
#var c = newEvalContext(module, emRepl) #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 # immediate macros can bypass any type and arity checking so we check the
# arity here too: # arity here too:
if sym.typ.len > n.safeLen and sym.typ.len > 1: 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) setupGlobalCtx(module)
var c = globalCtx var c = globalCtx

View file

@ -213,6 +213,7 @@ proc newCtx*(module: PSym): PCtx =
proc refresh*(c: PCtx, module: PSym) = proc refresh*(c: PCtx, module: PSym) =
c.module = module c.module = module
c.prc = PProc(blocks: @[]) c.prc = PProc(blocks: @[])
c.loopIterations = MaxLoopIterations
proc registerCallback*(c: PCtx; name: string; callback: VmCallback) = proc registerCallback*(c: PCtx; name: string; callback: VmCallback) =
c.callbacks.add((name, callback)) c.callbacks.add((name, callback))

View file

@ -1,13 +1,13 @@
# #
# #
# The Nim Compiler # The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf # (c) Copyright 2015 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
import ast, types, msgs, osproc, streams, options import ast, types, msgs, osproc, streams, options, idents
proc readOutput(p: Process): string = proc readOutput(p: Process): string =
result = "" result = ""
@ -19,11 +19,14 @@ proc readOutput(p: Process): string =
discard p.waitForExit discard p.waitForExit
proc opGorge*(cmd, input: string): string = proc opGorge*(cmd, input: string): string =
var p = startCmd(cmd) try:
if input.len != 0: var p = startProcess(cmd, options={poEvalCommand})
p.inputStream.write(input) if input.len != 0:
p.inputStream.close() p.inputStream.write(input)
result = p.readOutput p.inputStream.close()
result = p.readOutput
except IOError, OSError:
result = ""
proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
try: try:
@ -36,3 +39,116 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
except IOError: except IOError:
localError(info, errCannotOpenFile, file) localError(info, errCannotOpenFile, file)
result = "" 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}) let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
# uint is uint64 in the VM, we we only need to mask the result for # uint is uint64 in the VM, we we only need to mask the result for
# other unsigned types: # 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)) c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = 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: of mHigh:
if dest < 0: dest = c.getTemp(n.typ) if dest < 0: dest = c.getTemp(n.typ)
let tmp = c.genx(n.sons[1]) 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) c.gABI(n, opcLenStr, dest, tmp, 1)
else: else:
c.gABI(n, opcLenSeq, dest, tmp, 1) 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 mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal)
of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol) of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol)
of mNIdent: genUnaryABC(c, n, dest, opcNIdent) 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 mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
of mNSetIntVal: of mNSetIntVal:
unused(n, dest) unused(n, dest)
@ -1244,8 +1251,8 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
c.globals.add(getNullValue(s.typ, n.info)) c.globals.add(getNullValue(s.typ, n.info))
s.position = c.globals.len s.position = c.globals.len
# This is rather hard to support, due to the laziness of the VM code # This is rather hard to support, due to the laziness of the VM code
# generator. See tests/compile/tmacro2 for why this is necesary: # generator. See tests/compile/tmacro2 for why this is necessary:
# var decls{.compileTime.}: seq[PNimrodNode] = @[] # var decls{.compileTime.}: seq[NimNode] = @[]
let dest = c.getTemp(s.typ) let dest = c.getTemp(s.typ)
c.gABx(n, opcLdGlobal, dest, s.position) c.gABx(n, opcLdGlobal, dest, s.position)
let tmp = c.genx(s.ast) let tmp = c.genx(s.ast)

View file

@ -5,10 +5,17 @@
# You may set environment variables with # You may set environment variables with
# @putenv "key" "val" # @putenv "key" "val"
# Environment variables cannot be used in the options, however! # Environment variables can be accessed like so:
# gcc.path %= "$CC_PATH"
cc = gcc cc = gcc
# additional options always passed to the compiler:
--parallel_build: "0" # 0 to auto-detect number of processors
hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off
# example of how to setup a cross-compiler: # example of how to setup a cross-compiler:
arm.linux.gcc.exe = "arm-linux-gcc" arm.linux.gcc.exe = "arm-linux-gcc"
arm.linux.gcc.linkerexe = "arm-linux-gcc" arm.linux.gcc.linkerexe = "arm-linux-gcc"
@ -21,6 +28,7 @@ mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc"
@end @end
path="$lib/core" path="$lib/core"
path="$lib/pure" path="$lib/pure"
path="$lib/pure/collections" path="$lib/pure/collections"
path="$lib/pure/concurrency" path="$lib/pure/concurrency"
@ -64,12 +72,6 @@ path="$lib/pure/unidecode"
opt:speed opt:speed
@end @end
# additional options always passed to the compiler:
--parallel_build: "0" # 0 to auto-detect number of processors
hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off
@if unix: @if unix:
@if not bsd: @if not bsd:
# -fopenmp # -fopenmp
@ -103,13 +105,27 @@ hint[LineTooLong]=off
@if macosx or freebsd: @if macosx or freebsd:
cc = clang cc = clang
tlsEmulation:on tlsEmulation:on
gcc.options.always = "-w -fasm-blocks" gcc.options.always = "-w"
gcc.cpp.options.always = "-w -fasm-blocks -fpermissive" gcc.cpp.options.always = "-w -fpermissive"
@else: @else:
gcc.options.always = "-w" gcc.options.always = "-w"
gcc.cpp.options.always = "-w -fpermissive" gcc.cpp.options.always = "-w -fpermissive"
@end @end
# Configuration for the VxWorks
# This has been tested with VxWorks 6.9 only
@if vxworks:
# For now we only support compiling RTPs applications (i.e. no DKMs)
gcc.options.always = "-mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
# The linker config must add the VxWorks common library for the selected
# processor which is usually found in:
# "$WIND_BASE/target/lib/usr/lib/PROCESSOR_FAMILY/PROCESSOR_TYPE/common",
# where PROCESSOR_FAMILY and PROCESSOR_TYPE are those supported by the VxWorks
# compiler (e.g. ppc/PPC32 or mips/MIPSI64, etc)
# For now we only support the PowerPC CPU
gcc.options.linker %= "-L $WIND_BASE/target/lib/usr/lib/ppc/PPC32/common -mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings"
@end
gcc.options.speed = "-O3 -fno-strict-aliasing" gcc.options.speed = "-O3 -fno-strict-aliasing"
gcc.options.size = "-Os" gcc.options.size = "-Os"
gcc.options.debug = "-g3 -O0" gcc.options.debug = "-g3 -O0"

View file

@ -24,7 +24,7 @@ doc.section.toc = """
</li> </li>
""" """
# Chunk of HTML emmited for each entry in the HTML table of contents. # Chunk of HTML emitted for each entry in the HTML table of contents.
# Available variables are: # Available variables are:
# * $desc: the actual docstring of the item. # * $desc: the actual docstring of the item.
# * $header: the full version of name, including types, pragmas, tags, etc. # * $header: the full version of name, including types, pragmas, tags, etc.
@ -45,7 +45,7 @@ $seeSrc
</dd> </dd>
""" """
# Chunk of HTML emmited for each entry in the HTML table of contents. # Chunk of HTML emitted for each entry in the HTML table of contents.
# See doc.item for available substitution variables. # See doc.item for available substitution variables.
doc.item.toc = """ doc.item.toc = """
<li><a class="reference" href="#$itemSymOrID" <li><a class="reference" href="#$itemSymOrID"

View file

@ -1,136 +0,0 @@
# Configuration file for the Nim Compiler.
# (c) 2015 Andreas Rumpf
# Feel free to edit the default values as you need.
# You may set environment variables with
# @putenv "key" "val"
# Environment variables cannot be used in the options, however!
cc = gcc
# example of how to setup a cross-compiler:
arm.linux.gcc.exe = "arm-linux-gcc"
arm.linux.gcc.linkerexe = "arm-linux-gcc"
cs:partial
path="$lib/core"
path="$lib/pure"
path="$lib/pure/collections"
path="$lib/pure/concurrency"
path="$lib/impure"
path="$lib/wrappers"
# path="$lib/wrappers/cairo"
# path="$lib/wrappers/gtk"
# path="$lib/wrappers/lua"
# path="$lib/wrappers/opengl"
path="$lib/wrappers/pcre"
path="$lib/wrappers/readline"
path="$lib/wrappers/sdl"
# path="$lib/wrappers/x11"
path="$lib/wrappers/zip"
path="$lib/wrappers/libffi"
path="$lib/windows"
path="$lib/posix"
path="$lib/js"
path="$lib/pure/unidecode"
@if nimbabel:
babelpath="$home/.babel/pkgs/"
@end
@if release or quick:
obj_checks:off
field_checks:off
range_checks:off
bound_checks:off
overflow_checks:off
assertions:off
stacktrace:off
linetrace:off
debugger:off
line_dir:off
dead_code_elim:on
@end
@if release:
opt:speed
@end
# additional options always passed to the compiler:
--parallel_build: "0" # 0 to auto-detect number of processors
hint[LineTooLong]=off
#hint[XDeclaredButNotUsed]=off
@if unix:
@if not bsd:
# -fopenmp
gcc.options.linker = "-ldl"
gpp.options.linker = "-ldl"
clang.options.linker = "-ldl"
tcc.options.linker = "-ldl"
@end
@if bsd or haiku:
# BSD got posix_spawn only recently, so we deactivate it for osproc:
define:useFork
# at least NetBSD has problems with thread local storage:
tlsEmulation:on
@end
@end
# Configuration for the Intel C/C++ compiler:
@if windows:
icl.options.speed = "/Ox /arch:SSE2"
icl.options.always = "/nologo"
@end
# Configuration for the GNU C/C++ compiler:
@if windows:
#gcc.path = r"$nimrod\dist\mingw\bin"
@if gcc:
tlsEmulation:on
@end
@end
@if macosx:
cc = clang
tlsEmulation:on
gcc.options.always = "-w -fasm-blocks"
gpp.options.always = "-w -fasm-blocks -fpermissive"
@else:
gcc.options.always = "-w"
gpp.options.always = "-w -fpermissive"
@end
gcc.options.speed = "-O3 -fno-strict-aliasing"
gcc.options.size = "-Os"
gcc.options.debug = "-g3 -O0"
gpp.options.speed = "-O3 -fno-strict-aliasing"
gpp.options.size = "-Os"
gpp.options.debug = "-g3 -O0"
#passl = "-pg"
# Configuration for the LLVM GCC compiler:
llvm_gcc.options.debug = "-g"
llvm_gcc.options.always = "-w"
llvm_gcc.options.speed = "-O2"
llvm_gcc.options.size = "-Os"
# Configuration for the LLVM CLang compiler:
clang.options.debug = "-g"
clang.options.always = "-w"
clang.options.speed = "-O3"
clang.options.size = "-Os"
# Configuration for the Visual C/C++ compiler:
vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
vcc.options.always = "/nologo"
vcc.options.speed = "/Ox /arch:SSE2"
vcc.options.size = "/O1"
# Configuration for the Tiny C Compiler:
tcc.options.always = "-w"

View file

@ -1,7 +1,7 @@
===================================================== =====================================================
Nim -- a Compiler for Nim. http://nim-lang.org/ Nim -- a Compiler for Nim. http://nim-lang.org/
Copyright (C) 2006-2014 Andreas Rumpf. All rights reserved. Copyright (C) 2006-2015 Andreas Rumpf. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View file

@ -18,7 +18,7 @@ Advanced commands:
track a file, currently not saved to disk track a file, currently not saved to disk
--suggest suggest all possible symbols at position --suggest suggest all possible symbols at position
--def list all possible definitions at position --def list all possible definitions at position
--context list possible invokation context --context list possible invocation context
--usages list all usages of the symbol at position --usages list all usages of the symbol at position
--eval evaluates an expression --eval evaluates an expression
//serve start the compiler as a service mode (CAAS) //serve start the compiler as a service mode (CAAS)
@ -48,7 +48,6 @@ Advanced options:
--os:SYMBOL set the target operating system (cross-compilation) --os:SYMBOL set the target operating system (cross-compilation)
--cpu:SYMBOL set the target processor (cross-compilation) --cpu:SYMBOL set the target processor (cross-compilation)
--debuginfo enables debug information --debuginfo enables debug information
--debugger:on|off turn Embedded Nim Debugger on|off
-t, --passC:OPTION pass an option to the C compiler -t, --passC:OPTION pass an option to the C compiler
-l, --passL:OPTION pass an option to the linker -l, --passL:OPTION pass an option to the linker
--cincludes:DIR modify the C compiler header search path --cincludes:DIR modify the C compiler header search path
@ -66,7 +65,6 @@ Advanced options:
--threadanalysis:on|off turn thread analysis on|off --threadanalysis:on|off turn thread analysis on|off
--tlsEmulation:on|off turn thread local storage emulation on|off --tlsEmulation:on|off turn thread local storage emulation on|off
--taintMode:on|off turn taint mode on|off --taintMode:on|off turn taint mode on|off
--symbolFiles:on|off turn symbol files on|off (experimental)
--implicitStatic:on|off turn implicit compile time evaluation on|off --implicitStatic:on|off turn implicit compile time evaluation on|off
--patterns:on|off turn pattern matching on|off --patterns:on|off turn pattern matching on|off
--skipCfg do not read the general configuration file --skipCfg do not read the general configuration file
@ -86,10 +84,8 @@ Advanced options:
that --dynlibOverride:lua matches that --dynlibOverride:lua matches
dynlib: "liblua.so.3" dynlib: "liblua.so.3"
--listCmd list the commands used to execute external programs --listCmd list the commands used to execute external programs
--parallelBuild=0|1|... perform a parallel build --parallelBuild:0|1|... perform a parallel build
value = number of processors (0 for auto-detect) value = number of processors (0 for auto-detect)
--verbosity:0|1|2|3 set Nim's verbosity level (1 is default) --verbosity:0|1|2|3 set Nim's verbosity level (1 is default)
--cs:none|partial set case sensitivity level (default: none);
do not use! this setting affects the whole language
--experimental enable experimental language features --experimental enable experimental language features
-v, --version show detailed version information -v, --version show detailed version information

View file

@ -79,10 +79,3 @@ string str
identifier ident identifier ident
indentation indent indentation indent
------------------- ------------ -------------------------------------- ------------------- ------------ --------------------------------------
Coding Guidelines
=================
For coding guidelines see the `Internals of the Nim Compiler
<intern.html#coding-guidelines>`_ documentation.

View file

@ -1,14 +1,14 @@
The AST in Nim The AST in Nim
================= =================
This section describes how the AST is modelled with Nim's type system. This section describes how the AST is modelled with Nim's type system.
The AST consists of nodes (``PNimrodNode``) with a variable number of The AST consists of nodes (``NimNode``) with a variable number of
children. Each node has a field named ``kind`` which describes what the node children. Each node has a field named ``kind`` which describes what the node
contains: contains:
.. code-block:: nim .. code-block:: nim
type type
TNimrodNodeKind = enum ## kind of a node; only explanatory NimNodeKind = enum ## kind of a node; only explanatory
nnkNone, ## invalid node kind nnkNone, ## invalid node kind
nnkEmpty, ## empty node nnkEmpty, ## empty node
nnkIdent, ## node contains an identifier nnkIdent, ## node contains an identifier
@ -18,11 +18,11 @@ contains:
nnkCaseStmt, ## node represents a case statement nnkCaseStmt, ## node represents a case statement
... ## many more ... ## many more
PNimrodNode = ref TNimrodNode NimNode = ref NimNodeObj
TNimrodNode {.final.} = object NimNodeObj = object
case kind: TNimrodNodeKind ## the node's kind case kind: NimNodeKind ## the node's kind
of nnkNone, nnkEmpty, nnkNilLit: of nnkNone, nnkEmpty, nnkNilLit:
nil ## node contains no additional fields discard ## node contains no additional fields
of nnkCharLit..nnkInt64Lit: of nnkCharLit..nnkInt64Lit:
intVal: biggestInt ## the int literal intVal: biggestInt ## the int literal
of nnkFloatLit..nnkFloat64Lit: of nnkFloatLit..nnkFloat64Lit:
@ -30,13 +30,13 @@ contains:
of nnkStrLit..nnkTripleStrLit: of nnkStrLit..nnkTripleStrLit:
strVal: string ## the string literal strVal: string ## the string literal
of nnkIdent: of nnkIdent:
ident: TNimrodIdent ## the identifier ident: NimIdent ## the identifier
of nnkSym: of nnkSym:
symbol: PNimrodSymbol ## the symbol (after symbol lookup phase) symbol: NimSymbol ## the symbol (after symbol lookup phase)
else: else:
sons: seq[PNimrodNode] ## the node's sons (or children) sons: seq[NimNode] ## the node's sons (or children)
For the ``PNimrodNode`` type, the ``[]`` operator has been overloaded: For the ``NimNode`` type, the ``[]`` operator has been overloaded:
``n[i]`` is ``n``'s ``i``-th child. ``n[i]`` is ``n``'s ``i``-th child.
To specify the AST for the different Nim constructs, the notation To specify the AST for the different Nim constructs, the notation
@ -73,10 +73,7 @@ Nim expression corresponding AST
----------------- --------------------------------------------- ----------------- ---------------------------------------------
Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes
get transferred into ``nnkSym`` nodes. However, a macro receives an AST that get transferred into ``nnkSym`` nodes.
has not been checked for semantics and thus the identifiers have not been
looked up. Macros should deal with ``nnkIdent`` nodes and do not need to deal
with ``nnkSym`` nodes.
Calls/expressions Calls/expressions
@ -171,13 +168,13 @@ AST:
nnkStrLit("hallo")) nnkStrLit("hallo"))
Dereference operator ``^`` Dereference operator ``[]``
-------------------------- ---------------------------
Concrete syntax: Concrete syntax:
.. code-block:: nim .. code-block:: nim
x^ x[]
AST: AST:
@ -573,4 +570,3 @@ Other node kinds are especially designed to make AST manipulations easier.
These are explained here. These are explained here.
To be written. To be written.

View file

@ -225,7 +225,7 @@ The JavaScript target doesn't have any further interfacing considerations
since it also has garbage collection, but the C targets require you to since it also has garbage collection, but the C targets require you to
initialize Nim's internals, which is done calling a ``NimMain`` function. initialize Nim's internals, which is done calling a ``NimMain`` function.
Also, C code requires you to specify a forward declaration for functions or Also, C code requires you to specify a forward declaration for functions or
the compiler will asume certain types for the return value and parameters the compiler will assume certain types for the return value and parameters
which will likely make your program crash at runtime. which will likely make your program crash at runtime.
The Nim compiler can generate a C interface header through the ``--header`` The Nim compiler can generate a C interface header through the ``--header``
@ -427,7 +427,7 @@ Custom data types
----------------- -----------------
Just like strings, custom data types that are to be shared between Nim and Just like strings, custom data types that are to be shared between Nim and
the backend will need careful consideration of who controlls who. If you want the backend will need careful consideration of who controls who. If you want
to hand a Nim reference to C code, you will need to use `GC_ref to hand a Nim reference to C code, you will need to use `GC_ref
<system.html#GC_ref>`_ to mark the reference as used, so it does not get <system.html#GC_ref>`_ to mark the reference as used, so it does not get
freed. And for the C backend you will need to expose the `GC_unref freed. And for the C backend you will need to expose the `GC_unref

View file

@ -6,7 +6,6 @@ Command:
//compile, c compile project with default code generator (C) //compile, c compile project with default code generator (C)
//doc generate the documentation for inputfile //doc generate the documentation for inputfile
//doc2 generate the documentation for the whole project //doc2 generate the documentation for the whole project
//i start Nim in interactive mode (limited)
Arguments: Arguments:
arguments are passed to the program being run (if --run option is selected) arguments are passed to the program being run (if --run option is selected)
@ -14,7 +13,6 @@ Options:
-p, --path:PATH add path to search paths -p, --path:PATH add path to search paths
-d, --define:SYMBOL define a conditional symbol -d, --define:SYMBOL define a conditional symbol
-u, --undef:SYMBOL undefine a conditional symbol -u, --undef:SYMBOL undefine a conditional symbol
--symbol:SYMBOL declare a conditional symbol
-f, --forceBuild force rebuilding of all modules -f, --forceBuild force rebuilding of all modules
--stackTrace:on|off turn stack tracing on|off --stackTrace:on|off turn stack tracing on|off
--lineTrace:on|off turn line tracing on|off --lineTrace:on|off turn line tracing on|off
@ -31,6 +29,7 @@ Options:
--infChecks:on|off turn Inf checks on|off --infChecks:on|off turn Inf checks on|off
--deadCodeElim:on|off whole program dead code elimination on|off --deadCodeElim:on|off whole program dead code elimination on|off
--opt:none|speed|size optimize not at all or for speed|size --opt:none|speed|size optimize not at all or for speed|size
--debugger:native|endb use native debugger (gdb) | ENDB (experimental)
--app:console|gui|lib|staticlib --app:console|gui|lib|staticlib
generate a console app|GUI app|DLL|static library generate a console app|GUI app|DLL|static library
-r, --run run the compiled program with given arguments -r, --run run the compiled program with given arguments

View file

@ -87,14 +87,14 @@ is triggered.
Time measurement Time measurement
---------------- ----------------
The GC's way of measing time uses (see ``lib/system/timers.nim`` for the The GC's way of measuring time uses (see ``lib/system/timers.nim`` for the
implementation): implementation):
1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows. 1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows.
2) ``mach_absolute_time`` on Mac OS X. 2) ``mach_absolute_time`` on Mac OS X.
3) ``gettimeofday`` on Posix systems. 3) ``gettimeofday`` on Posix systems.
As such it supports a resolution of nano seconds internally; however the API As such it supports a resolution of nanoseconds internally; however the API
uses microseconds for convenience. uses microseconds for convenience.

View file

@ -27,7 +27,7 @@ integrations <https://github.com/Araq/Nim/wiki/Editor-Support>`_
already available. already available.
Idetools invokation Idetools invocation
=================== ===================
Specifying the location of the query Specifying the location of the query
@ -35,7 +35,7 @@ Specifying the location of the query
All of the available idetools commands require you to specify a All of the available idetools commands require you to specify a
query location through the ``--track`` or ``--trackDirty`` switches. query location through the ``--track`` or ``--trackDirty`` switches.
The general idetools invokations are:: The general idetools invocations are::
nim idetools --track:FILE,LINE,COL <switches> proj.nim nim idetools --track:FILE,LINE,COL <switches> proj.nim
@ -129,7 +129,7 @@ the suggestions sorted first by scope (from innermost to outermost)
and then by item name. and then by item name.
Invokation context Invocation context
------------------ ------------------
The ``--context`` idetools switch is very similar to the suggestions The ``--context`` idetools switch is very similar to the suggestions
@ -163,7 +163,7 @@ running/debugged user project.
Compiler as a service (CAAS) Compiler as a service (CAAS)
============================ ============================
The ocasional use of idetools is acceptable for things like The occasional use of idetools is acceptable for things like
definitions, where the user puts the cursor on a symbol or double definitions, where the user puts the cursor on a symbol or double
clicks it and after a second or two the IDE displays where that clicks it and after a second or two the IDE displays where that
symbol is defined. Such latencies would be terrible for features symbol is defined. Such latencies would be terrible for features
@ -533,10 +533,10 @@ run it manually. First you have to compile the tester::
Running the ``caasdriver`` without parameters will attempt to process Running the ``caasdriver`` without parameters will attempt to process
all the test cases in all three operation modes. If a test succeeds all the test cases in all three operation modes. If a test succeeds
nothing will be printed and the process will exit with zero. If any nothing will be printed and the process will exit with zero. If any
test fails, the specific line of the test preceeding the failure test fails, the specific line of the test preceding the failure
and the failure itself will be dumped to stdout, along with a final and the failure itself will be dumped to stdout, along with a final
indicator of the success state and operation mode. You can pass the indicator of the success state and operation mode. You can pass the
parameter ``verbose`` to force all output even on successfull tests. parameter ``verbose`` to force all output even on successful tests.
The normal operation mode is called ``ProcRun`` and it involves The normal operation mode is called ``ProcRun`` and it involves
starting a process for each command or query, similar to running starting a process for each command or query, similar to running

View file

@ -236,7 +236,7 @@ too. Type converters fall into this category:
If in the above example module ``B`` is re-compiled, but ``A`` is not then If in the above example module ``B`` is re-compiled, but ``A`` is not then
``B`` needs to be aware of ``toBool`` even though ``toBool`` is not referenced ``B`` needs to be aware of ``toBool`` even though ``toBool`` is not referenced
in ``B`` *explicitely*. in ``B`` *explicitly*.
Both the multi method and the type converter problems are solved by storing Both the multi method and the type converter problems are solved by storing
them in special sections in the ROD file that are loaded *unconditionally* them in special sections in the ROD file that are loaded *unconditionally*
@ -370,7 +370,7 @@ needed as the data structures needs to be rebuilt periodically anyway.
Complete traversal is done in this way:: Complete traversal is done in this way::
for each page decriptor d: for each page descriptor d:
for each bit in d: for each bit in d:
if bit == 1: if bit == 1:
traverse the pointer belonging to this bit traverse the pointer belonging to this bit
@ -406,7 +406,7 @@ The generated code looks roughly like this:
setRef(&r->left) setRef(&r->left)
} }
Note that for systems with a continous stack (which most systems have) Note that for systems with a continuous stack (which most systems have)
the check whether the ref is on the stack is very cheap (only two the check whether the ref is on the stack is very cheap (only two
comparisons). comparisons).

View file

@ -185,10 +185,19 @@ Math libraries
* `complex <complex.html>`_ * `complex <complex.html>`_
This module implements complex numbers and their mathematical operations. This module implements complex numbers and their mathematical operations.
* `rationals <rationals.html>`_
This module implements rational numbers and their mathematical operations.
* `fenv <fenv.html>`_ * `fenv <fenv.html>`_
Floating-point environment. Handling of floating-point rounding and Floating-point environment. Handling of floating-point rounding and
exceptions (overflow, zero-devide, etc.). exceptions (overflow, zero-devide, etc.).
* `basic2d <basic2d.html>`_
Basic 2d support with vectors, points, matrices and some basic utilities.
* `basic3d <basic3d.html>`_
Basic 3d support with vectors, points, matrices and some basic utilities.
Internet Protocols and Support Internet Protocols and Support
------------------------------ ------------------------------
@ -218,9 +227,6 @@ Internet Protocols and Support
* `smtp <smtp.html>`_ * `smtp <smtp.html>`_
This module implement a simple SMTP client. This module implement a simple SMTP client.
* `irc <irc.html>`_
This module implements an asynchronous IRC client.
* `ftpclient <ftpclient.html>`_ * `ftpclient <ftpclient.html>`_
This module implements an FTP client. This module implements an FTP client.
@ -367,7 +373,7 @@ Miscellaneous
------------- -------------
* `events <events.html>`_ * `events <events.html>`_
This module implements an event system that is not dependant on external This module implements an event system that is not dependent on external
graphical toolkits. graphical toolkits.
* `oids <oids.html>`_ * `oids <oids.html>`_

View file

@ -25,9 +25,9 @@ with ``'``. An example::
ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)? ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)?
The binary ``^*`` operator is used as a shorthand for 0 or more occurances The binary ``^*`` operator is used as a shorthand for 0 or more occurrences
separated by its second argument; likewise ``^+`` means 1 or more separated by its second argument; likewise ``^+`` means 1 or more
occurances: ``a ^+ b`` is short for ``a (b a)*`` occurrences: ``a ^+ b`` is short for ``a (b a)*``
and ``a ^* b`` is short for ``(a (b a)*)?``. Example:: and ``a ^* b`` is short for ``(a (b a)*)?``. Example::
arrayConstructor = '[' expr ^* ',' ']' arrayConstructor = '[' expr ^* ',' ']'

View file

@ -12,10 +12,8 @@ Binary operators have 11 different levels of precedence.
Associativity Associativity
------------- -------------
Binary operators whose first character is ``^`` or its last character Binary operators whose first character is ``^`` are right-associative, all
is ``>`` are right-associative, all other binary operators are left-associative. other binary operators are left-associative.
Exception: The single "greater than" ``>`` operator is left-associative too.
Operators ending in ``>`` but longer than a single character are Operators ending in ``>`` but longer than a single character are
called `arrow like`:idx:. called `arrow like`:idx:.
@ -61,7 +59,7 @@ Precedence level Operators First charact
Strong spaces Strong spaces
------------- -------------
The number of spaces preceeding a non-keyword operator affects precedence The number of spaces preceding a non-keyword operator affects precedence
if the experimental parser directive ``#!strongSpaces`` is used. Indentation if the experimental parser directive ``#!strongSpaces`` is used. Indentation
is not used to determine the number of spaces. If 2 or more operators have the is not used to determine the number of spaces. If 2 or more operators have the
same number of preceding spaces the precedence table applies, so ``1 + 3 * 4`` same number of preceding spaces the precedence table applies, so ``1 + 3 * 4``

View file

@ -25,7 +25,7 @@ For the purposes of code generation, all static params are treated as
generic params - the proc will be compiled separately for each unique generic params - the proc will be compiled separately for each unique
supplied value (or combination of values). supplied value (or combination of values).
Furthermore, the system module defines a `semistatic[T]` type than can be Furthermore, the system module defines a `semistatic[T]` type that can be
used to declare procs accepting both static and run-time values, which can used to declare procs accepting both static and run-time values, which can
optimize their body according to the supplied param using the `isStatic(p)` optimize their body according to the supplied param using the `isStatic(p)`
predicate: predicate:

View file

@ -1142,7 +1142,7 @@ modules like `db_sqlite <db_sqlite.html>`_.
Void type Void type
--------- ---------
The ``void`` type denotes the absense of any type. Parameters of The ``void`` type denotes the absence of any type. Parameters of
type ``void`` are treated as non-existent, ``void`` as a return type means that type ``void`` are treated as non-existent, ``void`` as a return type means that
the procedure does not return a value: the procedure does not return a value:

View file

@ -60,11 +60,6 @@ ConfigDeprecated The project makes use of a deprecated config
file. file.
SmallLshouldNotBeUsed The letter 'l' should not be used as an SmallLshouldNotBeUsed The letter 'l' should not be used as an
identifier. identifier.
AnalysisLoophole The thread analysis was incomplete due to
an indirect call.
DifferentHeaps The code mixes different local heaps in a
very dangerous way.
WriteToForeignHeap The code contains a threading error.
EachIdentIsTuple The code contains a confusing ``var`` EachIdentIsTuple The code contains a confusing ``var``
declaration. declaration.
ShadowIdent A local variable shadows another local ShadowIdent A local variable shadows another local
@ -139,7 +134,7 @@ found an ambiguity error is produced.
``nim dump`` shows the contents of the PATH. ``nim dump`` shows the contents of the PATH.
However before the PATH is used the current directory is checked for the However before the PATH is used the current directory is checked for the
file's existance. So if PATH contains ``$lib`` and ``$lib/bar`` and the file's existence. So if PATH contains ``$lib`` and ``$lib/bar`` and the
directory structure looks like this:: directory structure looks like this::
$lib/x.nim $lib/x.nim
@ -574,7 +569,7 @@ language for object types:
type type
StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object
proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {. proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {.
importcpp: "#[#] = #".} importcpp: "#[#] = #", header: "<map>".}
var x: StdMap[cint, cdouble] var x: StdMap[cint, cdouble]
x[6] = 91.4 x[6] = 91.4

View file

@ -37,7 +37,7 @@ Options:
--re pattern is a regular expression (default); extended --re pattern is a regular expression (default); extended
syntax for the regular expression is always turned on syntax for the regular expression is always turned on
--recursive process directories recursively --recursive process directories recursively
--confirm confirm each occurence/replacement; there is a chance --confirm confirm each occurrence/replacement; there is a chance
to abort any time without touching the file to abort any time without touching the file
--stdin read pattern from stdin (to avoid the shell's confusing --stdin read pattern from stdin (to avoid the shell's confusing
quoting rules) quoting rules)

View file

@ -190,6 +190,6 @@ Real world example
The installers for the Nim compiler itself are generated by niminst. Have a The installers for the Nim compiler itself are generated by niminst. Have a
look at its configuration file: look at its configuration file:
.. include:: compiler/nim.ini .. include:: compiler/installer.ini
:literal: :literal:

View file

@ -749,7 +749,8 @@ Forward declarations
-------------------- --------------------
Every variable, procedure, etc. needs to be declared before it can be used. Every variable, procedure, etc. needs to be declared before it can be used.
(The reason for this is compilation efficiency.) (The reason for this is that it is non-trivial to do better than that in a
language that supports meta programming as extensively as Nim does.)
However, this cannot be done for mutually recursive procedures: However, this cannot be done for mutually recursive procedures:
.. code-block:: nim .. code-block:: nim
@ -767,7 +768,7 @@ introduced to the compiler before it is completely defined. The syntax for
such a forward declaration is simple: just omit the ``=`` and the such a forward declaration is simple: just omit the ``=`` and the
procedure's body. procedure's body.
Later versions of the language may get rid of the need for forward Later versions of the language will weaken the requirements for forward
declarations. declarations.
The example also shows that a proc's body can consist of a single expression The example also shows that a proc's body can consist of a single expression

View file

@ -37,7 +37,7 @@ Object Oriented Programming
While Nim's support for object oriented programming (OOP) is minimalistic, While Nim's support for object oriented programming (OOP) is minimalistic,
powerful OOP techniques can be used. OOP is seen as *one* way to design a powerful OOP techniques can be used. OOP is seen as *one* way to design a
program, not *the only* way. Often a procedural approach leads to simpler program, not *the only* way. Often a procedural approach leads to simpler
and more efficient code. In particular, prefering composition over inheritance and more efficient code. In particular, preferring composition over inheritance
is often the better design. is often the better design.
@ -142,7 +142,7 @@ An example:
.. code-block:: nim .. code-block:: nim
# This is an example how an abstract syntax tree could be modeled in Nim # This is an example how an abstract syntax tree could be modelled in Nim
type type
NodeKind = enum # the different node types NodeKind = enum # the different node types
nkInt, # a leaf with an integer value nkInt, # a leaf with an integer value
@ -335,7 +335,7 @@ As the example demonstrates, invocation of a multi-method cannot be ambiguous:
Collide 2 is preferred over collide 1 because the resolution works from left to Collide 2 is preferred over collide 1 because the resolution works from left to
right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``. right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``.
**Perfomance note**: Nim does not produce a virtual method table, but **Performance note**: Nim does not produce a virtual method table, but
generates dispatch trees. This avoids the expensive indirect branch for method generates dispatch trees. This avoids the expensive indirect branch for method
calls and enables inlining. However, other optimizations like compile time calls and enables inlining. However, other optimizations like compile time
evaluation or dead code elimination do not work with methods. evaluation or dead code elimination do not work with methods.
@ -735,14 +735,6 @@ regular expressions:
return tkUnknown return tkUnknown
Term rewriting macros
---------------------
Term rewriting macros can be used to enhance the compilation process
with user defined optimizations; see this `document <trmacros.html>`_ for
further information.
Building your first macro Building your first macro
------------------------- -------------------------

View file

@ -10,7 +10,7 @@ just declared as a native method which will be resolved at runtime. The scripts
nimbuild.sh and jnibuild.sh are in charge of building the Nim code and nimbuild.sh and jnibuild.sh are in charge of building the Nim code and
generating the jni bridge from the java code respectively. Finally, the generating the jni bridge from the java code respectively. Finally, the
ndk-build command from the android ndk tools has to be run to build the binary ndk-build command from the android ndk tools has to be run to build the binary
libary which will be installed along the final apk. library which will be installed along the final apk.
All these steps are wrapped in the ant build script through the customization All these steps are wrapped in the ant build script through the customization
of the -post-compile rule. If you have the android ndk tools installed and you of the -post-compile rule. If you have the android ndk tools installed and you

View file

@ -55,7 +55,7 @@
[self.bText resignFirstResponder]; [self.bText resignFirstResponder];
} }
/** Custom loadView method for backwards compatiblity. /** Custom loadView method for backwards compatibility.
* Unfortunately I've been unable to coerce Xcode 4.4 to generate nib files * Unfortunately I've been unable to coerce Xcode 4.4 to generate nib files
* which are compatible with my trusty iOS 3.0 ipod touch so in order to be * which are compatible with my trusty iOS 3.0 ipod touch so in order to be
* fully compatible for all devices we have to build the interface manually in * fully compatible for all devices we have to build the interface manually in

View file

@ -1,4 +1,4 @@
# Nimrod configuration file. # Nimrod configuration file.
# The file is used only to add the path of the backend to the compiler options. # The file is used only to add the path of the backend to the compiler options.
path="../nimrod_backend" path="../nim_backend"

View file

@ -21,7 +21,7 @@ type
cmdParams, # Two valid parameters were provided cmdParams, # Two valid parameters were provided
cmdInteractive # No parameters were provided, run interactive mode cmdInteractive # No parameters were provided, run interactive mode
TParamConfig = object of TObject TParamConfig = object of RootObj
action: TCommand # store the type of operation action: TCommand # store the type of operation
paramA, paramB: int # possibly store the valid parameters paramA, paramB: int # possibly store the valid parameters
@ -63,7 +63,7 @@ proc parseCmdLine(): TParamConfig =
stdout.write USAGE stdout.write USAGE
quit "Unexpected option: " & key, 2 quit "Unexpected option: " & key, 2
of cmdEnd: break of cmdEnd: break
except EInvalidValue: except ValueError:
stdout.write USAGE stdout.write USAGE
quit "Invalid value " & val & " for parameter " & key, 3 quit "Invalid value " & val & " for parameter " & key, 3
@ -85,7 +85,7 @@ proc parseUserInput(question: string): int =
try: try:
result = input.parseInt result = input.parseInt
break break
except EInvalidValue: except ValueError:
if input.len < 1: quit "Blank line detected, quitting.", 0 if input.len < 1: quit "Blank line detected, quitting.", 0
echo "Sorry, `$1' doesn't seem to be a valid integer" % input echo "Sorry, `$1' doesn't seem to be a valid integer" % input

View file

@ -1,10 +1,10 @@
In this directory you will find the nimrod commandline version of the In this directory you will find the nim commandline version of the
cross-calculator sample. cross-calculator sample.
The commandline interface can be used non interactively through switches, or The commandline interface can be used non interactively through switches, or
interactively when running the command without parameters. interactively when running the command without parameters.
Compilation is fairly easy despite having the source split in different Compilation is fairly easy despite having the source split in different
directories. Thanks to the nimrod.cfg file, which adds the ../nimrod_backend directories. Thanks to the nim.cfg file, which adds the ../nim_backend
directory as a search path, you can compile and run the example just fine from directory as a search path, you can compile and run the example just fine from
the command line with 'nimrod c -r nimcalculator.nim'. the command line with 'nim c -r nimcalculator.nim'.

View file

@ -13,7 +13,7 @@ type
text*: string ## Description of the task to do. text*: string ## Description of the task to do.
priority*: int ## The priority can be any user defined integer. priority*: int ## The priority can be any user defined integer.
isDone*: bool ## Done todos are still kept marked. isDone*: bool ## Done todos are still kept marked.
modificationDate: TTime ## The modification time can't be modified from modificationDate: Time ## The modification time can't be modified from
## outside of this module, use the ## outside of this module, use the
## getModificationDate accessor. ## getModificationDate accessor.
@ -64,7 +64,7 @@ proc openDatabase*(path: string): TDbConn =
# - Procs related to TTodo objects # - Procs related to TTodo objects
# #
proc initFromDB(id: int64; text: string; priority: int, isDone: bool; proc initFromDB(id: int64; text: string; priority: int, isDone: bool;
modificationDate: TTime): TTodo = modificationDate: Time): TTodo =
## Returns an initialized TTodo object created from database parameters. ## Returns an initialized TTodo object created from database parameters.
## ##
## The proc assumes all values are right. Note this proc is NOT exported. ## The proc assumes all values are right. Note this proc is NOT exported.
@ -81,7 +81,7 @@ proc getId*(todo: TTodo): int64 =
return todo.id return todo.id
proc getModificationDate*(todo: TTodo): TTime = proc getModificationDate*(todo: TTodo): Time =
## Returns the last modification date of a TTodo entry. ## Returns the last modification date of a TTodo entry.
return todo.modificationDate return todo.modificationDate
@ -91,7 +91,7 @@ proc update*(todo: var TTodo; conn: TDbConn): bool =
## ##
## Use this method if you (or another entity) have modified the database and ## Use this method if you (or another entity) have modified the database and
## want to update the object you have with whatever the database has stored. ## want to update the object you have with whatever the database has stored.
## Returns true if the update suceeded, or false if the object was not found ## Returns true if the update succeeded, or false if the object was not found
## in the database any more, in which case you should probably get rid of the ## in the database any more, in which case you should probably get rid of the
## TTodo object. ## TTodo object.
assert(todo.id >= 0, "The identifier of the todo entry can't be negative") assert(todo.id >= 0, "The identifier of the todo entry can't be negative")
@ -99,14 +99,14 @@ proc update*(todo: var TTodo; conn: TDbConn): bool =
FROM Todos WHERE id = ?""" FROM Todos WHERE id = ?"""
try: try:
let rows = conn.GetAllRows(query, $todo.id) let rows = conn.getAllRows(query, $todo.id)
if len(rows) < 1: if len(rows) < 1:
return return
assert(1 == len(rows), "Woah, didn't expect so many rows") assert(1 == len(rows), "Woah, didn't expect so many rows")
todo.text = rows[0][0] todo.text = rows[0][0]
todo.priority = rows[0][1].parseInt todo.priority = rows[0][1].parseInt
todo.isDone = rows[0][2].parseBool todo.isDone = rows[0][2].parseBool
todo.modificationDate = TTime(rows[0][3].parseInt) todo.modificationDate = Time(rows[0][3].parseInt)
result = true result = true
except: except:
echo("Something went wrong selecting for id " & $todo.id) echo("Something went wrong selecting for id " & $todo.id)
@ -202,12 +202,12 @@ proc getPagedTodos*(conn: TDbConn; params: TPagedParams;
#echo("Query " & string(query)) #echo("Query " & string(query))
#echo("args: " & args.join(", ")) #echo("args: " & args.join(", "))
var newId: biggestInt var newId: BiggestInt
for row in conn.fastRows(query, args): for row in conn.fastRows(query, args):
let numChars = row[0].parseBiggestInt(newId) let numChars = row[0].parseBiggestInt(newId)
assert(numChars > 0, "Huh, couldn't parse identifier from database?") assert(numChars > 0, "Huh, couldn't parse identifier from database?")
result.add(initFromDB(int64(newId), row[1], row[2].parseInt, result.add(initFromDB(int64(newId), row[1], row[2].parseInt,
row[3].parseBool, TTime(row[4].parseInt))) row[3].parseBool, Time(row[4].parseInt)))
proc getTodo*(conn: TDbConn; todoId: int64): ref TTodo = proc getTodo*(conn: TDbConn; todoId: int64): ref TTodo =

View file

@ -1,4 +1,4 @@
This directory contains the nimrod backend code for the todo cross platform This directory contains the nim backend code for the todo cross platform
example. example.
Unlike the cross platform calculator example, this backend features more code, Unlike the cross platform calculator example, this backend features more code,
@ -8,7 +8,7 @@ The test is not embedded directly in the backend.nim file to avoid being able
to access internal data types and procs not exported and replicate the to access internal data types and procs not exported and replicate the
environment of client code. environment of client code.
In a bigger project with several people you could run `nimrod doc backend.nim` In a bigger project with several people you could run `nim doc backend.nim`
(or use the doc2 command for a whole project) and provide the generated html (or use the doc2 command for a whole project) and provide the generated html
documentation to another programer for her to implement an interface without documentation to another programer for her to implement an interface without
having to look at the source code. having to look at the source code.

View file

@ -1,4 +1,4 @@
# Nimrod configuration file. # Nimrod configuration file.
# The file is used only to add the path of the backend to the compiler options. # The file is used only to add the path of the backend to the compiler options.
path="../nimrod_backend" path="../nim_backend"

View file

@ -69,11 +69,11 @@ template parseTodoIdAndSetCommand(newCommand: TCommand): stmt =
## Helper to parse a big todo identifier into todoId and set command. ## Helper to parse a big todo identifier into todoId and set command.
try: try:
let numChars = val.parseBiggestInt(newId) let numChars = val.parseBiggestInt(newId)
if numChars < 1: raise newException(EInvalidValue, "Empty string?") if numChars < 1: raise newException(ValueError, "Empty string?")
result.command = newCommand result.command = newCommand
result.todoId = newId result.todoId = newId
except EOverflow: except OverflowError:
raise newException(EInvalidValue, "Value $1 too big" % val) raise newException(ValueError, "Value $1 too big" % val)
template verifySingleCommand(actions: stmt): stmt = template verifySingleCommand(actions: stmt): stmt =
@ -111,7 +111,7 @@ proc parseCmdLine(): TParamConfig =
usesListParams = false usesListParams = false
p = initOptParser() p = initOptParser()
key, val: TaintedString key, val: TaintedString
newId: biggestInt newId: BiggestInt
result.initDefaults result.initDefaults
@ -178,7 +178,7 @@ proc parseCmdLine(): TParamConfig =
abort("Unexpected option '$1'." % [key], 6) abort("Unexpected option '$1'." % [key], 6)
of cmdEnd: of cmdEnd:
break break
except EInvalidValue: except ValueError:
abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7) abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7)
if not specifiedCommand: if not specifiedCommand:

View file

@ -14,7 +14,7 @@ template optRe{re(x)}(x: string{lit}): Regex =
g g
template `=~`(s: string, pattern: Regex): bool = template `=~`(s: string, pattern: Regex): bool =
when not definedInScope(matches): when not declaredInScope(matches):
var matches {.inject.}: array[maxSubPatterns, string] var matches {.inject.}: array[maxSubPatterns, string]
match(s, pattern, matches) match(s, pattern, matches)

View file

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Before After
Before After

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