Merge branch 'devel' into warning-for-result
This commit is contained in:
commit
70eaf92ff0
356 changed files with 6122 additions and 3809 deletions
297
compiler/ast.nim
297
compiler/ast.nim
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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, ~" ")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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.}
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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``.
|
||||||
|
|
|
||||||
|
|
@ -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
89
compiler/forloops.nim
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2015 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## This module implements for loop detection for better C code generation.
|
||||||
|
|
||||||
|
import ast, astalgo
|
||||||
|
|
||||||
|
const
|
||||||
|
someCmp = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
|
||||||
|
mEqUntracedRef, mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
|
||||||
|
mLeCh, mLeB, mLePtr, mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
|
||||||
|
mLtCh, mLtB, mLtPtr}
|
||||||
|
|
||||||
|
proc isCounter(s: PSym): bool {.inline.} =
|
||||||
|
s.kind in {skResult, skVar, skLet, skTemp} and
|
||||||
|
{sfGlobal, sfAddrTaken} * s.flags == {}
|
||||||
|
|
||||||
|
proc isCall(n: PNode): bool {.inline.} =
|
||||||
|
n.kind in nkCallKinds and n[0].kind == nkSym
|
||||||
|
|
||||||
|
proc fromSystem(op: PSym): bool = sfSystemModule in getModule(op).flags
|
||||||
|
|
||||||
|
proc getCounter(lastStmt: PNode): PSym =
|
||||||
|
if lastStmt.isCall:
|
||||||
|
let op = lastStmt.sym
|
||||||
|
if op.magic in {mDec, mInc} or
|
||||||
|
((op.name.s == "+=" or op.name.s == "-=") and op.fromSystem):
|
||||||
|
if op[1].kind == nkSym and isCounter(op[1].sym):
|
||||||
|
result = op[1].sym
|
||||||
|
|
||||||
|
proc counterInTree(n, loop: PNode; counter: PSym): bool =
|
||||||
|
# prune the search tree: within the loop the counter may be used:
|
||||||
|
if n == loop: return
|
||||||
|
case n.kind
|
||||||
|
of nkSym:
|
||||||
|
if n.sym == counter: return true
|
||||||
|
of nkVarSection, nkLetSection:
|
||||||
|
# definitions are fine!
|
||||||
|
for it in n:
|
||||||
|
if counterInTree(it.lastSon): return true
|
||||||
|
else:
|
||||||
|
for i in 0 .. <safeLen(n):
|
||||||
|
if counterInTree(n[i], loop, counter): return true
|
||||||
|
|
||||||
|
proc copyExcept(n: PNode, x, dest: PNode) =
|
||||||
|
if x == n: return
|
||||||
|
if n.kind in {nkStmtList, nkStmtListExpr}:
|
||||||
|
for i in 0 .. <n.len: copyExcept(n[i], x, dest)
|
||||||
|
else:
|
||||||
|
dest.add n
|
||||||
|
|
||||||
|
type
|
||||||
|
ForLoop* = object
|
||||||
|
counter*: PSym
|
||||||
|
init*, cond*, increment*, body*: PNode
|
||||||
|
|
||||||
|
proc extractForLoop*(loop, fullTree: PNode): ForLoop =
|
||||||
|
## returns 'counter == nil' if the while loop 'n' is not a for loop:
|
||||||
|
assert loop.kind == nkWhileStmt
|
||||||
|
let cond == loop[0]
|
||||||
|
|
||||||
|
if not cond.isCall: return
|
||||||
|
if cond[0].sym.magic notin someCmp: return
|
||||||
|
|
||||||
|
var lastStmt = loop[1]
|
||||||
|
while lastStmt.kind in {nkStmtList, nkStmtListExpr}:
|
||||||
|
lastStmt = lastStmt.lastSon
|
||||||
|
|
||||||
|
let counter = getCounter(lastStmt)
|
||||||
|
if counter.isNil or counter.ast.isNil: return
|
||||||
|
|
||||||
|
template `=~`(a, b): expr = a.kind == nkSym and a.sym == b
|
||||||
|
|
||||||
|
if cond[1] =~ counter or cond[2] =~ counter:
|
||||||
|
# ok, now check 'counter' is not used *after* the loop
|
||||||
|
if counterInTree(fullTree, loop, counter): return
|
||||||
|
# ok, success, fill in the fields:
|
||||||
|
result.counter = counter
|
||||||
|
result.init = counter.ast
|
||||||
|
result.cond = cond
|
||||||
|
result.increment = lastStmt
|
||||||
|
result.body = newNodeI(nkStmtList, loop[1].info)
|
||||||
|
copyExcept(loop[1], lastStmt, result.body)
|
||||||
|
|
@ -51,10 +51,10 @@ Files: "configure;makefile"
|
||||||
Files: "*.ini"
|
Files: "*.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"
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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(): ...
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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":
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 =
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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: "/",
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:"):
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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])
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
# Configuration file for the Nim Compiler.
|
|
||||||
# (c) 2015 Andreas Rumpf
|
|
||||||
|
|
||||||
# Feel free to edit the default values as you need.
|
|
||||||
|
|
||||||
# You may set environment variables with
|
|
||||||
# @putenv "key" "val"
|
|
||||||
# Environment variables cannot be used in the options, however!
|
|
||||||
|
|
||||||
cc = gcc
|
|
||||||
|
|
||||||
# example of how to setup a cross-compiler:
|
|
||||||
arm.linux.gcc.exe = "arm-linux-gcc"
|
|
||||||
arm.linux.gcc.linkerexe = "arm-linux-gcc"
|
|
||||||
|
|
||||||
cs:partial
|
|
||||||
|
|
||||||
path="$lib/core"
|
|
||||||
path="$lib/pure"
|
|
||||||
path="$lib/pure/collections"
|
|
||||||
path="$lib/pure/concurrency"
|
|
||||||
path="$lib/impure"
|
|
||||||
path="$lib/wrappers"
|
|
||||||
# path="$lib/wrappers/cairo"
|
|
||||||
# path="$lib/wrappers/gtk"
|
|
||||||
# path="$lib/wrappers/lua"
|
|
||||||
# path="$lib/wrappers/opengl"
|
|
||||||
path="$lib/wrappers/pcre"
|
|
||||||
path="$lib/wrappers/readline"
|
|
||||||
path="$lib/wrappers/sdl"
|
|
||||||
# path="$lib/wrappers/x11"
|
|
||||||
path="$lib/wrappers/zip"
|
|
||||||
path="$lib/wrappers/libffi"
|
|
||||||
path="$lib/windows"
|
|
||||||
path="$lib/posix"
|
|
||||||
path="$lib/js"
|
|
||||||
path="$lib/pure/unidecode"
|
|
||||||
|
|
||||||
@if nimbabel:
|
|
||||||
babelpath="$home/.babel/pkgs/"
|
|
||||||
@end
|
|
||||||
|
|
||||||
@if release or quick:
|
|
||||||
obj_checks:off
|
|
||||||
field_checks:off
|
|
||||||
range_checks:off
|
|
||||||
bound_checks:off
|
|
||||||
overflow_checks:off
|
|
||||||
assertions:off
|
|
||||||
stacktrace:off
|
|
||||||
linetrace:off
|
|
||||||
debugger:off
|
|
||||||
line_dir:off
|
|
||||||
dead_code_elim:on
|
|
||||||
@end
|
|
||||||
|
|
||||||
@if release:
|
|
||||||
opt:speed
|
|
||||||
@end
|
|
||||||
|
|
||||||
# additional options always passed to the compiler:
|
|
||||||
--parallel_build: "0" # 0 to auto-detect number of processors
|
|
||||||
|
|
||||||
hint[LineTooLong]=off
|
|
||||||
#hint[XDeclaredButNotUsed]=off
|
|
||||||
|
|
||||||
@if unix:
|
|
||||||
@if not bsd:
|
|
||||||
# -fopenmp
|
|
||||||
gcc.options.linker = "-ldl"
|
|
||||||
gpp.options.linker = "-ldl"
|
|
||||||
clang.options.linker = "-ldl"
|
|
||||||
tcc.options.linker = "-ldl"
|
|
||||||
@end
|
|
||||||
@if bsd or haiku:
|
|
||||||
# BSD got posix_spawn only recently, so we deactivate it for osproc:
|
|
||||||
define:useFork
|
|
||||||
# at least NetBSD has problems with thread local storage:
|
|
||||||
tlsEmulation:on
|
|
||||||
@end
|
|
||||||
@end
|
|
||||||
|
|
||||||
# Configuration for the Intel C/C++ compiler:
|
|
||||||
@if windows:
|
|
||||||
icl.options.speed = "/Ox /arch:SSE2"
|
|
||||||
icl.options.always = "/nologo"
|
|
||||||
@end
|
|
||||||
|
|
||||||
# Configuration for the GNU C/C++ compiler:
|
|
||||||
@if windows:
|
|
||||||
#gcc.path = r"$nimrod\dist\mingw\bin"
|
|
||||||
@if gcc:
|
|
||||||
tlsEmulation:on
|
|
||||||
@end
|
|
||||||
@end
|
|
||||||
|
|
||||||
@if macosx:
|
|
||||||
cc = clang
|
|
||||||
tlsEmulation:on
|
|
||||||
gcc.options.always = "-w -fasm-blocks"
|
|
||||||
gpp.options.always = "-w -fasm-blocks -fpermissive"
|
|
||||||
@else:
|
|
||||||
gcc.options.always = "-w"
|
|
||||||
gpp.options.always = "-w -fpermissive"
|
|
||||||
@end
|
|
||||||
|
|
||||||
gcc.options.speed = "-O3 -fno-strict-aliasing"
|
|
||||||
gcc.options.size = "-Os"
|
|
||||||
gcc.options.debug = "-g3 -O0"
|
|
||||||
|
|
||||||
gpp.options.speed = "-O3 -fno-strict-aliasing"
|
|
||||||
gpp.options.size = "-Os"
|
|
||||||
gpp.options.debug = "-g3 -O0"
|
|
||||||
#passl = "-pg"
|
|
||||||
|
|
||||||
# Configuration for the LLVM GCC compiler:
|
|
||||||
llvm_gcc.options.debug = "-g"
|
|
||||||
llvm_gcc.options.always = "-w"
|
|
||||||
llvm_gcc.options.speed = "-O2"
|
|
||||||
llvm_gcc.options.size = "-Os"
|
|
||||||
|
|
||||||
# Configuration for the LLVM CLang compiler:
|
|
||||||
clang.options.debug = "-g"
|
|
||||||
clang.options.always = "-w"
|
|
||||||
clang.options.speed = "-O3"
|
|
||||||
clang.options.size = "-Os"
|
|
||||||
|
|
||||||
# Configuration for the Visual C/C++ compiler:
|
|
||||||
vcc.options.linker = "/DEBUG /Zi /Fd\"$projectName.pdb\" /F33554432" # set the stack size to 8 MB
|
|
||||||
vcc.options.debug = "/Zi /Fd\"$projectName.pdb\""
|
|
||||||
vcc.options.always = "/nologo"
|
|
||||||
vcc.options.speed = "/Ox /arch:SSE2"
|
|
||||||
vcc.options.size = "/O1"
|
|
||||||
|
|
||||||
# Configuration for the Tiny C Compiler:
|
|
||||||
tcc.options.always = "-w"
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
=====================================================
|
=====================================================
|
||||||
Nim -- a Compiler for Nim. http://nim-lang.org/
|
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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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).
|
||||||
|
|
||||||
|
|
|
||||||
14
doc/lib.txt
14
doc/lib.txt
|
|
@ -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>`_
|
||||||
|
|
|
||||||
|
|
@ -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 ^* ',' ']'
|
||||||
|
|
|
||||||
|
|
@ -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``
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
14
doc/tut2.txt
14
doc/tut2.txt
|
|
@ -37,7 +37,7 @@ Object Oriented Programming
|
||||||
While Nim's support for object oriented programming (OOP) is minimalistic,
|
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
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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'.
|
||||||
|
|
@ -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 =
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -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"
|
||||||
|
|
@ -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:
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue