diff options
author | Simon Hafner <hafnersimon@gmail.com> | 2015-03-05 14:44:54 -0600 |
---|---|---|
committer | Simon Hafner <hafnersimon@gmail.com> | 2015-03-05 14:44:54 -0600 |
commit | 70eaf92ff0493ed11c6e6c8887bca1b235371aff (patch) | |
tree | 530255b69df349728c76621e97bf40a11d63fe79 | |
parent | f592240c545506448e2bea78a2fa3404c7f46e69 (diff) | |
parent | 8f43979cf6308c9d7e14a0d87c0faf227e1c4afe (diff) | |
download | Nim-70eaf92ff0493ed11c6e6c8887bca1b235371aff.tar.gz |
Merge branch 'devel' into warning-for-result
356 files changed, 6122 insertions, 3809 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index d487b5380..1462d58d5 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -314,7 +314,7 @@ type # XXX put this into an include file to avoid this issue! tyNone, tyBool, tyChar, tyEmpty, tyArrayConstr, tyNil, tyExpr, tyStmt, tyTypeDesc, - tyGenericInvokation, # ``T[a, b]`` for types to invoke + tyGenericInvocation, # ``T[a, b]`` for types to invoke tyGenericBody, # ``T[a, b, body]`` last parameter is the body tyGenericInst, # ``T[a, b, realInstance]`` instantiated generic type # realInstance will be a concrete type like tyObject @@ -377,7 +377,7 @@ type tyFromExpr #\ # This is a type representing an expression that depends - # on generic parameters (the exprsesion is stored in t.n) + # on generic parameters (the expression is stored in t.n) # It will be converted to a real type only during generic # instantiation and prior to this it has the potential to # be any type. @@ -459,7 +459,7 @@ type tfNeedsInit, # type constains a "not nil" constraint somewhere or some # other type so that it requires inititalization - tfHasShared, # type constains a "shared" constraint modifier somewhere + tfVarIsPtr, # 'var' type is translated like 'ptr' even in C++ mode tfHasMeta, # type contains "wildcard" sub-types such as generic params # or other type classes tfHasGCedMem, # type contains GC'ed memory @@ -522,7 +522,7 @@ const skError* = skUnknown # type flags that are essential for type equality: - eqTypeFlags* = {tfIterator, tfShared, tfNotNil} + eqTypeFlags* = {tfIterator, tfShared, tfNotNil, tfVarIsPtr} type TMagic* = enum # symbols that require compiler magic: @@ -655,7 +655,6 @@ type locGlobalVar, # location is a global variable locParam, # location is a parameter locField, # location is a record field - locArrayElem, # location is an array element locExpr, # "location" is really an expression locProc, # location is a proc (an address of a procedure) locData, # location is a constant @@ -669,14 +668,15 @@ type lfDynamicLib, # link symbol to dynamic library lfExportLib, # export symbol for dynamic library generation lfHeader, # include header file for symbol - lfImportCompilerProc # ``importc`` of a compilerproc + lfImportCompilerProc, # ``importc`` of a compilerproc + lfSingleUse # no location yet and will only be used once TStorageLoc* = enum OnUnknown, # location is unknown (stack, heap or static) OnStack, # location is on hardware stack OnHeap # location is on heap or global # (reference counting needed) TLocFlags* = set[TLocFlag] - TLoc*{.final.} = object + TLoc* = object k*: TLocKind # kind of location s*: TStorageLoc flags*: TLocFlags # location's flags @@ -859,7 +859,7 @@ const OverloadableSyms* = {skProc, skMethod, skIterator, skClosureIterator, skConverter, skModule, skTemplate, skMacro} - GenericTypes*: TTypeKinds = {tyGenericInvokation, tyGenericBody, + GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody, tyGenericParam} StructuralEquivTypes*: TTypeKinds = {tyArrayConstr, tyNil, tyTuple, tyArray, @@ -918,50 +918,6 @@ const # only used when 'gCmd == cmdPretty': Indicates that the symbol has been # imported via 'importc: "fullname"' and no format string. -# creator procs: -proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, - info: TLineInfo): PSym -proc newType*(kind: TTypeKind, owner: PSym): PType -proc newNode*(kind: TNodeKind): PNode -proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode -proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode -proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode -proc newStrNode*(kind: TNodeKind, strVal: string): PNode -proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode -proc newSymNode*(sym: PSym): PNode -proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode -proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode -proc initStrTable*(x: var TStrTable) -proc initTable*(x: var TTable) -proc initIdTable*(x: var TIdTable) -proc initObjectSet*(x: var TObjectSet) -proc initIdNodeTable*(x: var TIdNodeTable) -proc initNodeTable*(x: var TNodeTable) - -# copy procs: -proc copyType*(t: PType, owner: PSym, keepId: bool): PType -proc copySym*(s: PSym, keepId: bool = false): PSym -proc assignType*(dest, src: PType) -proc copyStrTable*(dest: var TStrTable, src: TStrTable) -proc copyTable*(dest: var TTable, src: TTable) -proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) -proc copyIdTable*(dest: var TIdTable, src: TIdTable) -proc sonsLen*(n: PNode): int {.inline.} -proc sonsLen*(n: PType): int {.inline.} -proc lastSon*(n: PNode): PNode {.inline.} -proc lastSon*(n: PType): PType {.inline.} -proc newSons*(father: PNode, length: int) -proc newSons*(father: PType, length: int) -proc addSon*(father, son: PNode) -proc delSon*(father: PNode, idx: int) -proc hasSonWith*(n: PNode, kind: TNodeKind): bool -proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool -proc replaceSons*(n: PNode, oldKind, newKind: TNodeKind) -proc copyNode*(src: PNode): PNode - # does not copy its sons! -proc copyTree*(src: PNode): PNode - # does copy its sons! - proc isCallExpr*(n: PNode): bool = result = n.kind in nkCallKinds @@ -988,7 +944,61 @@ proc `[]`*(n: PNode, i: int): PNode {.inline.} = template `{}`*(n: PNode, i: int): expr = n[i -| n] template `{}=`*(n: PNode, i: int, s: PNode): stmt = n.sons[i -| n] = s - + +when defined(useNodeIds): + const nodeIdToDebug* = -1 # 884953 # 612794 + #612840 # 612905 # 614635 # 614637 # 614641 + # 423408 + #429107 # 430443 # 441048 # 441090 # 441153 + var gNodeId: int + +proc newNode*(kind: TNodeKind): PNode = + new(result) + result.kind = kind + #result.info = UnknownLineInfo() inlined: + result.info.fileIndex = int32(- 1) + result.info.col = int16(- 1) + result.info.line = int16(- 1) + when defined(useNodeIds): + result.id = gNodeId + if result.id == nodeIdToDebug: + echo "KIND ", result.kind + writeStackTrace() + inc gNodeId + +proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode = + result = newNode(kind) + result.intVal = intVal + +proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode = + result = newIntNode(kind, intVal) + result.typ = typ + +proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode = + result = newNode(kind) + result.floatVal = floatVal + +proc newStrNode*(kind: TNodeKind, strVal: string): PNode = + result = newNode(kind) + result.strVal = strVal + +proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, + info: TLineInfo): PSym = + # generates a symbol and initializes the hash field too + new(result) + result.name = name + result.kind = symKind + result.flags = {} + result.info = info + result.options = gOptions + result.owner = owner + result.offset = - 1 + result.id = getID() + when debugIds: + registerId(result) + #if result.id < 2000: + # MessageOut(name.s & " has id: " & toString(result.id)) + var emptyNode* = newNode(nkEmpty) # There is a single empty node that is shared! Do not overwrite it! @@ -1031,80 +1041,43 @@ const # for all kind of hash tables: GrowthFactor* = 2 # must be power of 2, > 0 StartSize* = 8 # must be power of 2, > 0 -proc copyStrTable(dest: var TStrTable, src: TStrTable) = +proc copyStrTable*(dest: var TStrTable, src: TStrTable) = dest.counter = src.counter if isNil(src.data): return setLen(dest.data, len(src.data)) for i in countup(0, high(src.data)): dest.data[i] = src.data[i] -proc copyIdTable(dest: var TIdTable, src: TIdTable) = +proc copyIdTable*(dest: var TIdTable, src: TIdTable) = dest.counter = src.counter if isNil(src.data): return newSeq(dest.data, len(src.data)) for i in countup(0, high(src.data)): dest.data[i] = src.data[i] -proc copyTable(dest: var TTable, src: TTable) = +proc copyTable*(dest: var TTable, src: TTable) = dest.counter = src.counter if isNil(src.data): return setLen(dest.data, len(src.data)) for i in countup(0, high(src.data)): dest.data[i] = src.data[i] -proc copyObjectSet(dest: var TObjectSet, src: TObjectSet) = +proc copyObjectSet*(dest: var TObjectSet, src: TObjectSet) = dest.counter = src.counter if isNil(src.data): return setLen(dest.data, len(src.data)) for i in countup(0, high(src.data)): dest.data[i] = src.data[i] -proc discardSons(father: PNode) = +proc discardSons*(father: PNode) = father.sons = nil -when defined(useNodeIds): - const nodeIdToDebug* = -1 # 884953 # 612794 - #612840 # 612905 # 614635 # 614637 # 614641 - # 423408 - #429107 # 430443 # 441048 # 441090 # 441153 - var gNodeId: int - -proc newNode(kind: TNodeKind): PNode = - new(result) - result.kind = kind - #result.info = UnknownLineInfo() inlined: - result.info.fileIndex = int32(- 1) - result.info.col = int16(- 1) - result.info.line = int16(- 1) - when defined(useNodeIds): - result.id = gNodeId - if result.id == nodeIdToDebug: - echo "KIND ", result.kind - writeStackTrace() - inc gNodeId - -proc newIntNode(kind: TNodeKind, intVal: BiggestInt): PNode = - result = newNode(kind) - result.intVal = intVal - -proc newIntTypeNode(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode = - result = newIntNode(kind, intVal) - result.typ = typ - -proc newFloatNode(kind: TNodeKind, floatVal: BiggestFloat): PNode = - result = newNode(kind) - result.floatVal = floatVal - -proc newStrNode(kind: TNodeKind, strVal: string): PNode = - result = newNode(kind) - result.strVal = strVal - proc withInfo*(n: PNode, info: TLineInfo): PNode = n.info = info return n -proc newIdentNode(ident: PIdent, info: TLineInfo): PNode = +proc newIdentNode*(ident: PIdent, info: TLineInfo): PNode = result = newNode(nkIdent) result.ident = ident result.info = info -proc newSymNode(sym: PSym): PNode = +proc newSymNode*(sym: PSym): PNode = result = newNode(nkSym) result.sym = sym result.typ = sym.typ @@ -1116,7 +1089,7 @@ proc newSymNode*(sym: PSym, info: TLineInfo): PNode = result.typ = sym.typ result.info = info -proc newNodeI(kind: TNodeKind, info: TLineInfo): PNode = +proc newNodeI*(kind: TNodeKind, info: TLineInfo): PNode = new(result) result.kind = kind result.info = info @@ -1155,11 +1128,16 @@ proc newNode*(kind: TNodeKind, info: TLineInfo, sons: TNodeSeq = @[], writeStackTrace() inc gNodeId -proc newNodeIT(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = +proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode = result = newNode(kind) result.info = info result.typ = typ +proc addSon*(father, son: PNode) = + assert son != nil + if isNil(father.sons): father.sons = @[] + add(father.sons, son) + var emptyParams = newNode(nkFormalParams) emptyParams.addSon(emptyNode) @@ -1181,7 +1159,7 @@ proc `$`*(x: TLockLevel): string = elif x.ord == UnknownLockLevel.ord: result = "<unknown>" else: result = $int16(x) -proc newType(kind: TTypeKind, owner: PSym): PType = +proc newType*(kind: TTypeKind, owner: PSym): PType = new(result) result.kind = kind result.owner = owner @@ -1201,8 +1179,38 @@ proc mergeLoc(a: var TLoc, b: TLoc) = if a.t == nil: a.t = b.t if a.r == nil: a.r = b.r #if a.a == 0: a.a = b.a + +proc newSons*(father: PNode, length: int) = + if isNil(father.sons): + newSeq(father.sons, length) + else: + setLen(father.sons, length) + +proc newSons*(father: PType, length: int) = + if isNil(father.sons): + newSeq(father.sons, length) + else: + setLen(father.sons, length) + +proc sonsLen*(n: PType): int = + if isNil(n.sons): result = 0 + else: result = len(n.sons) + +proc len*(n: PType): int = + if isNil(n.sons): result = 0 + else: result = len(n.sons) + +proc sonsLen*(n: PNode): int = + if isNil(n.sons): result = 0 + else: result = len(n.sons) -proc assignType(dest, src: PType) = +proc lastSon*(n: PNode): PNode = + result = n.sons[sonsLen(n) - 1] + +proc lastSon*(n: PType): PType = + result = n.sons[sonsLen(n) - 1] + +proc assignType*(dest, src: PType) = dest.kind = src.kind dest.flags = src.flags dest.callConv = src.callConv @@ -1223,7 +1231,7 @@ proc assignType(dest, src: PType) = newSons(dest, sonsLen(src)) for i in countup(0, sonsLen(src) - 1): dest.sons[i] = src.sons[i] -proc copyType(t: PType, owner: PSym, keepId: bool): PType = +proc copyType*(t: PType, owner: PSym, keepId: bool): PType = result = newType(t.kind, owner) assignType(result, t) if keepId: @@ -1232,7 +1240,7 @@ proc copyType(t: PType, owner: PSym, keepId: bool): PType = when debugIds: registerId(result) result.sym = t.sym # backend-info should not be copied -proc copySym(s: PSym, keepId: bool = false): PSym = +proc copySym*(s: PSym, keepId: bool = false): PSym = result = newSym(s.kind, s.name, s.owner, s.info) #result.ast = nil # BUGFIX; was: s.ast which made problems result.typ = s.typ @@ -1266,24 +1274,7 @@ proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym = # XXX once usedGenerics is used, ensure module aliases keep working! assert s.usedGenerics == nil -proc newSym(symKind: TSymKind, name: PIdent, owner: PSym, - info: TLineInfo): PSym = - # generates a symbol and initializes the hash field too - new(result) - result.name = name - result.kind = symKind - result.flags = {} - result.info = info - result.options = gOptions - result.owner = owner - result.offset = - 1 - result.id = getID() - when debugIds: - registerId(result) - #if result.id < 2000: - # MessageOut(name.s & " has id: " & toString(result.id)) - -proc initStrTable(x: var TStrTable) = +proc initStrTable*(x: var TStrTable) = x.counter = 0 newSeq(x.data, StartSize) @@ -1294,45 +1285,27 @@ proc initTable(x: var TTable) = x.counter = 0 newSeq(x.data, StartSize) -proc initIdTable(x: var TIdTable) = +proc initIdTable*(x: var TIdTable) = x.counter = 0 newSeq(x.data, StartSize) -proc initObjectSet(x: var TObjectSet) = +proc resetIdTable*(x: var TIdTable) = x.counter = 0 - newSeq(x.data, StartSize) + # clear and set to old initial size: + setLen(x.data, 0) + setLen(x.data, StartSize) -proc initIdNodeTable(x: var TIdNodeTable) = +proc initObjectSet*(x: var TObjectSet) = x.counter = 0 newSeq(x.data, StartSize) -proc initNodeTable(x: var TNodeTable) = +proc initIdNodeTable*(x: var TIdNodeTable) = x.counter = 0 newSeq(x.data, StartSize) -proc sonsLen(n: PType): int = - if isNil(n.sons): result = 0 - else: result = len(n.sons) - -proc len*(n: PType): int = - if isNil(n.sons): result = 0 - else: result = len(n.sons) - -proc newSons(father: PType, length: int) = - if isNil(father.sons): - newSeq(father.sons, length) - else: - setLen(father.sons, length) - -proc sonsLen(n: PNode): int = - if isNil(n.sons): result = 0 - else: result = len(n.sons) - -proc newSons(father: PNode, length: int) = - if isNil(father.sons): - newSeq(father.sons, length) - else: - setLen(father.sons, length) +proc initNodeTable*(x: var TNodeTable) = + x.counter = 0 + newSeq(x.data, StartSize) proc skipTypes*(t: PType, kinds: TTypeKinds): PType = ## Used throughout the compiler code to test whether a type tree contains or @@ -1348,9 +1321,9 @@ proc isGCedMem*(t: PType): bool {.inline.} = proc propagateToOwner*(owner, elem: PType) = const HaveTheirOwnEmpty = {tySequence, tySet} - owner.flags = owner.flags + (elem.flags * {tfHasShared, tfHasMeta}) + owner.flags = owner.flags + (elem.flags * {tfHasMeta}) if tfNotNil in elem.flags: - if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvokation}: + if owner.kind in {tyGenericInst, tyGenericBody, tyGenericInvocation}: owner.flags.incl tfNotNil elif owner.kind notin HaveTheirOwnEmpty: owner.flags.incl tfNeedsInit @@ -1359,9 +1332,6 @@ proc propagateToOwner*(owner, elem: PType) = if owner.kind in HaveTheirOwnEmpty: discard else: owner.flags.incl tfNeedsInit - if tfShared in elem.flags: - owner.flags.incl tfHasShared - if elem.isMetaType: owner.flags.incl tfHasMeta @@ -1374,22 +1344,17 @@ proc rawAddSon*(father, son: PType) = add(father.sons, son) if not son.isNil: propagateToOwner(father, son) -proc addSon(father, son: PNode) = - assert son != nil - if isNil(father.sons): father.sons = @[] - add(father.sons, son) - proc addSonNilAllowed*(father, son: PNode) = if isNil(father.sons): father.sons = @[] add(father.sons, son) -proc delSon(father: PNode, idx: int) = +proc delSon*(father: PNode, idx: int) = if isNil(father.sons): return var length = sonsLen(father) for i in countup(idx, length - 2): father.sons[i] = father.sons[i + 1] setLen(father.sons, length - 1) -proc copyNode(src: PNode): PNode = +proc copyNode*(src: PNode): PNode = # does not copy its sons! if src == nil: return nil @@ -1426,7 +1391,7 @@ proc shallowCopy*(src: PNode): PNode = of nkStrLit..nkTripleStrLit: result.strVal = src.strVal else: newSeq(result.sons, sonsLen(src)) -proc copyTree(src: PNode): PNode = +proc copyTree*(src: PNode): PNode = # copy a whole syntax tree; performs deep copying if src == nil: return nil @@ -1447,14 +1412,8 @@ proc copyTree(src: PNode): PNode = newSeq(result.sons, sonsLen(src)) for i in countup(0, sonsLen(src) - 1): result.sons[i] = copyTree(src.sons[i]) - -proc lastSon(n: PNode): PNode = - result = n.sons[sonsLen(n) - 1] - -proc lastSon(n: PType): PType = - result = n.sons[sonsLen(n) - 1] -proc hasSonWith(n: PNode, kind: TNodeKind): bool = +proc hasSonWith*(n: PNode, kind: TNodeKind): bool = for i in countup(0, sonsLen(n) - 1): if n.sons[i].kind == kind: return true @@ -1476,7 +1435,7 @@ proc containsNode*(n: PNode, kinds: TNodeKinds): bool = for i in countup(0, sonsLen(n) - 1): if n.kind in kinds or containsNode(n.sons[i], kinds): return true -proc hasSubnodeWith(n: PNode, kind: TNodeKind): bool = +proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool = case n.kind of nkEmpty..nkNilLit: result = n.kind == kind else: diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index f23e9a983..8d132ab26 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -130,8 +130,8 @@ proc skipConvAndClosure*(n: PNode): PNode = proc sameValue*(a, b: PNode): bool = result = false case a.kind - of nkCharLit..nkInt64Lit: - if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal == b.intVal + of nkCharLit..nkUInt64Lit: + if b.kind in {nkCharLit..nkUInt64Lit}: result = a.intVal == b.intVal of nkFloatLit..nkFloat64Lit: if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: @@ -145,13 +145,13 @@ proc leValue*(a, b: PNode): bool = # a <= b? result = false case a.kind - of nkCharLit..nkInt64Lit: - if b.kind in {nkCharLit..nkInt64Lit}: result = a.intVal <= b.intVal - of nkFloatLit..nkFloat64Lit: + of nkCharLit..nkUInt32Lit: + if b.kind in {nkCharLit..nkUInt32Lit}: result = a.intVal <= b.intVal + of nkFloatLit..nkFloat64Lit: if b.kind in {nkFloatLit..nkFloat64Lit}: result = a.floatVal <= b.floatVal - of nkStrLit..nkTripleStrLit: + of nkStrLit..nkTripleStrLit: if b.kind in {nkStrLit..nkTripleStrLit}: result = a.strVal <= b.strVal - else: + else: # don't raise an internal error for 'nimrod check': #InternalError(a.info, "leValue") discard @@ -387,6 +387,9 @@ proc debugType(n: PType, maxRecDepth=100): PRope = if n.sym != nil: app(result, " ") app(result, n.sym.name.s) + if n.kind in IntegralTypes and n.n != nil: + app(result, ", node: ") + app(result, debugTree(n.n, 2, maxRecDepth-1, renderType=true)) if (n.kind != tyString) and (sonsLen(n) > 0) and maxRecDepth != 0: app(result, "(") for i in countup(0, sonsLen(n) - 1): @@ -445,21 +448,21 @@ proc debugTree(n: PNode, indent: int, maxRecDepth: int; proc debug(n: PSym) = if n == nil: - writeln(stdout, "null") + msgWriteln("null") elif n.kind == skUnknown: - writeln(stdout, "skUnknown") + msgWriteln("skUnknown") else: #writeln(stdout, ropeToStr(symToYaml(n, 0, 1))) - writeln(stdout, "$1_$2: $3, $4, $5, $6" % [ + msgWriteln("$1_$2: $3, $4, $5, $6" % [ n.name.s, $n.id, flagsToStr(n.flags).ropeToStr, flagsToStr(n.loc.flags).ropeToStr, lineInfoToStr(n.info).ropeToStr, $n.kind]) proc debug(n: PType) = - writeln(stdout, ropeToStr(debugType(n))) + msgWriteln(ropeToStr(debugType(n))) proc debug(n: PNode) = - writeln(stdout, ropeToStr(debugTree(n, 0, 100))) + msgWriteln(ropeToStr(debugTree(n, 0, 100))) const EmptySeq = @[] @@ -678,9 +681,8 @@ proc initIdentIter(ti: var TIdentIter, tab: TStrTable, s: PIdent): PSym = else: result = nextIdentIter(ti, tab) proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = - var h, start: THash - h = ti.h and high(tab.data) - start = h + var h = ti.h and high(tab.data) + var start = h result = tab.data[h] while result != nil: if result.name.id == ti.name.id: break diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim index 02010961d..50d3fd017 100644 --- a/compiler/canonicalizer.nim +++ b/compiler/canonicalizer.nim @@ -119,8 +119,8 @@ proc hashType(c: var MD5Context, t: PType) = c.hashSym(t.sym) case t.kind - of tyGenericBody, tyGenericInst, tyGenericInvokation: - for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)): + of tyGenericBody, tyGenericInst, tyGenericInvocation: + for i in countup(0, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)): c.hashType t.sons[i] of tyUserTypeClass: internalAssert t.sym != nil and t.sym.owner != nil diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index cb8dcc25b..200ff91e0 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -45,12 +45,20 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc, genAssignment(p, d, tmp, {}) # no need for deep copying else: app(pl, ~")") - if d.k == locNone: getTemp(p, typ.sons[0], d) - assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.t, OnUnknown) - list.r = pl - genAssignment(p, d, list, {}) # no need for deep copying + if p.module.compileToCpp and lfSingleUse in d.flags: + # do not generate spurious temporaries for C++! For C we're better off + # with them to prevent undefined behaviour and because the codegen + # is free to emit expressions multiple times! + d.k = locCall + d.r = pl + excl d.flags, lfSingleUse + else: + if d.k == locNone: getTemp(p, typ.sons[0], d) + assert(d.t != nil) # generate an assignment to d: + var list: TLoc + initLoc(list, locCall, d.t, OnUnknown) + list.r = pl + genAssignment(p, d, list, {}) # no need for deep copying else: app(pl, ~");$n") line(p, cpsStmts, pl) @@ -90,7 +98,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope = of tyOpenArray, tyVarargs, tyArray, tyArrayConstr: "($1)+($2), ($3)-($2)+1" of tyString, tySequence: - if skipTypes(n.typ, abstractInst).kind == tyVar: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): "(*$1)->data+($2), ($3)-($2)+1" else: "$1->data+($2), ($3)-($2)+1" @@ -102,7 +111,8 @@ proc openArrayLoc(p: BProc, n: PNode): PRope = of tyOpenArray, tyVarargs: result = ropef("$1, $1Len0", [rdLoc(a)]) of tyString, tySequence: - if skipTypes(n.typ, abstractInst).kind == tyVar: + if skipTypes(n.typ, abstractInst).kind == tyVar and + not compileToCpp(p.module): result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)]) else: result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)]) @@ -114,8 +124,8 @@ proc genArgStringToCString(p: BProc, n: PNode): PRope {.inline.} = var a: TLoc initLocExpr(p, n.sons[0], a) result = ropef("$1->data", [a.rdLoc]) - -proc genArg(p: BProc, n: PNode, param: PSym): PRope = + +proc genArg(p: BProc, n: PNode, param: PSym; call: PNode): PRope = var a: TLoc if n.kind == nkStringToCString: result = genArgStringToCString(p, n) @@ -125,8 +135,20 @@ proc genArg(p: BProc, n: PNode, param: PSym): PRope = elif ccgIntroducedPtr(param): initLocExpr(p, n, a) result = addrLoc(a) + elif p.module.compileToCpp and param.typ.kind == tyVar and + n.kind == nkHiddenAddr: + initLocExprSingleUse(p, n.sons[0], a) + # if the proc is 'importc'ed but not 'importcpp'ed then 'var T' still + # means '*T'. See posix.nim for lots of examples that do that in the wild. + let callee = call.sons[0] + if callee.kind == nkSym and + {sfImportC, sfInfixCall, sfCompilerProc} * callee.sym.flags == {sfImportC} and + {lfHeader, lfNoDecl} * callee.sym.loc.flags != {}: + result = addrLoc(a) + else: + result = rdLoc(a) else: - initLocExpr(p, n, a) + initLocExprSingleUse(p, n, a) result = rdLoc(a) proc genArgNoParam(p: BProc, n: PNode): PRope = @@ -134,7 +156,7 @@ proc genArgNoParam(p: BProc, n: PNode): PRope = if n.kind == nkStringToCString: result = genArgStringToCString(p, n) else: - initLocExpr(p, n, a) + initLocExprSingleUse(p, n, a) result = rdLoc(a) proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = @@ -152,7 +174,7 @@ proc genPrefixCall(p: BProc, le, ri: PNode, d: var TLoc) = if params != nil: app(params, ~", ") if i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) - app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym)) + app(params, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) else: app(params, genArgNoParam(p, ri.sons[i])) fixupCall(p, le, ri, d, op.r, params) @@ -178,7 +200,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) = assert(sonsLen(typ) == sonsLen(typ.n)) if i < sonsLen(typ): assert(typ.n.sons[i].kind == nkSym) - app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym)) + app(pl, genArg(p, ri.sons[i], typ.n.sons[i].sym, ri)) else: app(pl, genArgNoParam(p, ri.sons[i])) if i < length - 1: app(pl, ~", ") @@ -274,26 +296,28 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope = assert(typ.n.sons[i].kind == nkSym) # if the parameter is lying (tyVar) and thus we required an additional deref, # skip the deref: + var ri = ri[i] + while ri.kind == nkObjDownConv: ri = ri[0] if typ.sons[i].kind == tyVar: - let x = if ri[i].kind == nkHiddenAddr: ri[i][0] else: ri[i] - if x.kind in {nkHiddenDeref, nkDerefExpr}: - result = genArgNoParam(p, x[0]) - result.app("->") - elif x.typ.kind in {tyVar, tyPtr}: + let x = if ri.kind == nkHiddenAddr: ri[0] else: ri + if x.typ.kind == tyPtr: result = genArgNoParam(p, x) result.app("->") + elif x.kind in {nkHiddenDeref, nkDerefExpr} and x[0].typ.kind == tyPtr: + result = genArgNoParam(p, x[0]) + result.app("->") else: result = genArgNoParam(p, x) result.app(".") elif typ.sons[i].kind == tyPtr: - if ri.sons[i].kind in {nkAddr, nkHiddenAddr}: - result = genArgNoParam(p, ri.sons[i][0]) + if ri.kind in {nkAddr, nkHiddenAddr}: + result = genArgNoParam(p, ri[0]) result.app(".") else: - result = genArgNoParam(p, ri.sons[i]) + result = genArgNoParam(p, ri) result.app("->") else: - result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym) + result = genArgNoParam(p, ri) #, typ.n.sons[i].sym) result.app(".") proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope = @@ -367,12 +391,20 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) = # simpler version of 'fixupCall' that works with the pl+params combination: var typ = skipTypes(ri.sons[0].typ, abstractInst) if typ.sons[0] != nil: - if d.k == locNone: getTemp(p, typ.sons[0], d) - assert(d.t != nil) # generate an assignment to d: - var list: TLoc - initLoc(list, locCall, d.t, OnUnknown) - list.r = pl - genAssignment(p, d, list, {}) # no need for deep copying + if p.module.compileToCpp and lfSingleUse in d.flags: + # do not generate spurious temporaries for C++! For C we're better off + # with them to prevent undefined behaviour and because the codegen + # is free to emit expressions multiple times! + d.k = locCall + d.r = pl + excl d.flags, lfSingleUse + else: + if d.k == locNone: getTemp(p, typ.sons[0], d) + assert(d.t != nil) # generate an assignment to d: + var list: TLoc + initLoc(list, locCall, d.t, OnUnknown) + list.r = pl + genAssignment(p, d, list, {}) # no need for deep copying else: app(pl, ~";$n") line(p, cpsStmts, pl) @@ -398,15 +430,27 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = assert(typ.kind == tyProc) var length = sonsLen(ri) assert(sonsLen(typ) == sonsLen(typ.n)) - - if length > 1: - app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym)) - app(pl, ~" ") - app(pl, op.r) - if length > 2: - app(pl, ~": ") - app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym)) - for i in countup(3, length-1): + + # don't call 'ropeToStr' here for efficiency: + let pat = ri.sons[0].sym.loc.r.data + internalAssert pat != nil + var start = 3 + if ' ' in pat: + start = 1 + app(pl, op.r) + if length > 1: + app(pl, ~": ") + app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri)) + start = 2 + else: + if length > 1: + app(pl, genArg(p, ri.sons[1], typ.n.sons[1].sym, ri)) + app(pl, ~" ") + app(pl, op.r) + if length > 2: + app(pl, ~": ") + app(pl, genArg(p, ri.sons[2], typ.n.sons[2].sym, ri)) + for i in countup(start, length-1): assert(sonsLen(typ) == sonsLen(typ.n)) if i >= sonsLen(typ): internalError(ri.info, "varargs for objective C method?") @@ -415,7 +459,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) = app(pl, ~" ") app(pl, param.name.s) app(pl, ~": ") - app(pl, genArg(p, ri.sons[i], param)) + app(pl, genArg(p, ri.sons[i], param, ri)) if typ.sons[0] != nil: if isInvalidReturnType(typ.sons[0]): if sonsLen(ri) > 1: app(pl, ~" ") diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 93bb5dbf5..5f5aa6308 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -56,11 +56,6 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope = case skipTypes(ty, abstractVarRange).kind of tyChar, tyNil: result = intLiteral(n.intVal) - of tyInt: - if n.intVal >= low(int32) and n.intVal <= high(int32): - result = int32Literal(int32(n.intVal)) - else: - result = intLiteral(n.intVal) of tyBool: if n.intVal != 0: result = ~"NIM_TRUE" else: result = ~"NIM_FALSE" @@ -83,11 +78,13 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): PRope = else: result = toRope("NIM_NIL") of nkStrLit..nkTripleStrLit: - if skipTypes(ty, abstractVarRange).kind == tyString: + if n.strVal.isNil: + result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", []) + elif skipTypes(ty, abstractVarRange).kind == tyString: var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) if id == gBackendId: # string literal not found in the cache: - result = ropecg(p.module, "((#NimStringDesc*) &$1)", + result = ropecg(p.module, "((#NimStringDesc*) &$1)", [getStrLit(p.module, n.strVal)]) else: result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [toRope(id)]) @@ -156,7 +153,7 @@ proc getStorageLoc(n: PNode): TStorageLoc = of skVar, skForVar, skResult, skLet: if sfGlobal in n.sym.flags: result = OnHeap else: result = OnStack - of skConst: + of skConst: if sfGlobal in n.sym.flags: result = OnHeap else: result = OnUnknown else: result = OnUnknown @@ -234,7 +231,7 @@ proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = for i in 0 .. <t.len: let t = t.sons[i] let field = ropef("Field$1", i.toRope) - genAssignment(p, optAsgnLoc(dest, t, field), + genAssignment(p, optAsgnLoc(dest, t, field), optAsgnLoc(src, t, field), newflags) proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, @@ -250,20 +247,20 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, case t.kind of nkSym: let field = t.sym - genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r), + genAssignment(p, optAsgnLoc(dest, field.typ, field.loc.r), optAsgnLoc(src, field.typ, field.loc.r), newflags) of nkRecList: for child in items(t): genOptAsgnObject(p, dest, src, newflags, child) else: discard proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = - # Consider: + # Consider: # type TMyFastString {.shallow.} = string # Due to the implementation of pragmas this would end up to set the # tfShallow flag for the built-in string type too! So we check only # here for this flag, where it is reasonably safe to do so # (for objects, etc.): - if needToCopy notin flags or + if needToCopy notin flags or tfShallow in skipTypes(dest.t, abstractVarRange).flags: if dest.s == OnStack or not usesNativeGC(): useStringh(p.module) @@ -508,7 +505,7 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = var storage: PRope var size = getSize(t) if size < platform.intSize: - storage = toRope("NI") + storage = toRope("NI") else: storage = getTypeDesc(p.module, t) var tmp = getTempName() @@ -545,7 +542,7 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = "(($4)($1) - ($4)($2))", # SubF64 "(($4)($1) * ($4)($2))", # MulF64 "(($4)($1) / ($4)($2))", # DivF64 - + "($4)((NU$3)($1) >> (NU$3)($2))", # ShrI "($4)((NU$3)($1) << (NU$3)($2))", # ShlI "($4)($1 & $2)", # BitandI @@ -615,7 +612,7 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) if a.t.callConv == ccClosure: - putIntoDest(p, d, e.typ, + putIntoDest(p, d, e.typ, ropef("($1.ClPrc == $2.ClPrc && $1.ClEnv == $2.ClEnv)", [ rdLoc(a), rdLoc(b)])) else: @@ -662,9 +659,14 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) = ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8), getSimpleTypeDesc(p.module, e.typ)])) +proc isCppRef(p: BProc; typ: PType): bool {.inline.} = + result = p.module.compileToCpp and + skipTypes(typ, abstractInst).kind == tyVar and + tfVarIsPtr notin skipTypes(typ, abstractInst).flags + proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = let mt = mapType(e.sons[0].typ) - if mt in {ctArray, ctPtrToArray} and not enforceDeref: + if (mt in {ctArray, ctPtrToArray} and not enforceDeref): # XXX the amount of hacks for C's arrays is incredible, maybe we should # simply wrap them in a struct? --> Losing auto vectorization then? #if e[0].kind != nkBracketExpr: @@ -672,12 +674,17 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = expr(p, e.sons[0], d) else: var a: TLoc - initLocExpr(p, e.sons[0], a) - case skipTypes(a.t, abstractInst).kind + initLocExprSingleUse(p, e.sons[0], a) + let typ = skipTypes(a.t, abstractInst) + case typ.kind of tyRef: d.s = OnHeap of tyVar: d.s = OnUnknown + if tfVarIsPtr notin typ.flags and p.module.compileToCpp and + e.kind == nkHiddenDeref: + putIntoDest(p, d, e.typ, rdLoc(a)) + return of tyPtr: d.s = OnUnknown # BUGFIX! else: internalError(e.info, "genDeref " & $a.t.kind) @@ -698,7 +705,7 @@ proc genAddr(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[0], a) putIntoDest(p, d, e.typ, con("&", a.r)) #Message(e.info, warnUser, "HERE NEW &") - elif mapType(e.sons[0].typ) == ctArray: + elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ): expr(p, e.sons[0], d) else: var a: TLoc @@ -709,7 +716,7 @@ template inheritLocation(d: var TLoc, a: TLoc) = if d.k == locNone: d.s = a.s if d.heapRoot == nil: d.heapRoot = if a.heapRoot != nil: a.heapRoot else: a.r - + proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType = initLocExpr(p, e.sons[0], a) if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux") @@ -916,6 +923,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = L: TLabel tmp: TLoc getTemp(p, e.typ, tmp) # force it into a temp! + inc p.splitDecls expr(p, e.sons[1], tmp) L = getLabel(p) if m == mOr: @@ -928,6 +936,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) = d = tmp else: genAssignment(p, d, tmp, {}) # no need for deep copying + dec p.splitDecls proc genEcho(p: BProc, n: PNode) = # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)`` @@ -938,7 +947,7 @@ proc genEcho(p: BProc, n: PNode) = var a: TLoc for i in countup(0, n.len-1): initLocExpr(p, n.sons[i], a) - appf(args, ", ($1)->data", [rdLoc(a)]) + appf(args, ", $1? ($1)->data:\"nil\"", [rdLoc(a)]) linefmt(p, cpsStmts, "printf($1$2);$n", makeCString(repeatStr(n.len, "%s") & tnl), args) @@ -1047,7 +1056,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = genAssignment(p, dest, b, {needToCopy, afDestIsNil}) gcUsage(e) -proc genReset(p: BProc, n: PNode) = +proc genReset(p: BProc, n: PNode) = var a: TLoc initLocExpr(p, n.sons[1], a) linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n", @@ -1106,14 +1115,14 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: PRope) = else: call.r = ropecg(p.module, "($1) #newSeq($2, $3)", args) genAssignment(p, dest, call, {needToKeepAlive}) - + proc genNewSeq(p: BProc, e: PNode) = var a, b: TLoc initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) genNewSeqAux(p, a, b.rdLoc) gcUsage(e) - + proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = var tmp: TLoc var t = e.typ.skipTypes(abstractInst) @@ -1154,7 +1163,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = d = tmp else: genAssignment(p, d, tmp, {}) - + proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) = var arr: TLoc if d.k == locNone: @@ -1178,7 +1187,7 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) = getTemp(p, t.typ, d) # generate call to newSeq before adding the elements per hand: var L = int(lengthOrd(t.sons[1].typ)) - + genNewSeqAux(p, d, intLiteral(L)) initLocExpr(p, t.sons[1], a) for i in countup(0, L - 1): @@ -1188,7 +1197,7 @@ proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) = initLoc(arr, locExpr, elemType(skipTypes(t.sons[1].typ, abstractInst)), a.s) arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i)) genAssignment(p, elem, arr, {afDestIsNil, needToCopy}) - + proc genNewFinalize(p: BProc, e: PNode) = var a, b, f: TLoc @@ -1236,14 +1245,15 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = var t = skipTypes(a.t, abstractInst) while t.kind in {tyVar, tyPtr, tyRef}: if t.kind != tyVar: nilCheck = r - r = rfmt(nil, "(*$1)", r) + if t.kind != tyVar or not p.module.compileToCpp: + r = rfmt(nil, "(*$1)", r) t = skipTypes(t.lastSon, typedescInst) if not p.module.compileToCpp: while t.kind == tyObject and t.sons[0] != nil: app(r, ~".Sup") t = skipTypes(t.sons[0], typedescInst) if isObjLackingTypeField(t): - globalError(x.info, errGenerated, + globalError(x.info, errGenerated, "no 'of' operator available for pure objects") if nilCheck != nil: r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r)) @@ -1260,7 +1270,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = var t = skipTypes(e.sons[1].typ, abstractVarRange) case t.kind of tyInt..tyInt64, tyUInt..tyUInt64: - putIntoDest(p, d, e.typ, + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)])) of tyFloat..tyFloat128: putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)])) @@ -1283,13 +1293,13 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = of tyOpenArray, tyVarargs: putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)])) of tyString, tySequence: - putIntoDest(p, b, e.typ, + putIntoDest(p, b, e.typ, ropef("$1->data, $1->$2", [rdLoc(a), lenField(p)])) of tyArray, tyArrayConstr: putIntoDest(p, b, e.typ, ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])) else: internalError(e.sons[0].info, "genRepr()") - putIntoDest(p, d, e.typ, + putIntoDest(p, d, e.typ, ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b), genTypeInfo(p.module, elemType(t))])) of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil, @@ -1375,7 +1385,7 @@ proc genSwap(p: BProc, e: PNode, d: var TLoc) = genAssignment(p, b, tmp, {}) proc rdSetElemLoc(a: TLoc, setType: PType): PRope = - # read a location of an set element; it may need a substraction operation + # read a location of an set element; it may need a subtraction operation # before the set operation result = rdCharLoc(a) assert(setType.kind == tySet) @@ -1418,7 +1428,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) = # do not emit the set, but generate a bunch of comparisons; and if we do # so, we skip the unnecessary range check: This is a semantical extension # that code now relies on. :-/ XXX - let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}: + let ea = if e.sons[2].kind in {nkChckRange, nkChckRange64}: e.sons[2].sons[0] else: e.sons[2] @@ -1503,7 +1513,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) = initLocExpr(p, e.sons[2], b) if d.k == locNone: getTemp(p, a.t, d) lineF(p, cpsStmts, - "for ($1 = 0; $1 < $2; $1++) $n" & + "for ($1 = 0; $1 < $2; $1++) $n" & " $3[$1] = $4[$1] $6 $5[$1];$n", [ rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b), toRope(lookupOpr[op])]) @@ -1534,7 +1544,7 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) = proc genCast(p: BProc, e: PNode, d: var TLoc) = const floatTypes = {tyFloat..tyFloat128} - let + let destt = skipTypes(e.typ, abstractRange) srct = skipTypes(e.sons[1].typ, abstractRange) if destt.kind in floatTypes or srct.kind in floatTypes: @@ -1641,7 +1651,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mRepr: genRepr(p, e, d) of mGetTypeInfo: genGetTypeInfo(p, e, d) of mSwap: genSwap(p, e, d) - of mUnaryLt: + of mUnaryLt: if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)") else: unaryExpr(p, e, d, "#subInt($1, 1)") of mPred: @@ -1815,10 +1825,10 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = proc isConstClosure(n: PNode): bool {.inline.} = result = n.sons[0].kind == nkSym and isRoutine(n.sons[0].sym) and n.sons[1].kind == nkNilLit - + proc genClosure(p: BProc, n: PNode, d: var TLoc) = assert n.kind == nkClosure - + if isConstClosure(n): inc(p.labels) var tmp = con("LOC", toRope(p.labels)) @@ -1863,7 +1873,8 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = var t = skipTypes(a.t, abstractInst) while t.kind in {tyVar, tyPtr, tyRef}: if t.kind != tyVar: nilCheck = r - r = ropef("(*$1)", [r]) + if t.kind != tyVar or not p.module.compileToCpp: + r = ropef("(*$1)", [r]) t = skipTypes(t.lastSon, abstractInst) if not p.module.compileToCpp: while t.kind == tyObject and t.sons[0] != nil: @@ -1904,7 +1915,7 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) = if isRef: # it can happen that we end up generating '&&x->Sup' here, so we pack # the '&x->Sup' into a temporary and then those address is taken - # (see bug #837). However sometimes using a temporary is not correct: + # (see bug #837). However sometimes using a temporary is not correct: # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test # this by ensuring the destination is also a pointer: if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}: @@ -1921,13 +1932,13 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) = discard getTypeDesc(p.module, t) # so that any fields are initialized var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId) var tmp = con("TMP", toRope(id)) - + if id == gBackendId: # expression not found in the cache: inc(gBackendId) appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", [getTypeDesc(p.module, t), tmp, genConstExpr(p, n)]) - + if d.k == locNone: fillLoc(d, locData, t, tmp, OnHeap) else: @@ -1968,7 +1979,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id if sfThread in sym.flags: accessThreadLocalVar(p, sym) - if emulatedThreadVars(): + if emulatedThreadVars(): putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r)) else: putLocIntoDest(p, d, sym.loc) @@ -1985,7 +1996,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = #echo "FAILED FOR PRCO ", p.prc.name.s #debug p.prc.typ.n #echo renderTree(p.prc.ast, {renderIds}) - internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) + internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id) putLocIntoDest(p, d, sym.loc) else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol") of nkNilLit: @@ -2073,8 +2084,8 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = genAsgn(p, n, fastAsgn=p.prc != nil) of nkDiscardStmt: if n.sons[0].kind != nkEmpty: - var a: TLoc genLineDir(p, n) + var a: TLoc initLocExpr(p, n.sons[0], a) of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt: @@ -2085,29 +2096,25 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = # we have to emit the type information for object types here to support # separate compilation: genTypeSection(p.module, n) - of nkCommentStmt, nkIteratorDef, nkIncludeStmt, - nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, - nkFromStmt, nkTemplateDef, nkMacroDef: + of nkCommentStmt, nkIteratorDef, nkIncludeStmt, + nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, + nkFromStmt, nkTemplateDef, nkMacroDef: discard of nkPragma: genPragma(p, n) of nkPragmaBlock: expr(p, n.lastSon, d) - of nkProcDef, nkMethodDef, nkConverterDef: - if (n.sons[genericParamsPos].kind == nkEmpty): + of nkProcDef, nkMethodDef, nkConverterDef: + if n.sons[genericParamsPos].kind == nkEmpty: var prc = n.sons[namePos].sym # due to a bug/limitation in the lambda lifting, unused inner procs # are not transformed correctly. We work around this issue (#411) here # by ensuring it's no inner proc (owner is a module): - # - # We also check whether the proc captures its environment here to - # prevent issue #1642. - if prc.skipGenericOwner.kind == skModule and - tfCapturesEnv in prc.typ.flags: + if prc.skipGenericOwner.kind == skModule: if (optDeadCodeElim notin gGlobalOptions and sfDeadCodeElim notin getModule(prc).flags) or ({sfExportc, sfCompilerProc} * prc.flags == {sfExportc}) or (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or - (prc.kind == skMethod): - # we have not only the header: + (prc.kind == skMethod): + # we have not only the header: if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags: genProc(p.module, prc) of nkParForStmt: genParForStmt(p, n) @@ -2130,7 +2137,7 @@ proc genConstSimpleList(p: BProc, n: PNode): PRope = proc genConstSeq(p: BProc, n: PNode, t: PType): PRope = var data = ropef("{{$1, $1}", n.len.toRope) - if n.len > 0: + if n.len > 0: # array part needs extra curlies: data.app(", {") for i in countup(0, n.len - 1): @@ -2138,14 +2145,14 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): PRope = data.app genConstExpr(p, n.sons[i]) data.app("}") data.app("}") - + inc(gBackendId) result = con("CNSTSEQ", gBackendId.toRope) - + appcg(p.module, cfsData, - "NIM_CONST struct {$n" & + "NIM_CONST struct {$n" & " #TGenericSeq Sup;$n" & - " $1 data[$2];$n" & + " $1 data[$2];$n" & "} $3 = $4;$n", [ getTypeDesc(p.module, t.sons[0]), n.len.toRope, result, data]) @@ -2159,7 +2166,7 @@ proc genConstExpr(p: BProc, n: PNode): PRope = var cs: TBitSet toBitSet(n, cs) result = genRawSetData(cs, int(getSize(n.typ))) - of nkBracket, nkPar, nkClosure: + of nkBracket, nkPar, nkClosure, nkObjConstr: var t = skipTypes(n.typ, abstractInst) if t.kind == tySequence: result = genConstSeq(p, n, t) diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 36da68d23..f4f837834 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -223,7 +223,7 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) = of "typeInfo": readIntSet(L, m.typeInfoMarker) of "labels": m.labels = decodeVInt(L.buf, L.bufpos) of "hasframe": m.frameDeclared = decodeVInt(L.buf, L.bufpos) != 0 - else: internalError("ccgmerge: unkown key: " & k) + else: internalError("ccgmerge: unknown key: " & k) when not defined(nimhygiene): {.pragma: inject.} diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index f0870a5df..a4938c9ac 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -48,7 +48,7 @@ proc genVarTuple(p: BProc, n: PNode) = return genLineDir(p, n) initLocExpr(p, n.sons[L-1], tup) - var t = tup.t + var t = tup.t.getUniqueType for i in countup(0, L-3): var v = n.sons[i].sym if sfCompileTime in v.flags: continue @@ -202,8 +202,20 @@ proc genSingleVar(p: BProc, a: PNode) = genVarPrototypeAux(generatedHeader, v) registerGcRoot(p, v) else: + let imm = isAssignedImmediately(a.sons[2]) + if imm and p.module.compileToCpp and p.splitDecls == 0 and + not containsHiddenPointer(v.typ): + # C++ really doesn't like things like 'Foo f; f = x' as that invokes a + # parameterless constructor followed by an assignment operator. So we + # generate better code here: + genLineDir(p, a) + let decl = localVarDecl(p, v) + var tmp: TLoc + initLocExprSingleUse(p, a.sons[2], tmp) + lineF(p, cpsStmts, "$# = $#;$n", decl, tmp.rdLoc) + return assignLocalVar(p, v) - initLocalVar(p, v, isAssignedImmediately(a.sons[2])) + initLocalVar(p, v, imm) if a.sons[2].kind != nkEmpty: genLineDir(targetProc, a) @@ -242,16 +254,7 @@ proc genConstStmt(p: BProc, t: PNode) = elif c.typ.kind in ConstantDataTypes and lfNoDecl notin c.loc.flags and c.ast.len != 0: if not emitLazily(c): requestConstImpl(p, c) - when false: - # generate the data: - fillLoc(c.loc, locData, c.typ, mangleName(c), OnUnknown) - if sfImportc in c.flags: - appf(p.module.s[cfsData], "extern NIM_CONST $1 $2;$n", - [getTypeDesc(p.module, c.typ), c.loc.r]) - else: - appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n", - [getTypeDesc(p.module, c.typ), c.loc.r, genConstExpr(p, c.ast)]) - + proc genIf(p: BProc, n: PNode, d: var TLoc) = # # { if (!expr1) goto L1; @@ -275,17 +278,22 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) = let it = n.sons[i] if it.len == 2: when newScopeForIf: startBlock(p) - initLocExpr(p, it.sons[0], a) + initLocExprSingleUse(p, it.sons[0], a) lelse = getLabel(p) inc(p.labels) - lineFF(p, cpsStmts, "if (!$1) goto $2;$n", - "br i1 $1, label %LOC$3, label %$2$nLOC$3: $n", - [rdLoc(a), lelse, toRope(p.labels)]) + lineF(p, cpsStmts, "if (!$1) goto $2;$n", + [rdLoc(a), lelse]) when not newScopeForIf: startBlock(p) - expr(p, it.sons[1], d) + if p.module.compileToCpp: + # avoid "jump to label crosses initialization" error: + app(p.s(cpsStmts), "{") + expr(p, it.sons[1], d) + app(p.s(cpsStmts), "}") + else: + expr(p, it.sons[1], d) endBlock(p) if sonsLen(n) > 1: - lineFF(p, cpsStmts, "goto $1;$n", "br label %$1$n", [lend]) + lineF(p, cpsStmts, "goto $1;$n", [lend]) fixLabel(p, lelse) elif it.len == 1: startBlock(p) @@ -344,7 +352,7 @@ proc genReturnStmt(p: BProc, t: PNode) = # consume it before we return. var safePoint = p.finallySafePoints[p.finallySafePoints.len-1] linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", safePoint) - lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", []) + lineF(p, cpsStmts, "goto BeforeRet;$n", []) proc genComputedGoto(p: BProc; n: PNode) = # first pass: Generate array of computed labels: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 90996d9cd..9a5a3ab34 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -27,17 +27,7 @@ proc isKeyword(w: PIdent): bool = proc mangleName(s: PSym): PRope = result = s.loc.r - if result == nil: - if gCmd == cmdCompileToLLVM: - case s.kind - of skProc, skMethod, skConverter, skConst, skIterators: - result = ~"@" - of skVar, skForVar, skResult, skLet: - if sfGlobal in s.flags: result = ~"@" - else: result = ~"%" - of skTemp, skParam, skType, skEnumField, skModule: - result = ~"%" - else: internalError(s.info, "mangleName") + if result == nil: when oKeepVariableNames: let keepOrigName = s.kind in skLocalVars - {skForVar} and {sfFromGeneric, sfGlobal, sfShadowed, sfGenSym} * s.flags == {} and @@ -103,13 +93,11 @@ proc typeName(typ: PType): PRope = else: ~"TY" proc getTypeName(typ: PType): PRope = - if (typ.sym != nil) and ({sfImportc, sfExportc} * typ.sym.flags != {}) and - (gCmd != cmdCompileToLLVM): + if typ.sym != nil and {sfImportc, sfExportc} * typ.sym.flags != {}: result = typ.sym.loc.r else: if typ.loc.r == nil: - typ.loc.r = if gCmd != cmdCompileToLLVM: con(typ.typeName, typ.id.toRope) - else: con([~"%", typ.typeName, typ.id.toRope]) + typ.loc.r = con(typ.typeName, typ.id.toRope) result = typ.loc.r if result == nil: internalError("getTypeName: " & $typ.kind) @@ -161,7 +149,13 @@ proc mapType(typ: PType): TCTypeKind = proc mapReturnType(typ: PType): TCTypeKind = if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr else: result = mapType(typ) - + +proc isImportedType(t: PType): bool = + result = t.sym != nil and sfImportc in t.sym.flags + +proc isImportedCppType(t: PType): bool = + result = t.sym != nil and sfInfixCall in t.sym.flags + proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope proc needsComplexAssignment(typ: PType): bool = result = containsGarbageCollectedRef(typ) @@ -170,19 +164,20 @@ proc isObjLackingTypeField(typ: PType): bool {.inline.} = result = (typ.kind == tyObject) and ((tfFinal in typ.flags) and (typ.sons[0] == nil) or isPureObject(typ)) -proc isInvalidReturnType(rettype: PType): bool = +proc isInvalidReturnType(rettype: PType): bool = # Arrays and sets cannot be returned by a C procedure, because C is # such a poor programming language. # We exclude records with refs too. This enhances efficiency and # is necessary for proper code generation of assignments. if rettype == nil: result = true - else: + else: case mapType(rettype) - of ctArray: + of ctArray: result = not (skipTypes(rettype, typedescInst).kind in {tyVar, tyRef, tyPtr}) of ctStruct: let t = skipTypes(rettype, typedescInst) + if rettype.isImportedCppType or t.isImportedCppType: return false result = needsComplexAssignment(t) or (t.kind == tyObject and not isObjLackingTypeField(t)) else: result = false @@ -193,9 +188,6 @@ const "N_SYSCALL", # this is probably not correct for all platforms, # but one can #define it to what one wants "N_INLINE", "N_NOINLINE", "N_FASTCALL", "N_CLOSURE", "N_NOCONV"] - CallingConvToStrLLVM: array[TCallingConvention, string] = ["fastcc $1", - "stdcall $1", "ccc $1", "safecall $1", "syscall $1", "$1 alwaysinline", - "$1 noinline", "fastcc $1", "ccc $1", "$1"] proc cacheGetType(tab: TIdTable, key: PType): PRope = # returns nil if we need to declare this type @@ -234,77 +226,8 @@ proc fillResult(param: PSym) = incl(param.loc.flags, lfIndirect) param.loc.s = OnUnknown -proc getParamTypeDesc(m: BModule, t: PType, check: var IntSet): PRope = - when false: - if t.Kind in {tyRef, tyPtr, tyVar}: - var b = skipTypes(t.lastson, typedescInst) - if b.kind == tySet and mapSetType(b) == ctArray: - return getTypeDescAux(m, b, check) - result = getTypeDescAux(m, t, check) - -proc paramStorageLoc(param: PSym): TStorageLoc = - if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}: - result = OnStack - else: - result = OnUnknown - -proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, - check: var IntSet, declareEnvironment=true) = - params = nil - if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): - rettype = ~"void" - else: - rettype = getTypeDescAux(m, t.sons[0], check) - for i in countup(1, sonsLen(t.n) - 1): - if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams") - var param = t.n.sons[i].sym - if isCompileTimeOnly(param.typ): continue - if params != nil: app(params, ~", ") - fillLoc(param.loc, locParam, param.typ, mangleName(param), - param.paramStorageLoc) - app(params, getParamTypeDesc(m, param.typ, check)) - if ccgIntroducedPtr(param): - app(params, ~"*") - incl(param.loc.flags, lfIndirect) - param.loc.s = OnUnknown - app(params, ~" ") - app(params, param.loc.r) - # declare the len field for open arrays: - var arr = param.typ - if arr.kind == tyVar: arr = arr.sons[0] - var j = 0 - while arr.kind in {tyOpenArray, tyVarargs}: - # this fixes the 'sort' bug: - if param.typ.kind == tyVar: param.loc.s = OnUnknown - # need to pass hidden parameter: - appff(params, ", NI $1Len$2", ", @NI $1Len$2", [param.loc.r, j.toRope]) - inc(j) - arr = arr.sons[0] - if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): - var arr = t.sons[0] - if params != nil: app(params, ", ") - app(params, getTypeDescAux(m, arr, check)) - if (mapReturnType(t.sons[0]) != ctArray) or (gCmd == cmdCompileToLLVM): - app(params, "*") - appff(params, " Result", " @Result", []) - if t.callConv == ccClosure and declareEnvironment: - if params != nil: app(params, ", ") - app(params, "void* ClEnv") - if tfVarargs in t.flags: - if params != nil: app(params, ", ") - app(params, "...") - if params == nil and gCmd != cmdCompileToLLVM: app(params, "void)") - else: app(params, ")") - params = con("(", params) - -proc isImportedType(t: PType): bool = - result = t.sym != nil and sfImportc in t.sym.flags - -proc isImportedCppType(t: PType): bool = - result = t.sym != nil and sfInfixCall in t.sym.flags - proc typeNameOrLiteral(t: PType, literal: string): PRope = - if (t.sym != nil) and (sfImportc in t.sym.flags) and (t.sym.magic == mNone): + if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone: result = getTypeName(t) else: result = toRope(literal) @@ -341,7 +264,10 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): PRope = result = typeNameOrLiteral(typ, NumericalTypeToStr[typ.kind]) of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0]) else: result = nil - + +proc pushType(m: BModule, typ: PType) = + add(m.typeStack, typ) + proc getTypePre(m: BModule, typ: PType): PRope = if typ == nil: result = toRope("void") else: @@ -368,6 +294,81 @@ proc getTypeForward(m: BModule, typ: PType): PRope = [structOrUnion(typ), result]) idTablePut(m.forwTypeCache, typ, result) else: internalError("getTypeForward(" & $typ.kind & ')') + +proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): PRope = + ## like getTypeDescAux but creates only a *weak* dependency. In other words + ## we know we only need a pointer to it so we only generate a struct forward + ## declaration: + var etB = t.skipTypes(abstractInst) + case etB.kind + of tyObject, tyTuple: + if isImportedCppType(etB) and t.kind == tyGenericInst: + result = getTypeDescAux(m, t, check) + else: + let x = getUniqueType(etB) + result = getTypeForward(m, x) + pushType(m, x) + else: + result = getTypeDescAux(m, t, check) + +proc paramStorageLoc(param: PSym): TStorageLoc = + if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin {tyArray, tyOpenArray}: + result = OnStack + else: + result = OnUnknown + +proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, + check: var IntSet, declareEnvironment=true) = + params = nil + if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): + rettype = ~"void" + else: + rettype = getTypeDescAux(m, t.sons[0], check) + for i in countup(1, sonsLen(t.n) - 1): + if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams") + var param = t.n.sons[i].sym + if isCompileTimeOnly(param.typ): continue + if params != nil: app(params, ~", ") + fillLoc(param.loc, locParam, param.typ, mangleName(param), + param.paramStorageLoc) + if ccgIntroducedPtr(param): + app(params, getTypeDescWeak(m, param.typ, check)) + app(params, ~"*") + incl(param.loc.flags, lfIndirect) + param.loc.s = OnUnknown + else: + app(params, getTypeDescAux(m, param.typ, check)) + app(params, ~" ") + app(params, param.loc.r) + # declare the len field for open arrays: + var arr = param.typ + if arr.kind == tyVar: arr = arr.sons[0] + var j = 0 + while arr.kind in {tyOpenArray, tyVarargs}: + # this fixes the 'sort' bug: + if param.typ.kind == tyVar: param.loc.s = OnUnknown + # need to pass hidden parameter: + appf(params, ", NI $1Len$2", [param.loc.r, j.toRope]) + inc(j) + arr = arr.sons[0] + if (t.sons[0] != nil) and isInvalidReturnType(t.sons[0]): + var arr = t.sons[0] + if params != nil: app(params, ", ") + if (mapReturnType(t.sons[0]) != ctArray): + app(params, getTypeDescWeak(m, arr, check)) + app(params, "*") + else: + app(params, getTypeDescAux(m, arr, check)) + appf(params, " Result", []) + if t.callConv == ccClosure and declareEnvironment: + if params != nil: app(params, ", ") + app(params, "void* ClEnv") + if tfVarargs in t.flags: + if params != nil: app(params, ", ") + app(params, "...") + if params == nil: app(params, "void)") + else: app(params, ")") + params = con("(", params) proc mangleRecFieldName(field: PSym, rectype: PType): PRope = if (rectype.sym != nil) and @@ -421,14 +422,18 @@ proc genRecordFieldsAux(m: BModule, n: PNode, if accessExpr != nil: ae = ropef("$1.$2", [accessExpr, sname]) else: ae = sname fillLoc(field.loc, locField, field.typ, ae, OnUnknown) - let fieldType = field.loc.t.skipTypes(abstractInst) - if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: - appf(result, "$1 $2[SEQ_DECL_SIZE];$n", - [getTypeDescAux(m, fieldType.elemType, check), sname]) - else: - # don't use fieldType here because we need the - # tyGenericInst for C++ template support - appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) + # for importcpp'ed objects, we only need to set field.loc, but don't + # have to recurse via 'getTypeDescAux'. And not doing so prevents problems + # with heavily templatized C++ code: + if not isImportedCppType(rectype): + let fieldType = field.loc.t.skipTypes(abstractInst) + if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: + appf(result, "$1 $2[SEQ_DECL_SIZE];$n", + [getTypeDescAux(m, fieldType.elemType, check), sname]) + else: + # don't use fieldType here because we need the + # tyGenericInst for C++ template support + appf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname]) else: internalError(n.info, "genRecordFieldsAux()") proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = @@ -483,9 +488,6 @@ proc getTupleDesc(m: BModule, typ: PType, name: PRope, else: app(result, desc) app(result, "};" & tnl) -proc pushType(m: BModule, typ: PType) = - add(m.typeStack, typ) - proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = # returns only the type's name var t = getUniqueType(typ) @@ -493,13 +495,16 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = if t.sym != nil: useHeader(m, t.sym) result = getTypePre(m, t) if result != nil: return - if containsOrIncl(check, t.id): + if containsOrIncl(check, t.id): + if isImportedCppType(typ) or isImportedCppType(t): return internalError("cannot generate C type for: " & typeToString(typ)) # XXX: this BUG is hard to fix -> we need to introduce helper structs, # but determining when this needs to be done is hard. We should split # C type generation into an analysis and a code generation phase somehow. case t.kind - of tyRef, tyPtr, tyVar: + of tyRef, tyPtr, tyVar: + var star = if t.kind == tyVar and tfVarIsPtr notin typ.flags and + compileToCpp(m): "&" else: "*" var et = t.lastSon var etB = et.skipTypes(abstractInst) if etB.kind in {tyArrayConstr, tyArray, tyOpenArray, tyVarargs}: @@ -507,27 +512,28 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = # ``var set[char]`` in `getParamTypeDesc` et = elemType(etB) etB = et.skipTypes(abstractInst) + star[0] = '*' case etB.kind of tyObject, tyTuple: if isImportedCppType(etB) and et.kind == tyGenericInst: - result = con(getTypeDescAux(m, et, check), "*") + result = con(getTypeDescAux(m, et, check), star) else: # no restriction! We have a forward declaration for structs let x = getUniqueType(etB) let name = getTypeForward(m, x) - result = con(name, "*") + result = con(name, star) idTablePut(m.typeCache, t, result) pushType(m, x) of tySequence: # no restriction! We have a forward declaration for structs let x = getUniqueType(etB) let name = getTypeForward(m, x) - result = con(name, "**") + result = con(name, "*" & star) idTablePut(m.typeCache, t, result) pushType(m, x) else: # else we have a strong dependency :-( - result = con(getTypeDescAux(m, et, check), "*") + result = con(getTypeDescAux(m, et, check), star) idTablePut(m.typeCache, t, result) of tyOpenArray, tyVarargs: result = con(getTypeDescAux(m, t.sons[0], check), "*") @@ -670,7 +676,7 @@ proc genProcHeader(m: BModule, prc: PSym): PRope = rettype, params: PRope genCLineDir(result, prc.info) # using static is needed for inline procs - if gCmd != cmdCompileToLLVM and lfExportLib in prc.loc.flags: + if lfExportLib in prc.loc.flags: if m.isHeaderFile: result.app "N_LIB_IMPORT " else: @@ -696,16 +702,7 @@ proc getNimNode(m: BModule): PRope = result = ropef("$1[$2]", [m.typeNodesName, toRope(m.typeNodes)]) inc(m.typeNodes) -when false: - proc getNimType(m: BModule): PRope = - result = ropef("$1[$2]", [m.nimTypesName, toRope(m.nimTypes)]) - inc(m.nimTypes) - - proc allocMemTI(m: BModule, typ: PType, name: PRope) = - var tmp = getNimType(m) - appf(m.s[cfsTypeInit2], "$2 = &$1;$n", [tmp, name]) - -proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) = +proc genTypeInfoAuxBase(m: BModule; typ, origType: PType; name, base: PRope) = var nimtypeKind: int #allocMemTI(m, typ, name) if isObjLackingTypeField(typ): @@ -715,6 +712,7 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) = var size: PRope if tfIncompleteStruct in typ.flags: size = toRope"void*" + elif m.compileToCpp: size = getTypeDesc(m, origType) else: size = getTypeDesc(m, typ) appf(m.s[cfsTypeInit3], "$1.size = sizeof($2);$n" & "$1.kind = $3;$n" & "$1.base = $4;$n", @@ -730,13 +728,13 @@ proc genTypeInfoAuxBase(m: BModule, typ: PType, name, base: PRope) = appf(m.s[cfsVars], "TNimType $1; /* $2 */$n", [name, toRope(typeToString(typ))]) -proc genTypeInfoAux(m: BModule, typ: PType, name: PRope) = +proc genTypeInfoAux(m: BModule, typ, origType: PType, name: PRope) = var base: PRope if (sonsLen(typ) > 0) and (typ.sons[0] != nil): base = genTypeInfo(m, typ.sons[0]) else: base = toRope("0") - genTypeInfoAuxBase(m, typ, name, base) + genTypeInfoAuxBase(m, typ, origType, name, base) proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): PRope = # bugfix: we need to search the type that contains the discriminator: @@ -814,11 +812,12 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: PRope) = field.loc.r, genTypeInfo(m, field.typ), makeCString(field.name.s)]) else: internalError(n.info, "genObjectFields") -proc genObjectInfo(m: BModule, typ: PType, name: PRope) = - if typ.kind == tyObject: genTypeInfoAux(m, typ, name) - else: genTypeInfoAuxBase(m, typ, name, toRope("0")) +proc genObjectInfo(m: BModule, typ, origType: PType, name: PRope) = + if typ.kind == tyObject: genTypeInfoAux(m, typ, origType, name) + else: genTypeInfoAuxBase(m, typ, origType, name, toRope("0")) var tmp = getNimNode(m) - genObjectFields(m, typ, typ.n, tmp) + if not isImportedCppType(typ): + genObjectFields(m, typ, typ.n, tmp) appf(m.s[cfsTypeInit3], "$1.node = &$2;$n", [name, tmp]) var t = typ.sons[0] while t != nil: @@ -827,7 +826,7 @@ proc genObjectInfo(m: BModule, typ: PType, name: PRope) = t = t.sons[0] proc genTupleInfo(m: BModule, typ: PType, name: PRope) = - genTypeInfoAuxBase(m, typ, name, toRope("0")) + genTypeInfoAuxBase(m, typ, typ, name, toRope("0")) var expr = getNimNode(m) var length = sonsLen(typ) if length > 0: @@ -854,7 +853,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) = # optimizations here: The ``typ`` field is never set, as it is redundant # anyway. We generate a cstring array and a loop over it. Exceptional # positions will be reset after the loop. - genTypeInfoAux(m, typ, name) + genTypeInfoAux(m, typ, typ, name) var nodePtrs = getTempName() var length = sonsLen(typ.n) appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", @@ -894,13 +893,13 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) = proc genSetInfo(m: BModule, typ: PType, name: PRope) = assert(typ.sons[0] != nil) - genTypeInfoAux(m, typ, name) + genTypeInfoAux(m, typ, typ, name) var tmp = getNimNode(m) appf(m.s[cfsTypeInit3], "$1.len = $2; $1.kind = 0;$n" & "$3.node = &$1;$n", [tmp, toRope(firstOrd(typ)), name]) proc genArrayInfo(m: BModule, typ: PType, name: PRope) = - genTypeInfoAuxBase(m, typ, name, genTypeInfo(m, typ.sons[1])) + genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1])) proc fakeClosureType(owner: PSym): PType = # we generate the same RTTI as for a tuple[pointer, ref tuple[]] @@ -946,23 +945,23 @@ proc genTypeInfo(m: BModule, t: PType): PRope = case t.kind of tyEmpty: result = toRope"0" of tyPointer, tyBool, tyChar, tyCString, tyString, tyInt..tyUInt64, tyVar: - genTypeInfoAuxBase(m, t, result, toRope"0") + genTypeInfoAuxBase(m, t, t, result, toRope"0") of tyProc: if t.callConv != ccClosure: - genTypeInfoAuxBase(m, t, result, toRope"0") + genTypeInfoAuxBase(m, t, t, result, toRope"0") else: genTupleInfo(m, fakeClosureType(t.owner), result) of tySequence, tyRef: - genTypeInfoAux(m, t, result) + genTypeInfoAux(m, t, t, result) if gSelectedGC >= gcMarkAndSweep: let markerProc = genTraverseProc(m, t, tiNew) appf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc]) - of tyPtr, tyRange: genTypeInfoAux(m, t, result) + of tyPtr, tyRange: genTypeInfoAux(m, t, t, result) of tyArrayConstr, tyArray: genArrayInfo(m, t, result) of tySet: genSetInfo(m, t, result) of tyEnum: genEnumInfo(m, t, result) - of tyObject: genObjectInfo(m, t, result) - of tyTuple: + of tyObject: genObjectInfo(m, t, origType, result) + of tyTuple: # if t.n != nil: genObjectInfo(m, t, result) # else: # BUGFIX: use consistently RTTI without proper field names; otherwise diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 1e1fcd6fb..59b9611fc 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -69,7 +69,20 @@ when false: proc echoStats*() = for i in countup(low(TTypeKind), high(TTypeKind)): echo i, " ", gTypeTable[i].counter - + +proc slowSearch(key: PType; k: TTypeKind): PType = + # tuples are quite horrible as C does not support them directly and + # tuple[string, string] is a (strange) subtype of + # tuple[nameA, nameB: string]. This bites us here, so we + # use 'sameBackendType' instead of 'sameType'. + if idTableHasObjectAsKey(gTypeTable[k], key): return key + for h in countup(0, high(gTypeTable[k].data)): + var t = PType(gTypeTable[k].data[h].key) + if t != nil and sameBackendType(t, key): + return t + idTablePut(gTypeTable[k], key, key) + result = key + proc getUniqueType*(key: PType): PType = # this is a hotspot in the compiler! if key == nil: return @@ -86,7 +99,7 @@ proc getUniqueType*(key: PType): PType = gCanonicalTypes[k] = key result = key of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor: - internalError("GetUniqueType") + internalError("getUniqueType") of tyDistinct: if key.deepCopy != nil: result = key else: result = getUniqueType(lastSon(key)) @@ -96,23 +109,20 @@ proc getUniqueType*(key: PType): PType = #if obj.sym != nil and obj.sym.name.s == "TOption": # echo "for ", typeToString(key), " I returned " # debug result - of tyArrayConstr, tyGenericInvokation, tyGenericBody, + of tyPtr, tyRef, tyVar: + let elemType = lastSon(key) + if elemType.kind in {tyBool, tyChar, tyInt..tyUInt64}: + # no canonicalization for integral types, so that e.g. ``ptr pid_t`` is + # produced instead of ``ptr NI``. + result = key + else: + result = slowSearch(key, k) + of tyArrayConstr, tyGenericInvocation, tyGenericBody, tyOpenArray, tyArray, tySet, tyRange, tyTuple, - tyPtr, tyRef, tySequence, tyForward, tyVarargs, tyProxy, tyVar: - # tuples are quite horrible as C does not support them directly and - # tuple[string, string] is a (strange) subtype of - # tuple[nameA, nameB: string]. This bites us here, so we - # use 'sameBackendType' instead of 'sameType'. - + tySequence, tyForward, tyVarargs, tyProxy: # we have to do a slow linear search because types may need # to be compared by their structure: - if idTableHasObjectAsKey(gTypeTable[k], key): return key - for h in countup(0, high(gTypeTable[k].data)): - var t = PType(gTypeTable[k].data[h].key) - if t != nil and sameBackendType(t, key): - return t - idTablePut(gTypeTable[k], key, key) - result = key + result = slowSearch(key, k) of tyObject: if tfFromGeneric notin key.flags: # fast case; lookup per id suffices: @@ -123,9 +133,9 @@ proc getUniqueType*(key: PType): PType = else: # ugly slow case: need to compare by structure if idTableHasObjectAsKey(gTypeTable[k], key): return key - for h in countup(0, high(gTypeTable[k].data)): + for h in countup(0, high(gTypeTable[k].data)): var t = PType(gTypeTable[k].data[h].key) - if t != nil and sameType(t, key): + if t != nil and sameBackendType(t, key): return t idTablePut(gTypeTable[k], key, key) result = key @@ -139,14 +149,8 @@ proc getUniqueType*(key: PType): PType = result = key else: # ugh, we need the canon here: - if idTableHasObjectAsKey(gTypeTable[k], key): return key - for h in countup(0, high(gTypeTable[k].data)): - var t = PType(gTypeTable[k].data[h].key) - if t != nil and sameBackendType(t, key): - return t - idTablePut(gTypeTable[k], key, key) - result = key - + result = slowSearch(key, k) + proc tableGetType*(tab: TIdTable, key: PType): RootRef = # returns nil if we need to declare this type result = idTableGet(tab, key) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 480c131ae..cc376d87a 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -25,15 +25,6 @@ when options.hasTinyCBackend: var generatedHeader: BModule -proc ropeff(cformat, llvmformat: string, args: varargs[PRope]): PRope = - if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args) - else: result = ropef(cformat, args) - -proc appff(dest: var PRope, cformat, llvmformat: string, - args: varargs[PRope]) = - if gCmd == cmdCompileToLLVM: appf(dest, llvmformat, args) - else: appf(dest, cformat, args) - proc addForwardedProc(m: BModule, prc: PSym) = m.forwardedProcs.add(prc) inc(gForwardedProcsCounter) @@ -137,79 +128,8 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope = if i - 1 >= start: app(result, substr(frmt, start, i - 1)) -const compileTimeRopeFmt = false - -when compileTimeRopeFmt: - import macros - - type TFmtFragmentKind = enum - ffSym, - ffLit, - ffParam - - type TFragment = object - case kind: TFmtFragmentKind - of ffSym, ffLit: - value: string - of ffParam: - intValue: int - - iterator fmtStringFragments(s: string): tuple[kind: TFmtFragmentKind, - value: string, - intValue: int] = - # This is a bit less featured version of the ropecg's algorithm - # (be careful when replacing ropecg calls) - var - i = 0 - length = s.len - - while i < length: - var start = i - case s[i] - of '$': - let n = s[i+1] - case n - of '$': - inc i, 2 - of '0'..'9': - # XXX: use the new case object construction syntax when it's ready - yield (kind: ffParam, value: "", intValue: n.ord - ord('1')) - inc i, 2 - start = i - else: - inc i - of '#': - inc i - var j = i - while s[i] in IdentChars: inc i - yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0) - start = i - else: discard - - while i < length: - if s[i] != '$' and s[i] != '#': inc i - else: break - - if i - 1 >= start: - yield (kind: ffLit, value: substr(s, start, i-1), intValue: 0) - - macro rfmt(m: BModule, fmt: static[string], args: varargs[PRope]): expr = - ## Experimental optimized rope-formatting operator - ## The run-time code it produces will be very fast, but will it speed up - ## the compilation of nimrod itself or will the macro execution time - ## offset the gains? - result = newCall(bindSym"ropeConcat") - for frag in fmtStringFragments(fmt): - case frag.kind - of ffSym: - result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value))) - of ffLit: - result.add(newCall(bindSym"~", newStrLitNode(frag.value))) - of ffParam: - result.add(args[frag.intValue]) -else: - template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr = - ropecg(m, fmt, args) +template rfmt(m: BModule, fmt: string, args: varargs[PRope]): expr = + ropecg(m, fmt, args) proc appcg(m: BModule, c: var PRope, frmt: TFormatStr, args: varargs[PRope]) = @@ -242,24 +162,14 @@ proc lineCg(p: BProc, s: TCProcSection, frmt: TFormatStr, args: varargs[PRope]) = app(p.s(s), indentLine(p, ropecg(p.module, frmt, args))) -when compileTimeRopeFmt: - template linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr, - args: varargs[PRope]) = - line(p, s, rfmt(p.module, frmt, args)) -else: - proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr, - args: varargs[PRope]) = - app(p.s(s), indentLine(p, ropecg(p.module, frmt, args))) +proc linefmt(p: BProc, s: TCProcSection, frmt: TFormatStr, + args: varargs[PRope]) = + app(p.s(s), indentLine(p, ropecg(p.module, frmt, args))) proc appLineCg(p: BProc, r: var PRope, frmt: TFormatStr, args: varargs[PRope]) = app(r, indentLine(p, ropecg(p.module, frmt, args))) -proc lineFF(p: BProc, s: TCProcSection, cformat, llvmformat: string, - args: varargs[PRope]) = - if gCmd == cmdCompileToLLVM: lineF(p, s, llvmformat, args) - else: lineF(p, s, cformat, args) - proc safeLineNm(info: TLineInfo): int = result = toLinenumber(info) if result < 0: result = 0 # negative numbers are not allowed in #line @@ -267,8 +177,8 @@ proc safeLineNm(info: TLineInfo): int = proc genCLineDir(r: var PRope, filename: string, line: int) = assert line >= 0 if optLineDir in gOptions: - appff(r, "$N#line $2 $1$N", "; line $2 \"$1\"$n", - [toRope(makeSingleLineCString(filename)), toRope(line)]) + appf(r, "$N#line $2 $1$N", + [toRope(makeSingleLineCString(filename)), toRope(line)]) proc genCLineDir(r: var PRope, info: TLineInfo) = genCLineDir(r, info.toFullPath, info.safeLineNm) @@ -402,11 +312,8 @@ proc initLocalVar(p: BProc, v: PSym, immediateAsgn: bool) = proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = inc(p.labels) - if gCmd == cmdCompileToLLVM: - result.r = con("%LOC", toRope(p.labels)) - else: - result.r = con("LOC", toRope(p.labels)) - linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) + result.r = con("LOC", toRope(p.labels)) + linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) result.k = locTemp #result.a = - 1 result.t = getUniqueType(t) @@ -446,29 +353,6 @@ proc deinitGCFrame(p: BProc): PRope = if p.gcFrameId > 0: result = ropecg(p.module, "if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n") - -proc cstringLit(p: BProc, r: var PRope, s: string): PRope = - if gCmd == cmdCompileToLLVM: - inc(p.module.labels) - inc(p.labels) - result = ropef("%LOC$1", [toRope(p.labels)]) - appf(p.module.s[cfsData], "@C$1 = private constant [$2 x i8] $3$n", - [toRope(p.module.labels), toRope(len(s)), makeLLVMString(s)]) - appf(r, "$1 = getelementptr [$2 x i8]* @C$3, %NI 0, %NI 0$n", - [result, toRope(len(s)), toRope(p.module.labels)]) - else: - result = makeCString(s) - -proc cstringLit(m: BModule, r: var PRope, s: string): PRope = - if gCmd == cmdCompileToLLVM: - inc(m.labels, 2) - result = ropef("%MOC$1", [toRope(m.labels - 1)]) - appf(m.s[cfsData], "@MOC$1 = private constant [$2 x i8] $3$n", - [toRope(m.labels), toRope(len(s)), makeLLVMString(s)]) - appf(r, "$1 = getelementptr [$2 x i8]* @MOC$3, %NI 0, %NI 0$n", - [result, toRope(len(s)), toRope(m.labels)]) - else: - result = makeCString(s) proc allocParam(p: BProc, s: PSym) = assert(s.kind == skParam) @@ -494,22 +378,26 @@ proc localDebugInfo(p: BProc, s: PSym) = inc(p.maxFrameLen) inc p.blocks[p.blocks.len-1].frameLen -proc assignLocalVar(p: BProc, s: PSym) = - #assert(s.loc.k == locNone) // not yet assigned - # this need not be fullfilled for inline procs; they are regenerated - # for each module that uses them! +proc localVarDecl(p: BProc; s: PSym): PRope = if s.loc.k == locNone: fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) - var decl = getTypeDesc(p.module, s.loc.t) + result = getTypeDesc(p.module, s.loc.t) if s.constraint.isNil: - if sfRegister in s.flags: app(decl, " register") + if sfRegister in s.flags: app(result, " register") #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # app(decl, " GC_GUARD") - if sfVolatile in s.flags: app(decl, " volatile") - appf(decl, " $1;$n", [s.loc.r]) + if sfVolatile in s.flags: app(result, " volatile") + app(result, " ") + app(result, s.loc.r) else: - decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r) + result = ropef(s.cgDeclFrmt, result, s.loc.r) + +proc assignLocalVar(p: BProc, s: PSym) = + #assert(s.loc.k == locNone) # not yet assigned + # this need not be fulfilled for inline procs; they are regenerated + # for each module that uses them! + let decl = localVarDecl(p, s).con(";" & tnl) line(p, cpsLocals, decl) localDebugInfo(p, s) @@ -552,13 +440,11 @@ proc assignGlobalVar(p: BProc, s: PSym) = {optStackTrace, optEndb}: appcg(p.module, p.module.s[cfsDebugInit], "#dbgRegisterGlobal($1, &$2, $3);$n", - [cstringLit(p, p.module.s[cfsDebugInit], - normalize(s.owner.name.s & '.' & s.name.s)), + [makeCString(normalize(s.owner.name.s & '.' & s.name.s)), s.loc.r, genTypeInfo(p.module, s.typ)]) proc assignParam(p: BProc, s: PSym) = assert(s.loc.r != nil) - if sfAddrTaken in s.flags and gCmd == cmdCompileToLLVM: allocParam(p, s) localDebugInfo(p, s) proc fillProcLoc(sym: PSym) = @@ -586,6 +472,11 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = initLoc(result, locNone, e.typ, OnUnknown) expr(p, e, result) +proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) = + initLoc(result, locNone, e.typ, OnUnknown) + result.flags.incl lfSingleUse + expr(p, e, result) + proc lenField(p: BProc): PRope = result = toRope(if p.module.compileToCpp: "len" else: "Sup.len") @@ -647,7 +538,6 @@ proc symInDynamicLib(m: BModule, sym: PSym) = let isCall = isGetProcAddr(lib) var extname = sym.loc.r if not isCall: loadDynamicLib(m, lib) - if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect) var tmp = mangleDynLibProc(sym) sym.loc.r = tmp # from now on we only need the internal name sym.typ.sym = nil # generate a new name @@ -663,7 +553,7 @@ proc symInDynamicLib(m: BModule, sym: PSym) = params.app(", ") let load = ropef("\t$1 = ($2) ($3$4));$n", [tmp, getTypeDesc(m, sym.typ), - params, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))]) + params, makeCString(ropeToStr(extname))]) var last = lastSon(n) if last.kind == nkHiddenStdConv: last = last.sons[1] internalAssert(last.kind == nkStrLit) @@ -678,10 +568,8 @@ proc symInDynamicLib(m: BModule, sym: PSym) = appcg(m, m.s[cfsDynLibInit], "\t$1 = ($2) #nimGetProcAddr($3, $4);$n", [tmp, getTypeDesc(m, sym.typ), - lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))]) - appff(m.s[cfsVars], "$2 $1;$n", - "$1 = linkonce global $2 zeroinitializer$n", - [sym.loc.r, getTypeDesc(m, sym.loc.t)]) + lib.name, makeCString(ropeToStr(extname))]) + appf(m.s[cfsVars], "$2 $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)]) proc varInDynamicLib(m: BModule, sym: PSym) = var lib = sym.annex @@ -694,7 +582,7 @@ proc varInDynamicLib(m: BModule, sym: PSym) = appcg(m, m.s[cfsDynLibInit], "$1 = ($2*) #nimGetProcAddr($3, $4);$n", [tmp, getTypeDesc(m, sym.typ), - lib.name, cstringLit(m, m.s[cfsDynLibInit], ropeToStr(extname))]) + lib.name, makeCString(ropeToStr(extname))]) appf(m.s[cfsVars], "$2* $1;$n", [sym.loc.r, getTypeDesc(m, sym.loc.t)]) @@ -717,13 +605,13 @@ proc cgsym(m: BModule, name: string): PRope = rawMessage(errSystemNeeds, name) result = sym.loc.r -proc generateHeaders(m: BModule) = +proc generateHeaders(m: BModule) = app(m.s[cfsHeaders], tnl & "#include \"nimbase.h\"" & tnl) var it = PStrEntry(m.headerFiles.head) - while it != nil: + while it != nil: if it.data[0] notin {'\"', '<'}: appf(m.s[cfsHeaders], "$N#include \"$1\"$N", [toRope(it.data)]) - else: + else: appf(m.s[cfsHeaders], "$N#include $1$N", [toRope(it.data)]) it = PStrEntry(it.next) @@ -796,16 +684,17 @@ proc genProcAux(m: BModule, prc: PSym) = app(generatedProc, initGCFrame(p)) if optStackTrace in prc.options: app(generatedProc, p.s(cpsLocals)) - var procname = cstringLit(p, generatedProc, prc.name.s) + var procname = makeCString(prc.name.s) app(generatedProc, initFrame(p, procname, prc.info.quotedFilename)) else: app(generatedProc, p.s(cpsLocals)) - if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM): + if optProfiler in prc.options: # invoke at proc entry for recursion: appcg(p, cpsInit, "\t#nimProfile();$n", []) + if p.beforeRetNeeded: app(generatedProc, "{") app(generatedProc, p.s(cpsInit)) app(generatedProc, p.s(cpsStmts)) - if p.beforeRetNeeded: app(generatedProc, ~"\tBeforeRet: ;$n") + if p.beforeRetNeeded: app(generatedProc, ~"\t}BeforeRet: ;$n") app(generatedProc, deinitGCFrame(p)) if optStackTrace in prc.options: app(generatedProc, deinitFrame(p)) app(generatedProc, returnStmt) @@ -825,7 +714,6 @@ proc genProcPrototype(m: BModule, sym: PSym) = not containsOrIncl(m.declaredThings, sym.id): app(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n", getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym))) - if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect) elif not containsOrIncl(m.declaredProtos, sym.id): var header = genProcHeader(m, sym) if sym.typ.callConv != ccInline and crossesCppBoundary(m, sym): @@ -923,21 +811,17 @@ proc addIntTypes(result: var PRope) {.inline.} = proc getCopyright(cfile: string): PRope = if optCompileOnly in gGlobalOptions: - result = ropeff("/* Generated by Nim Compiler v$1 */$N" & + result = ropef("/* Generated by Nim Compiler v$1 */$N" & "/* (c) 2015 Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N", - "; Generated by Nim Compiler v$1$N" & - "; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)]) + [toRope(VersionAsString)]) else: - result = ropeff("/* Generated by Nim Compiler v$1 */$N" & + result = ropef("/* Generated by Nim Compiler v$1 */$N" & "/* (c) 2015 Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N" & "/* Compiled for: $2, $3, $4 */$N" & "/* Command for C compiler:$n $5 */$N", - "; Generated by Nim Compiler v$1$N" & - "; (c) 2015 Andreas Rumpf$N" & - "; Compiled for: $2, $3, $4$N" & - "; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString), + [toRope(VersionAsString), toRope(platform.OS[targetOS].name), toRope(platform.CPU[targetCPU].name), toRope(extccomp.CC[extccomp.cCompiler].name), @@ -1088,13 +972,11 @@ proc registerModuleToMain(m: PSym) = var init = m.getInitName datInit = m.getDatInitName - appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", - "declare void $1() noinline$N", [init]) - appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", - "declare void $1() noinline$N", [datInit]) + appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init]) + appf(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit]) if sfSystemModule notin m.flags: - appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit]) - let initCall = ropeff("\t$1();$N", "call void ()* $1$n", [init]) + appf(mainDatInit, "\t$1();$N", [datInit]) + let initCall = ropef("\t$1();$N", [init]) if sfMainModule in m.flags: app(mainModInit, initCall) else: @@ -1102,8 +984,7 @@ proc registerModuleToMain(m: PSym) = proc genInitCode(m: BModule) = var initname = getInitName(m.module) - var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", - "define void $1() noinline {$n", [initname]) + var prc = ropef("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", [initname]) if m.typeNodes > 0: appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", [m.typeNodesName, toRope(m.typeNodes)]) @@ -1124,7 +1005,7 @@ proc genInitCode(m: BModule) = # declare it nevertheless: m.frameDeclared = true if not m.preventStackTrace: - var procname = cstringLit(m.initProc, prc, m.module.name.s) + var procname = makeCString(m.module.name.s) app(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename)) else: app(prc, ~"\tTFrame F; F.len = 0;$N") @@ -1145,8 +1026,8 @@ proc genInitCode(m: BModule) = app(prc, deinitGCFrame(m.initProc)) appf(prc, "}$N$N") - prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", - "define void $1() noinline {$n", [getDatInitName(m.module)]) + prc.appf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", + [getDatInitName(m.module)]) for i in cfsTypeInit1..cfsDynLibInit: app(prc, genSectionStart(i)) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 508f98074..bb98454a7 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -82,6 +82,9 @@ type maxFrameLen*: int # max length of frame descriptor module*: BModule # used to prevent excessive parameter passing withinLoop*: int # > 0 if we are within a loop + splitDecls*: int # > 0 if we are in some context for C++ that + # requires 'T x = T()' to become 'T x; x = T()' + # (yes, C++ is weird like that) gcFrameId*: Natural # for the GC stack marking gcFrameType*: PRope # the struct {} we put the GC markers into diff --git a/compiler/commands.nim b/compiler/commands.nim index 78fa9249c..a2d02e469 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -52,7 +52,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) const HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & - "Copyright (c) 2006-2014 by Andreas Rumpf\n" + "Copyright (c) 2006-2015 by Andreas Rumpf\n" const Usage = slurp"doc/basicopt.txt".replace("//", "") @@ -141,7 +141,7 @@ proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch)) proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, - info: TLineInfo) = + info: TLineInfo; orig: string) = var id = "" # arg = "X]:on|off" var i = 0 var n = hintMin @@ -149,17 +149,17 @@ proc processSpecificNote(arg: string, state: TSpecialWord, pass: TCmdLinePass, add(id, arg[i]) inc(i) if i < len(arg) and (arg[i] == ']'): inc(i) - else: invalidCmdLineOption(pass, arg, info) + else: invalidCmdLineOption(pass, orig, info) if i < len(arg) and (arg[i] in {':', '='}): inc(i) - else: invalidCmdLineOption(pass, arg, info) - if state == wHint: + else: invalidCmdLineOption(pass, orig, info) + if state == wHint: var x = findStr(msgs.HintsToStr, id) if x >= 0: n = TNoteKind(x + ord(hintMin)) - else: invalidCmdLineOption(pass, arg, info) - else: + else: localError(info, "unknown hint: " & id) + else: var x = findStr(msgs.WarningsToStr, id) if x >= 0: n = TNoteKind(x + ord(warnMin)) - else: invalidCmdLineOption(pass, arg, info) + else: localError(info, "unknown warning: " & id) case whichKeyword(substr(arg, i)) of wOn: incl(gNotes, n) of wOff: excl(gNotes, n) @@ -326,7 +326,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "link": expectArg(switch, arg, pass, info) if pass in {passCmd2, passPP}: addFileToLink(arg) - of "debuginfo": + of "debuginfo": expectNoArg(switch, arg, pass, info) incl(gGlobalOptions, optCDebug) of "embedsrc": @@ -368,16 +368,26 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = defineSymbol("nogc") else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) of "warnings", "w": processOnOffSwitch({optWarns}, arg, pass, info) - of "warning": processSpecificNote(arg, wWarning, pass, info) - of "hint": processSpecificNote(arg, wHint, pass, info) + of "warning": processSpecificNote(arg, wWarning, pass, info, switch) + of "hint": processSpecificNote(arg, wHint, pass, info, switch) of "hints": processOnOffSwitch({optHints}, arg, pass, info) of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info) of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info) of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info) - of "debugger": - processOnOffSwitch({optEndb}, arg, pass, info) - if optEndb in gOptions: defineSymbol("endb") - else: undefSymbol("endb") + of "debugger": + case arg.normalize + of "on", "endb": + gOptions.incl optEndb + defineSymbol("endb") + of "off": + gOptions.excl optEndb + undefSymbol("endb") + of "native", "gdb": + incl(gGlobalOptions, optCDebug) + gOptions = gOptions + {optLineDir} - {optEndb} + undefSymbol("endb") + else: + localError(info, "expected endb|gdb but found " & arg) of "profiler": processOnOffSwitch({optProfiler}, arg, pass, info) if optProfiler in gOptions: defineSymbol("profiler") diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 8a5189167..7ddf44d4a 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -89,6 +89,7 @@ proc initDefines*() = defineSymbol("nimparsebiggestfloatmagic") defineSymbol("nimalias") defineSymbol("nimlocks") + defineSymbol("nimnode") # add platform specific symbols: for c in low(CPU)..high(CPU): diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 3f4f39c27..5439922af 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -126,7 +126,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string], if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break var idx = getVarIdx(varnames, id) if idx >= 0: app(result, varvalues[idx]) - else: rawMessage(errUnkownSubstitionVar, id) + else: rawMessage(errUnknownSubstitionVar, id) of '{': var id = "" inc(i) @@ -138,7 +138,7 @@ proc ropeFormatNamedVars(frmt: TFormatStr, varnames: openArray[string], # search for the variable: var idx = getVarIdx(varnames, id) if idx >= 0: app(result, varvalues[idx]) - else: rawMessage(errUnkownSubstitionVar, id) + else: rawMessage(errUnknownSubstitionVar, id) else: internalError("ropeFormatNamedVars") var start = i while i < L: @@ -272,7 +272,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string = ## type)?(,param type)*``. The callable type part will be added only if the ## node is not a proc, as those are the common ones. The suffix will be a dot ## and a single letter representing the type of the callable. The parameter - ## types will be added with a preceeding dash. Return types won't be added. + ## types will be added with a preceding dash. Return types won't be added. ## ## If you modify the output of this proc, please update the anchor generation ## section of ``doc/docgen.txt``. diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index bc888315f..5f6033e57 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -380,7 +380,7 @@ proc setCC*(ccname: string) = cCompiler = nameToCC(ccname) if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname) compileOptions = getConfigVar(cCompiler, ".options.always") - linkOptions = getConfigVar(cCompiler, ".options.linker") + linkOptions = "" ccompilerpath = getConfigVar(cCompiler, ".path") for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name) defineSymbol(CC[cCompiler].name) @@ -389,8 +389,8 @@ proc addOpt(dest: var string, src: string) = if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ") add(dest, src) -proc addLinkOption*(option: string) = - if find(linkOptions, option, 0) < 0: addOpt(linkOptions, option) +proc addLinkOption*(option: string) = + addOpt(linkOptions, option) proc addCompileOption*(option: string) = if strutils.find(compileOptions, option, 0) < 0: @@ -401,7 +401,7 @@ proc initVars*() = for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name) defineSymbol(CC[cCompiler].name) addCompileOption(getConfigVar(cCompiler, ".options.always")) - addLinkOption(getConfigVar(cCompiler, ".options.linker")) + #addLinkOption(getConfigVar(cCompiler, ".options.linker")) if len(ccompilerpath) == 0: ccompilerpath = getConfigVar(cCompiler, ".path") @@ -428,13 +428,17 @@ proc addFileToLink*(filename: string) = prependStr(toLink, filename) # BUGFIX: was ``appendStr`` -proc execExternalProgram*(cmd: string, prettyCmd = "") = +proc execWithEcho(cmd: string, prettyCmd = ""): int = if optListCmd in gGlobalOptions or gVerbosity > 0: if prettyCmd != "": msgWriteln(prettyCmd) else: msgWriteln(cmd) - if execCmd(cmd) != 0: rawMessage(errExecutionOfProgramFailed, "") + result = execCmd(cmd) + +proc execExternalProgram*(cmd: string, prettyCmd = "") = + if execWithEcho(cmd, prettyCmd) != 0: + rawMessage(errExecutionOfProgramFailed, "") proc generateScript(projectFile: string, script: PRope) = let (dir, name, ext) = splitFile(projectFile) @@ -549,13 +553,13 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = cfile = quoteShell(cfile) result = quoteShell(compilePattern % [ "file", cfile, "objfile", objfile, "options", options, - "include", includeCmd, "nimrod", getPrefixDir(), + "include", includeCmd, "nim", getPrefixDir(), "nim", getPrefixDir(), "lib", libpath]) add(result, ' ') addf(result, CC[c].compileTmpl, [ "file", cfile, "objfile", objfile, "options", options, "include", includeCmd, - "nimrod", quoteShell(getPrefixDir()), + "nim", quoteShell(getPrefixDir()), "nim", quoteShell(getPrefixDir()), "lib", quoteShell(libpath)]) @@ -622,15 +626,17 @@ proc callCCompiler*(projectfile: string) = if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors() var res = 0 if gNumberOfProcessors <= 1: - for i in countup(0, high(cmds)): res = max(execCmd(cmds[i]), res) + for i in countup(0, high(cmds)): + res = execWithEcho(cmds[i]) + if res != 0: rawMessage(errExecutionOfProgramFailed, []) elif optListCmd in gGlobalOptions or gVerbosity > 1: - res = execProcesses(cmds, {poEchoCmd, poUseShell, poParentStreams}, + res = execProcesses(cmds, {poEchoCmd, poUsePath, poParentStreams}, gNumberOfProcessors) elif gVerbosity == 1: - res = execProcesses(cmds, {poUseShell, poParentStreams}, + res = execProcesses(cmds, {poUsePath, poParentStreams}, gNumberOfProcessors, prettyCb) else: - res = execProcesses(cmds, {poUseShell, poParentStreams}, + res = execProcesses(cmds, {poUsePath, poParentStreams}, gNumberOfProcessors) if res != 0: if gNumberOfProcessors <= 1: @@ -673,15 +679,16 @@ proc callCCompiler*(projectfile: string) = if not exefile.isAbsolute(): exefile = joinPath(splitFile(projectfile).dir, exefile) exefile = quoteShell(exefile) - let linkOptions = getLinkOptions() + let linkOptions = getLinkOptions() & " " & + getConfigVar(cCompiler, ".options.linker") linkCmd = quoteShell(linkCmd % ["builddll", builddll, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, - "exefile", exefile, "nimrod", getPrefixDir(), "lib", libpath]) + "exefile", exefile, "nim", getPrefixDir(), "lib", libpath]) linkCmd.add ' ' addf(linkCmd, CC[c].linkTmpl, ["builddll", builddll, "buildgui", buildgui, "options", linkOptions, "objfiles", objfiles, "exefile", exefile, - "nimrod", quoteShell(getPrefixDir()), + "nim", quoteShell(getPrefixDir()), "lib", quoteShell(libpath)]) if optCompileOnly notin gGlobalOptions: if gVerbosity == 1: @@ -710,7 +717,8 @@ proc writeMapping*(gSymbolMapping: PRope) = app(code, strutils.escape(getCompileOptions())) app(code, "\n[Linker]\nFlags=") - app(code, strutils.escape(getLinkOptions())) + app(code, strutils.escape(getLinkOptions() & " " & + getConfigVar(cCompiler, ".options.linker"))) app(code, "\n[Environment]\nlibpath=") app(code, strutils.escape(libpath)) diff --git a/compiler/forloops.nim b/compiler/forloops.nim new file mode 100644 index 000000000..efe000968 --- /dev/null +++ b/compiler/forloops.nim @@ -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) diff --git a/compiler/nim.ini b/compiler/installer.ini index dcf9aa52f..48cd0b3b9 100644 --- a/compiler/nim.ini +++ b/compiler/installer.ini @@ -51,10 +51,10 @@ Files: "configure;makefile" Files: "*.ini" Files: "koch.nim" -Files: "icons/nimrod.ico" -Files: "icons/nimrod.rc" -Files: "icons/nimrod.res" -Files: "icons/nimrod_icon.o" +Files: "icons/nim.ico" +Files: "icons/nim.rc" +Files: "icons/nim.res" +Files: "icons/nim_icon.o" Files: "icons/koch.ico" Files: "icons/koch.rc" Files: "icons/koch.res" diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index beb84b00a..34f842d4a 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -148,7 +148,7 @@ proc mapType(typ: PType): TJSTypeKind = tyVarargs: result = etyObject of tyNil: result = etyNull - of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, + of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation, tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor, tyExpr, tyStmt, tyStatic, tyTypeDesc, tyTypeClasses: result = etyNone diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index b7dc277a4..123445e1f 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -15,7 +15,7 @@ import discard """ The basic approach is that captured vars need to be put on the heap and - that the calling chain needs to be explicitely modelled. Things to consider: + that the calling chain needs to be explicitly modelled. Things to consider: proc a = var v = 0 @@ -583,7 +583,7 @@ proc searchForInnerProcs(o: POuterContext, n: PNode, env: PEnv) = elif it.kind == nkIdentDefs: var L = sonsLen(it) if it.sons[0].kind == nkSym: - # this can be false for recursive invokations that already + # this can be false for recursive invocations that already # transformed it into 'env.varName': env.vars.incl(it.sons[0].sym.id) searchForInnerProcs(o, it.sons[L-1], env) @@ -999,7 +999,7 @@ proc liftForLoop*(body: PNode): PNode = # proc invoke(iter: iterator(): int) = # for x in iter(): echo x # - # --> When to create the closure? --> for the (count) occurence! + # --> When to create the closure? --> for the (count) occurrence! discard """ for i in foo(): ... diff --git a/compiler/lexer.nim b/compiler/lexer.nim index 4fbac2d5c..c86762121 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -107,7 +107,7 @@ type TToken* = object # a Nim token tokType*: TTokType # the type of the token indent*: int # the indentation; != -1 if the token has been - # preceeded with indentation + # preceded with indentation ident*: PIdent # the parsed identifier iNumber*: BiggestInt # the parsed integer literal fNumber*: BiggestFloat # the parsed floating point literal @@ -181,10 +181,8 @@ proc prettyTok*(tok: TToken): string = else: result = tokToStr(tok) proc printTok*(tok: TToken) = - write(stdout, tok.line, ":", tok.col, "\t") - write(stdout, TokTypeToStr[tok.tokType]) - write(stdout, " ") - writeln(stdout, tokToStr(tok)) + msgWriteln($tok.line & ":" & $tok.col & "\t" & + TokTypeToStr[tok.tokType] & " " & tokToStr(tok)) var dummyIdent: PIdent @@ -679,7 +677,7 @@ proc getOperator(L: var TLexer, tok: var TToken) = inc(pos) endOperator(L, tok, pos, h) # advance pos but don't store it in L.bufpos so the next token (which might - # be an operator too) gets the preceeding spaces: + # be an operator too) gets the preceding spaces: tok.strongSpaceB = 0 while buf[pos] == ' ': inc pos diff --git a/compiler/llstream.nim b/compiler/llstream.nim index be469548d..18ca4aec7 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -30,47 +30,32 @@ type PLLStream* = ref TLLStream -proc llStreamOpen*(data: string): PLLStream -proc llStreamOpen*(f: var File): PLLStream -proc llStreamOpen*(filename: string, mode: FileMode): PLLStream -proc llStreamOpen*(): PLLStream -proc llStreamOpenStdIn*(): PLLStream -proc llStreamClose*(s: PLLStream) -proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int -proc llStreamReadLine*(s: PLLStream, line: var string): bool -proc llStreamReadAll*(s: PLLStream): string -proc llStreamWrite*(s: PLLStream, data: string) -proc llStreamWrite*(s: PLLStream, data: char) -proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) -proc llStreamWriteln*(s: PLLStream, data: string) -# implementation - -proc llStreamOpen(data: string): PLLStream = +proc llStreamOpen*(data: string): PLLStream = new(result) result.s = data result.kind = llsString -proc llStreamOpen(f: var File): PLLStream = +proc llStreamOpen*(f: File): PLLStream = new(result) result.f = f result.kind = llsFile -proc llStreamOpen(filename: string, mode: FileMode): PLLStream = +proc llStreamOpen*(filename: string, mode: FileMode): PLLStream = new(result) result.kind = llsFile if not open(result.f, filename, mode): result = nil -proc llStreamOpen(): PLLStream = +proc llStreamOpen*(): PLLStream = new(result) result.kind = llsNone -proc llStreamOpenStdIn(): PLLStream = +proc llStreamOpenStdIn*(): PLLStream = new(result) result.kind = llsStdIn result.s = "" result.lineOffset = -1 -proc llStreamClose(s: PLLStream) = +proc llStreamClose*(s: PLLStream) = case s.kind of llsNone, llsString, llsStdIn: discard @@ -130,7 +115,7 @@ proc llReadFromStdin(s: PLLStream, buf: pointer, bufLen: int): int = copyMem(buf, addr(s.s[s.rd]), result) inc(s.rd, result) -proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int = +proc llStreamRead*(s: PLLStream, buf: pointer, bufLen: int): int = case s.kind of llsNone: result = 0 @@ -144,7 +129,7 @@ proc llStreamRead(s: PLLStream, buf: pointer, bufLen: int): int = of llsStdIn: result = llReadFromStdin(s, buf, bufLen) -proc llStreamReadLine(s: PLLStream, line: var string): bool = +proc llStreamReadLine*(s: PLLStream, line: var string): bool = setLen(line, 0) case s.kind of llsNone: @@ -168,7 +153,7 @@ proc llStreamReadLine(s: PLLStream, line: var string): bool = of llsStdIn: result = readLine(stdin, line) -proc llStreamWrite(s: PLLStream, data: string) = +proc llStreamWrite*(s: PLLStream, data: string) = case s.kind of llsNone, llsStdIn: discard @@ -178,11 +163,11 @@ proc llStreamWrite(s: PLLStream, data: string) = of llsFile: write(s.f, data) -proc llStreamWriteln(s: PLLStream, data: string) = +proc llStreamWriteln*(s: PLLStream, data: string) = llStreamWrite(s, data) llStreamWrite(s, "\n") -proc llStreamWrite(s: PLLStream, data: char) = +proc llStreamWrite*(s: PLLStream, data: char) = var c: char case s.kind of llsNone, llsStdIn: @@ -194,7 +179,7 @@ proc llStreamWrite(s: PLLStream, data: char) = c = data discard writeBuffer(s.f, addr(c), sizeof(c)) -proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) = +proc llStreamWrite*(s: PLLStream, buf: pointer, buflen: int) = case s.kind of llsNone, llsStdIn: discard @@ -206,7 +191,7 @@ proc llStreamWrite(s: PLLStream, buf: pointer, buflen: int) = of llsFile: discard writeBuffer(s.f, buf, buflen) -proc llStreamReadAll(s: PLLStream): string = +proc llStreamReadAll*(s: PLLStream): string = const bufSize = 2048 case s.kind diff --git a/compiler/lookups.nim b/compiler/lookups.nim index 21d07f280..6d3379bb9 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -176,7 +176,7 @@ proc addInterfaceDeclAux(c: PContext, sym: PSym) = if sfExported in sym.flags: # add to interface: if c.module != nil: strTableAdd(c.module.tab, sym) - else: internalError(sym.info, "AddInterfaceDeclAux") + else: internalError(sym.info, "addInterfaceDeclAux") proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) = addDeclAt(scope, sym) diff --git a/compiler/main.nim b/compiler/main.nim index 06dcad7b0..f7592a891 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -62,7 +62,7 @@ proc commandCompileToC = compileProject() cgenWriteModules() if gCmd != cmdRun: - extccomp.callCCompiler(changeFileExt(gProjectFull, "")) + extccomp.callCCompiler(if gProjectName == "-": "stdinfile" else: changeFileExt(gProjectFull, "")) if isServing: # caas will keep track only of the compilation commands @@ -251,7 +251,6 @@ proc mainCommand* = commandCompileToC() of "cpp", "compiletocpp": gCmd = cmdCompileToCpp - if cCompiler == ccGcc: setCC("gcc") defineSymbol("cpp") commandCompileToC() of "objc", "compiletooc": diff --git a/compiler/modules.nim b/compiler/modules.nim index db05ccc6c..a2b739efc 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -116,7 +116,7 @@ proc newModule(fileIdx: int32): PSym = result.kind = skModule let filename = fileIdx.toFullPath result.name = getIdent(splitFile(filename).name) - if not isNimIdentifier(result.name.s): + if result.name.s != "-" and not isNimIdentifier(result.name.s): rawMessage(errInvalidModuleName, result.name.s) result.info = newLineInfo(fileIdx, 1, 1) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index e78414804..088468dcc 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -69,7 +69,7 @@ type errInvalidOrderInArrayConstructor, errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, errOptionExpected, errXisNoLabel, errNotAllCasesCovered, - errUnkownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, + errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable, errNoPragmasAllowedForX, errNoGenericParamsAllowedForX, errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent, errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX, @@ -89,7 +89,7 @@ type errTIsNotAConcreteType, errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError, errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile, - errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitely, + errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly, errOnlyACallOpCanBeDelegator, errUsingNoSymbol, errMacroBodyDependsOnGenericTypes, errDestructorNotGenericEnough, @@ -113,7 +113,7 @@ type warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel, warnUnknownSubstitutionX, warnLanguageXNotSupported, warnFieldXNotSupported, warnCommentXIgnored, - warnNilStatement, warnAnalysisLoophole, + warnNilStatement, warnTypelessParam, warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode, warnEachIdentIsTuple, warnShadowIdent, warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, @@ -280,7 +280,7 @@ const errOptionExpected: "option expected, but found \'$1\'", errXisNoLabel: "\'$1\' is not a label", errNotAllCasesCovered: "not all cases are covered", - errUnkownSubstitionVar: "unknown substitution variable: \'$1\'", + errUnknownSubstitionVar: "unknown substitution variable: \'$1\'", errComplexStmtRequiresInd: "complex statement requires indentation", errXisNotCallable: "\'$1\' is not callable", errNoPragmasAllowedForX: "no pragmas allowed for $1", @@ -312,7 +312,7 @@ const errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", errXNeedsParamObjectType: "'$1' needs a parameter that has an object type", errTemplateInstantiationTooNested: "template/macro instantiation too nested", - errInstantiationFrom: "instantiation from here", + errInstantiationFrom: "template/generic instantiation from here", errInvalidIndexValueForTuple: "invalid index value for tuple subscript", errCommandExpectsFilename: "command expects a filename argument", errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file", @@ -326,12 +326,12 @@ const errXisNoValidIndexFile: "\'$1\' is no valid index file", errCannotRenderX: "cannot render reStructuredText element \'$1\'", errVarVarTypeNotAllowed: "type \'var var\' is not allowed", - errInstantiateXExplicitely: "instantiate '$1' explicitely", + errInstantiateXExplicitly: "instantiate '$1' explicitly", errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator", errUsingNoSymbol: "'$1' is not a variable, constant or a proc name", errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " & "because the parameter '$1' has a generic type", - errDestructorNotGenericEnough: "Destructor signarue is too specific. " & + errDestructorNotGenericEnough: "Destructor signature is too specific. " & "A destructor must be associated will all instantiations of a generic type", errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " & "templates, macros and other inline iterators", @@ -360,7 +360,7 @@ const errCannotInferReturnType: "cannot infer the return type of the proc", errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " & "it is used as an operand to another routine and the types " & - "of the generic paramers can be infered from the expected signature.", + "of the generic paramers can be inferred from the expected signature.", errCompilerDoesntSupportTarget: "The current compiler \'$1\' doesn't support the requested compilation target", errUser: "$1", warnCannotOpenFile: "cannot open \'$1\' [CannotOpenFile]", @@ -377,7 +377,7 @@ const warnFieldXNotSupported: "field \'$1\' not supported [FieldXNotSupported]", warnCommentXIgnored: "comment \'$1\' ignored [CommentXIgnored]", warnNilStatement: "'nil' statement is deprecated; use an empty 'discard' statement instead [NilStmt]", - warnAnalysisLoophole: "thread analysis incomplete due to unknown call '$1' [AnalysisLoophole]", + warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template' [TypelessParam]", warnDifferentHeaps: "possible inconsistency of thread local heaps [DifferentHeaps]", warnWriteToForeignHeap: "write to foreign heap [WriteToForeignHeap]", warnUnsafeCode: "unsafe code: '$1' [UnsafeCode]", @@ -420,7 +420,7 @@ const "RedefinitionOfLabel", "UnknownSubstitutionX", "LanguageXNotSupported", "FieldXNotSupported", "CommentXIgnored", "NilStmt", - "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap", + "TypelessParam", "DifferentHeaps", "WriteToForeignHeap", "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", "GcMem", "Destructor", "LockLevel", "User"] @@ -445,7 +445,7 @@ type TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints TNoteKinds* = set[TNoteKind] - TFileInfo*{.final.} = object + TFileInfo* = object fullPath: string # This is a canonical full filesystem path projPath*: string # This is relative to the project's root shortName*: string # short name of the module @@ -460,9 +460,9 @@ type # and parsed; usually 'nil' but is used # for 'nimsuggest' - TLineInfo*{.final.} = object # This is designed to be as small as possible, + TLineInfo* = object # This is designed to be as small as possible, # because it is used - # in syntax nodes. We safe space here by using + # in syntax nodes. We save space here by using # two int16 and an int32. # On 64 bit and on 32 bit systems this is # only 8 bytes. @@ -495,7 +495,7 @@ proc toCChar*(c: char): string = proc makeCString*(s: string): PRope = # BUGFIX: We have to split long strings into many ropes. Otherwise - # this could trigger an InternalError(). See the ropes module for + # this could trigger an internalError(). See the ropes module for # further information. const MaxLineLength = 64 @@ -524,7 +524,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo = if optEmbedOrigSrc in gGlobalOptions or true: result.lines = @[] -proc fileInfoIdx*(filename: string): int32 = +proc fileInfoIdx*(filename: string; isKnownFile: var bool): int32 = var canon: string pseudoPath = false @@ -541,11 +541,16 @@ proc fileInfoIdx*(filename: string): int32 = if filenameToIndexTbl.hasKey(canon): result = filenameToIndexTbl[canon] else: + isKnownFile = false result = fileInfos.len.int32 fileInfos.add(newFileInfo(canon, if pseudoPath: filename else: canon.shortenDir)) filenameToIndexTbl[canon] = result +proc fileInfoIdx*(filename: string): int32 = + var dummy: bool + result = fileInfoIdx(filename, dummy) + proc newLineInfo*(fileInfoIdx: int32, line, col: int): TLineInfo = result.fileIndex = fileInfoIdx result.line = int16(line) @@ -693,7 +698,9 @@ proc msgWriteln*(s: string) = #if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return - if optStdout in gGlobalOptions: + if not isNil(writelnHook): + writelnHook(s) + elif optStdout in gGlobalOptions: if eStdErr in errorOutputs: writeln(stderr, s) else: if eStdOut in errorOutputs: writeln(stdout, s) @@ -717,7 +724,10 @@ type proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = template quit = if defined(debug) or gVerbosity >= 3 or msg == errInternal: - writeStackTrace() + if stackTraceAvailable() and isNil(writelnHook): + writeStackTrace() + else: + msgWriteln("No stack traceback available\nTo create a stacktrace, rerun compilation with ./koch temp " & options.command & " <file>") quit 1 if msg >= fatalMin and msg <= fatalMax: diff --git a/compiler/nim.nim b/compiler/nim.nim index 617758b2d..b8ba2c6da 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -9,9 +9,9 @@ when defined(gcc) and defined(windows): when defined(x86): - {.link: "icons/nimrod.res".} + {.link: "icons/nim.res".} else: - {.link: "icons/nimrod_icon.o".} + {.link: "icons/nim_icon.o".} import commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, @@ -61,6 +61,8 @@ proc handleCmdLine() = if gCmd == cmdRun: tccgen.run(commands.arguments) if optRun in gGlobalOptions: + if gProjectName == "-": + gProjectFull = "stdinfile" if gCmd == cmdCompileToJS: var ex: string if options.outFile.len > 0: diff --git a/compiler/nim.nimrod.cfg b/compiler/nim.nim.cfg index f4d8b9dcb..f4d8b9dcb 100644 --- a/compiler/nim.nimrod.cfg +++ b/compiler/nim.nim.cfg diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 049b94aa9..23f3331a2 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -33,7 +33,7 @@ proc `<.`(a, b: string): bool = while true: let ii = parseInt(a, verA, i) let jj = parseInt(b, verB, j) - # if A has no number left, but B has, B is prefered: 0.8 vs 0.8.3 + # if A has no number left, but B has, B is preferred: 0.8 vs 0.8.3 if ii <= 0 or jj <= 0: return jj > 0 if verA < verB: return true elif verA > verB: return false diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index bcf9b5359..711b476e6 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -11,10 +11,10 @@ import llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer, - options, idents, wordrecg + options, idents, wordrecg, strtabs # ---------------- configuration file parser ----------------------------- -# we use Nim's scanner here to safe space and work +# we use Nim's scanner here to save space and work proc ppGetTok(L: var TLexer, tok: var TToken) = # simple filter @@ -82,17 +82,17 @@ proc doElif(L: var TLexer, tok: var TToken) = proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest) = var nestedIfs = 0 while true: - if (tok.ident != nil) and (tok.ident.s == "@"): + if tok.ident != nil and tok.ident.s == "@": ppGetTok(L, tok) case whichKeyword(tok.ident) of wIf: inc(nestedIfs) of wElse: - if (dest == jdElseEndif) and (nestedIfs == 0): + if dest == jdElseEndif and nestedIfs == 0: doElse(L, tok) break of wElif: - if (dest == jdElseEndif) and (nestedIfs == 0): + if dest == jdElseEndif and nestedIfs == 0: doElif(L, tok) break of wEnd: @@ -119,9 +119,10 @@ proc parseDirective(L: var TLexer, tok: var TToken) = of wElif: doElif(L, tok) of wElse: doElse(L, tok) of wEnd: doEnd(L, tok) - of wWrite: + of wWrite: ppGetTok(L, tok) - msgs.msgWriteln(tokToStr(tok)) + msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars, + {useEnvironment, useKey})) ppGetTok(L, tok) else: case tok.ident.s.normalize @@ -157,7 +158,7 @@ proc checkSymbol(L: TLexer, tok: TToken) = proc parseAssignment(L: var TLexer, tok: var TToken) = if tok.ident.id == getIdent("-").id or tok.ident.id == getIdent("--").id: confTok(L, tok) # skip unnecessary prefix - var info = getLineInfo(L, tok) # safe for later in case of an error + var info = getLineInfo(L, tok) # save for later in case of an error checkSymbol(L, tok) var s = tokToStr(tok) confTok(L, tok) # skip symbol @@ -178,9 +179,10 @@ proc parseAssignment(L: var TLexer, tok: var TToken) = if tok.tokType == tkBracketRi: confTok(L, tok) else: lexMessage(L, errTokenExpected, "']'") add(val, ']') - if tok.tokType in {tkColon, tkEquals}: + let percent = tok.ident.id == getIdent("%=").id + if tok.tokType in {tkColon, tkEquals} or percent: if len(val) > 0: add(val, ':') - confTok(L, tok) # skip ':' or '=' + confTok(L, tok) # skip ':' or '=' or '%' checkSymbol(L, tok) add(val, tokToStr(tok)) confTok(L, tok) # skip symbol @@ -189,7 +191,11 @@ proc parseAssignment(L: var TLexer, tok: var TToken) = checkSymbol(L, tok) add(val, tokToStr(tok)) confTok(L, tok) - processSwitch(s, val, passPP, info) + if percent: + processSwitch(s, strtabs.`%`(val, options.gConfigVars, + {useEnvironment, useEmpty}), passPP, info) + else: + processSwitch(s, val, passPP, info) proc readConfigFile(filename: string) = var @@ -246,6 +252,11 @@ proc loadConfigs*(cfg: string) = if gProjectName.len != 0: # new project wide config file: - let projectConfig = changeFileExt(gProjectFull, "nim.cfg") - if fileExists(projectConfig): readConfigFile(projectConfig) - else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg")) + var projectConfig = changeFileExt(gProjectFull, "nimcfg") + if not fileExists(projectConfig): + projectConfig = changeFileExt(gProjectFull, "nim.cfg") + if not fileExists(projectConfig): + projectConfig = changeFileExt(gProjectFull, "nimrod.cfg") + if fileExists(projectConfig): + rawMessage(warnDeprecated, projectConfig) + readConfigFile(projectConfig) diff --git a/compiler/nimfix/nimfix.nim.cfg b/compiler/nimfix/nimfix.nim.cfg index 31a41e080..533563a98 100644 --- a/compiler/nimfix/nimfix.nim.cfg +++ b/compiler/nimfix/nimfix.nim.cfg @@ -2,7 +2,7 @@ # gc:markAndSweep hint[XDeclaredButNotUsed]:off -path:"$projectPath/../.." +path:"$projectPath/.." path:"$lib/packages/docutils" path:"$nim/compiler" diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim index 6edea06e5..b45ca475c 100644 --- a/compiler/nimsuggest/nimsuggest.nim +++ b/compiler/nimsuggest/nimsuggest.nim @@ -87,8 +87,9 @@ proc action(cmd: string) = i += skipWhile(cmd, seps, i) i += parseInt(cmd, col, i) + var isKnownFile = true if orig.len == 0: err() - let dirtyIdx = orig.fileInfoIdx + let dirtyIdx = orig.fileInfoIdx(isKnownFile) if dirtyfile.len != 0: msgs.setDirtyFile(dirtyIdx, dirtyfile) else: msgs.setDirtyFile(dirtyIdx, nil) @@ -99,7 +100,10 @@ proc action(cmd: string) = gTrackPos = newLineInfo(dirtyIdx, line, col) #echo dirtyfile, gDirtyBufferIdx, " project ", gProjectMainIdx gErrorCounter = 0 - compileProject() + if not isKnownFile: + compileProject(dirtyIdx) + else: + compileProject() proc serve() = # do not stop after the first error: @@ -116,13 +120,17 @@ proc serve() = server.bindAddr(gPort, gAddress) var inp = "".TaintedString server.listen() - var stdoutSocket = newSocket() - msgs.writelnHook = proc (line: string) = - stdoutSocket.send(line & "\c\L") + while true: + var stdoutSocket = newSocket() + msgs.writelnHook = proc (line: string) = + stdoutSocket.send(line & "\c\L") + accept(server, stdoutSocket) + stdoutSocket.readLine(inp) action inp.string + stdoutSocket.send("\c\L") stdoutSocket.close() diff --git a/compiler/options.nim b/compiler/options.nim index d6d9389f5..1b4a624ab 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -283,19 +283,19 @@ when noTimeMachine: var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir]) discard p.waitForExit p.close - except E_Base, EOS: + except Exception: discard -proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = +proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = var (head, tail) = splitPath(f) #if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep)) var subdir = getGeneratedPath() # / head if createSubDir: - try: + try: createDir(subdir) when noTimeMachine: excludeDirFromTimeMachine(subdir) - except OSError: + except OSError: writeln(stdout, "cannot create directory: " & subdir) quit(1) result = joinPath(subdir, tail) diff --git a/compiler/parser.nim b/compiler/parser.nim index aae0ce7f9..8fbf033d8 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -198,8 +198,8 @@ proc isSigilLike(tok: TToken): bool {.inline.} = proc isRightAssociative(tok: TToken): bool {.inline.} = ## Determines whether the token is right assocative. - result = tok.tokType == tkOpr and (tok.ident.s[0] == '^' or - (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>')) + result = tok.tokType == tkOpr and tok.ident.s[0] == '^' + # or (let L = tok.ident.s.len; L > 1 and tok.ident.s[L-1] == '>')) proc getPrecedence(tok: TToken, strongSpaces: bool): int = ## Calculates the precedence of the given token. @@ -1597,6 +1597,7 @@ proc parseEnum(p: var TParser): PNode = optInd(p, result) while true: var a = parseSymbol(p) + if a.kind == nkEmpty: return if p.tok.indent >= 0 and p.tok.indent <= p.currInd: add(result, a) break diff --git a/compiler/passes.nim b/compiler/passes.nim index f9c3d75f9..96088bd88 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -170,7 +170,11 @@ proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) = openPasses(a, module) if stream == nil: let filename = fileIdx.toFullPathConsiderDirty - s = llStreamOpen(filename, fmRead) + if module.name.s == "-": + module.name.s = "stdinfile" + s = llStreamOpen(stdin) + else: + s = llStreamOpen(filename, fmRead) if s == nil: rawMessage(errCannotOpenFile, filename) return diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 9ac0988c5..368b0b37b 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -275,7 +275,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = if arg != rs and aliases.isPartOf(rs, arg) == arYes: ok = true break - # constraint not fullfilled: + # constraint not fulfilled: if not ok: return nil of aqNoAlias: # it MUST not alias with any other param: @@ -284,7 +284,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode = if arg != rs and aliases.isPartOf(rs, arg) != arNo: ok = false break - # constraint not fullfilled: + # constraint not fulfilled: if not ok: return nil markUsed(n.info, s) diff --git a/compiler/platform.nim b/compiler/platform.nim index 8360a9dcc..a21e73248 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -138,7 +138,7 @@ const props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}), (name: "VxWorks", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ";", dirSep: "\\", - scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", + scriptExt: ".sh", curDir: ".", exeExt: ".vxe", extSep: ".", props: {ospNeedsPIC, ospPosix, ospLacksThreadVars}), (name: "JS", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 90f87696b..78ee490e2 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -735,11 +735,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, incl(sym.flags, sfProcvar) if sym.typ != nil: incl(sym.typ.flags, tfThread) of wGcSafe: - if optThreadAnalysis in gGlobalOptions: - noVal(it) - if sym.kind != skType: incl(sym.flags, sfThread) - if sym.typ != nil: incl(sym.typ.flags, tfGcSafe) - else: invalidPragma(it) + noVal(it) + if sym.kind != skType: incl(sym.flags, sfThread) + if sym.typ != nil: incl(sym.typ.flags, tfGcSafe) + else: invalidPragma(it) of wPacked: noVal(it) if sym.typ == nil: invalidPragma(it) diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 3b3538e5d..545a8dda9 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -666,7 +666,7 @@ proc newRodReader(modfilename: string, crc: TCrc32, r.readerIndex = readerIndex r.filename = modfilename initIdTable(r.syms) - # we terminate the file explicitely with ``\0``, so the cast to `cstring` + # we terminate the file explicitly with ``\0``, so the cast to `cstring` # is safe: r.s = cast[cstring](r.memfile.mem) if startsWith(r.s, "NIM:"): diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 9fed7ac52..0f211b4ba 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -200,7 +200,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) = return # we need no surrounding [] here because the type is in a line of its own if t.kind == tyForward: internalError("encodeType: tyForward") - # for the new rodfile viewer we use a preceeding [ so that the data section + # for the new rodfile viewer we use a preceding [ so that the data section # can easily be disambiguated: add(result, '[') encodeVInt(ord(t.kind), result) diff --git a/compiler/ropes.nim b/compiler/ropes.nim index b14081694..ad6801d18 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -52,7 +52,7 @@ # Note that the left and right pointers are not needed for leaves. # Leaves have relatively high memory overhead (~30 bytes on a 32 # bit machines) and we produce many of them. This is why we cache and -# share leaves accross different rope trees. +# share leaves across different rope trees. # To cache them they are inserted in a `cache` array. import diff --git a/compiler/sem.nim b/compiler/sem.nim index 214f471d6..a90948245 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -95,15 +95,6 @@ proc inferWithMetatype(c: PContext, formal: PType, var commonTypeBegin = PType(kind: tyExpr) -proc isEmptyContainer(t: PType): bool = - case t.kind - of tyExpr, tyNil: result = true - of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty - of tySet, tySequence, tyOpenArray, tyVarargs: - result = t.sons[0].kind == tyEmpty - of tyGenericInst: result = isEmptyContainer(t.lastSon) - else: result = false - proc commonType*(x, y: PType): PType = # new type relation that is used for array constructors, # if expressions, etc.: @@ -130,9 +121,11 @@ proc commonType*(x, y: PType): PType = elif a.kind == tyTuple and b.kind == tyTuple and a.len == b.len: var nt: PType for i in 0.. <a.len: - if isEmptyContainer(a.sons[i]) and not isEmptyContainer(b.sons[i]): + let aEmpty = isEmptyContainer(a.sons[i]) + let bEmpty = isEmptyContainer(b.sons[i]) + if aEmpty != bEmpty: if nt.isNil: nt = copyType(a, a.owner, false) - nt.sons[i] = b.sons[i] + nt.sons[i] = if aEmpty: b.sons[i] else: a.sons[i] if not nt.isNil: result = nt #elif b.sons[idx].kind == tyEmpty: return x elif a.kind == tyRange and b.kind == tyRange: diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 71ebbbafd..61e39877a 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -184,7 +184,7 @@ proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) = of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt, - tyTypeDesc, tyGenericInvokation, tyBigNum, tyConst, tyForward: + tyTypeDesc, tyGenericInvocation, tyBigNum, tyConst, tyForward: internalError(c.info, "assignment requested for type: " & typeToString(t)) of tyDistinct, tyOrdinal, tyRange, tyGenericInst, tyFieldAccessor, tyStatic, tyVar: diff --git a/compiler/semcall.nim b/compiler/semcall.nim index cdfdfc9d0..d92e1ab20 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -42,7 +42,7 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, errors: var CandidateErrors) = var o: TOverloadIter var sym = initOverloadIter(o, c, headSymbol) - var symScope = o.lastOverloadScope + let symScope = o.lastOverloadScope var z: TCandidate @@ -56,6 +56,9 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, determineType(c, sym) initCandidate(c, z, sym, initialBinding, o.lastOverloadScope) z.calleeSym = sym + + #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140: + # gDebug = true matches(c, n, orig, z) if errors != nil: errors.safeAdd(sym) @@ -72,9 +75,13 @@ proc pickBestCandidate(c: PContext, headSymbol: PNode, if cmp < 0: best = z # x is better than the best so far elif cmp == 0: alt = z # x is as good as the best so far else: discard - #if sym.name.s == "shl" and (n.info ?? "net.nim"): + #if sym.name.s == "*" and (n.info ?? "temp5.nim") and n.info.line == 140: # echo "Matches ", n.info, " ", typeToString(sym.typ) + # debug sym # writeMatches(z) + # for i in 1 .. <len(z.call): + # z.call[i].typ.debug + # quit 1 sym = nextOverloadIter(o, c, headSymbol) proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) = @@ -264,7 +271,7 @@ proc inferWithMetatype(c: PContext, formal: PType, instGenericConvertersArg(c, result, m) if result != nil: # This almost exactly replicates the steps taken by the compiler during - # param matching. It performs an embarassing ammount of back-and-forth + # param matching. It performs an embarrassing amount of back-and-forth # type jugling, but it's the price to pay for consistency and correctness result.typ = generateTypeInstance(c, m.bindings, arg.info, formal.skipTypes({tyCompositeTypeClass})) @@ -315,6 +322,8 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode, var r = resolveOverloads(c, n, nOrig, filter, errors) if r.state == csMatch: result = semResolvedCall(c, n, r) else: + # get rid of the deref again for a better error message: + n.sons[1] = n.sons[1].sons[0] notFoundError(c, n, errors) else: notFoundError(c, n, errors) diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 157761591..27d441000 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -221,6 +221,7 @@ proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode = proc makeTypeFromExpr*(c: PContext, n: PNode): PType = result = newTypeS(tyFromExpr, c) + assert n != nil result.n = n proc newTypeWithSons*(c: PContext, kind: TTypeKind, diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim index 4ce610bf9..bbc68ee87 100644 --- a/compiler/semdestruct.nim +++ b/compiler/semdestruct.nim @@ -30,7 +30,7 @@ proc instantiateDestructor(c: PContext, typ: PType): PType proc doDestructorStuff(c: PContext, s: PSym, n: PNode) = var t = s.typ.sons[1].skipTypes({tyVar}) - if t.kind == tyGenericInvokation: + if t.kind == tyGenericInvocation: for i in 1 .. <t.sonsLen: if t.sons[i].kind != tyGenericParam: localError(n.info, errDestructorNotGenericEnough) diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index cd27cf15d..89469ae50 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -103,28 +103,31 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = newSymNode(s, n.info) of skMacro: result = semMacroExpr(c, n, n, s, flags) of skTemplate: result = semTemplateExpr(c, n, s, flags) - of skVar, skLet, skResult, skParam, skForVar: + of skParam: + markUsed(n.info, s) + styleCheckUse(n.info, s) + if s.typ.kind == tyStatic and s.typ.n != nil: + # XXX see the hack in sigmatch.nim ... + return s.typ.n + elif sfGenSym in s.flags: + if c.p.wasForwarded: + # gensym'ed parameters that nevertheless have been forward declared + # need a special fixup: + let realParam = c.p.owner.typ.n[s.position+1] + internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam + return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info) + elif c.p.owner.kind == skMacro: + # gensym'ed macro parameters need a similar hack (see bug #1944): + var u = searchInScopes(c, s.name) + internalAssert u != nil and u.kind == skParam and u.owner == s.owner + return newSymNode(u, n.info) + result = newSymNode(s, n.info) + of skVar, skLet, skResult, skForVar: markUsed(n.info, s) styleCheckUse(n.info, s) # if a proc accesses a global variable, it is not side effect free: if sfGlobal in s.flags: incl(c.p.owner.flags, sfSideEffect) - elif s.kind == skParam: - if s.typ.kind == tyStatic and s.typ.n != nil: - # XXX see the hack in sigmatch.nim ... - return s.typ.n - elif sfGenSym in s.flags: - if c.p.wasForwarded: - # gensym'ed parameters that nevertheless have been forward declared - # need a special fixup: - let realParam = c.p.owner.typ.n[s.position+1] - internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam - return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info) - elif c.p.owner.kind == skMacro: - # gensym'ed macro parameters need a similar hack (see bug #1944): - var u = searchInScopes(c, s.name) - internalAssert u != nil and u.kind == skParam and u.owner == s.owner - return newSymNode(u, n.info) result = newSymNode(s, n.info) # We cannot check for access to outer vars for example because it's still # not sure the symbol really ends up being used: @@ -306,7 +309,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc, tyFieldAccessor}) case typ.kind - of tySequence, tyString, tyOpenArray, tyVarargs: + of tySequence, tyString, tyCString, tyOpenArray, tyVarargs: n.typ = getSysType(tyInt) of tyArrayConstr, tyArray: n.typ = typ.sons[0] # indextype @@ -445,25 +448,30 @@ proc changeType(n: PNode, newType: PType, check: bool) = let tup = newType.skipTypes({tyGenericInst}) if tup.kind != tyTuple: internalError(n.info, "changeType: no tuple type for constructor") - elif newType.n == nil: discard - elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: - for i in countup(0, sonsLen(n) - 1): + elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: + # named tuple? + for i in countup(0, sonsLen(n) - 1): var m = n.sons[i].sons[0] - if m.kind != nkSym: + if m.kind != nkSym: internalError(m.info, "changeType(): invalid tuple constr") return - var f = getSymFromList(newType.n, m.sym.name) - if f == nil: - internalError(m.info, "changeType(): invalid identifier") - return - changeType(n.sons[i].sons[1], f.typ, check) + if tup.n != nil: + var f = getSymFromList(newType.n, m.sym.name) + if f == nil: + internalError(m.info, "changeType(): invalid identifier") + return + changeType(n.sons[i].sons[1], f.typ, check) + else: + changeType(n.sons[i].sons[1], tup.sons[i], check) else: for i in countup(0, sonsLen(n) - 1): - var m = n.sons[i] - var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i]) - addSon(a, newSymNode(newType.n.sons[i].sym)) - addSon(a, m) - changeType(m, tup.sons[i], check) + changeType(n.sons[i], tup.sons[i], check) + when false: + var m = n.sons[i] + var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i]) + addSon(a, newSymNode(newType.n.sons[i].sym)) + addSon(a, m) + changeType(m, tup.sons[i], check) of nkCharLit..nkUInt64Lit: if check: let value = n.intVal @@ -578,11 +586,12 @@ proc skipObjConv(n: PNode): PNode = proc isAssignable(c: PContext, n: PNode): TAssignableResult = result = parampatterns.isAssignable(c.p.owner, n) -proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = - if n.kind == nkHiddenDeref: +proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = + if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or + sfCompileToCpp in c.module.flags): checkSonsLen(n, 1) result = n.sons[0] - else: + else: result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ)) addSon(result, n) if isAssignable(c, n) notin {arLValue, arLocalLValue}: @@ -677,7 +686,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = # implicit statics. if n.len > 1: for i in 1 .. <n.len: - if n[i].typ.kind != tyStatic or tfUnresolved notin n[i].typ.flags: + # see bug #2113, it's possible that n[i].typ for errornous code: + if n[i].typ.isNil or n[i].typ.kind != tyStatic or + tfUnresolved notin n[i].typ.flags: break maybeLabelAsStatic n.typ = newTypeWithSons(c, tyStatic, @[n.typ]) n.typ.flags.incl tfUnresolved @@ -745,6 +756,9 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, else: if callee.kind in skIterators and callee.id == c.p.owner.id: localError(n.info, errRecursiveDependencyX, callee.name.s) + # error correction, prevents endless for loop elimination in transf. + # See bug #2051: + result.sons[0] = newSymNode(errorSym(c, n)) if sfNoSideEffect notin callee.flags: if {sfImportc, sfSideEffect} * callee.flags != {}: incl(c.p.owner.flags, sfSideEffect) @@ -1209,6 +1223,7 @@ proc asgnToResultVar(c: PContext, n, le, ri: PNode) {.inline.} = if x.typ.kind == tyVar and x.kind == nkSym and x.sym.kind == skResult: n.sons[0] = x # 'result[]' --> 'result' n.sons[1] = takeImplicitAddr(c, ri) + x.typ.flags.incl tfVarIsPtr template resultTypeIsInferrable(typ: PType): expr = typ.isMetaType and typ.kind != tyTypeDesc @@ -1327,7 +1342,12 @@ proc semProcBody(c: PContext, n: PNode): PNode = if c.p.owner.kind notin {skMacro, skTemplate} and c.p.resultSym != nil and c.p.resultSym.typ.isMetaType: - localError(c.p.resultSym.info, errCannotInferReturnType) + if isEmptyType(result.typ): + # we inferred a 'void' return type: + c.p.resultSym.typ = nil + c.p.owner.typ.sons[0] = nil + else: + localError(c.p.resultSym.info, errCannotInferReturnType) closeScope(c) @@ -1492,7 +1512,9 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = # Preserve the magic symbol in order to be handled in evals.nim internalAssert n.sons[0].sym.magic == mExpandToAst - n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType + #n.typ = getSysSym("PNimrodNode").typ # expandedSym.getReturnType + n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode" + else: sysTypeFromName"PNimrodNode" result = n proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, @@ -1620,7 +1642,7 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode = result = semDirectOp(c, n, flags) proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType = - result = newType(tyGenericInvokation, c.module) + result = newType(tyGenericInvocation, c.module) addSonSkipIntLit(result, magicsys.getCompilerProc("FlowVar").typ) addSonSkipIntLit(result, t) result = instGenericContainer(c, info, result, allowMetaTypes = false) @@ -1900,7 +1922,7 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = it.sons[0] = newSymNode(f) e = fitNode(c, f.typ, e) # small hack here in a nkObjConstr the ``nkExprColonExpr`` node can have - # 3 childen the last being the field check + # 3 children the last being the field check if check != nil: check.sons[0] = it.sons[0] it.add(check) @@ -1984,7 +2006,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.kind == nkSym: markIndirect(c, result.sym) # if isGenericRoutine(result.sym): - # localError(n.info, errInstantiateXExplicitely, s.name.s) + # localError(n.info, errInstantiateXExplicitly, s.name.s) of nkSym: # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! @@ -2113,7 +2135,8 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkCurly: result = semSetConstr(c, n) of nkBracket: result = semArrayConstr(c, n, flags) of nkObjConstr: result = semObjConstr(c, n, flags) - of nkLambdaKinds: result = semLambda(c, n, flags) + of nkLambda: result = semLambda(c, n, flags) + of nkDo: result = semDo(c, n, flags) of nkDerefExpr: result = semDeref(c, n) of nkAddr: result = n diff --git a/compiler/semfields.nim b/compiler/semfields.nim index 823bef225..e086e73f8 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -19,12 +19,13 @@ type proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = case n.kind - of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n - of nkIdent: + of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n + of nkIdent, nkSym: result = n + let ident = considerQuotedIdent(n) var L = sonsLen(forLoop) if c.replaceByFieldName: - if n.ident.id == forLoop[0].ident.id: + if ident.id == considerQuotedIdent(forLoop[0]).id: let fieldName = if c.tupleType.isNil: c.field.name.s elif c.tupleType.n.isNil: "Field" & $c.tupleIndex else: c.tupleType.n.sons[c.tupleIndex].sym.name.s @@ -32,7 +33,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = return # other fields: for i in ord(c.replaceByFieldName)..L-3: - if n.ident.id == forLoop[i].ident.id: + if ident.id == considerQuotedIdent(forLoop[i]).id: var call = forLoop.sons[L-2] var tupl = call.sons[i+1-ord(c.replaceByFieldName)] if c.field.isNil: @@ -155,7 +156,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = dec(c.p.nestedLoopCounter) # for TR macros this 'while true: ...; break' loop is pretty bad, so # we avoid it now if we can: - if hasSonWith(stmts, nkBreakStmt): + if containsNode(stmts, {nkBreakStmt}): var b = newNodeI(nkBreakStmt, n.info) b.add(ast.emptyNode) stmts.add(b) diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 1988c512e..a3f1b1c13 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -665,8 +665,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode = of mLow: result = newIntNodeT(firstOrd(n.sons[1].typ), n) of mHigh: - if skipTypes(n.sons[1].typ, abstractVar).kind notin - {tyOpenArray, tyVarargs, tySequence, tyString}: + if skipTypes(n.sons[1].typ, abstractVar).kind notin + {tySequence, tyString, tyCString, tyOpenArray, tyVarargs}: result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n) else: var a = getArrayConstr(m, n.sons[1]) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 13941fa58..2601f05ac 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -243,7 +243,7 @@ proc semGenericStmt(c: PContext, n: PNode, elif fn.kind == nkDotExpr: result.sons[0] = fuzzyLookup(c, fn, flags, ctx, mixinContext) first = 1 - # Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)' + # Consider 'when declared(globalsSlot): ThreadVarSetValue(globalsSlot, ...)' # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which # is not exported and yet the generic 'threadProcWrapper' works correctly. let flags = if mixinContext: flags+{withinMixin} else: flags diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 81a4465c5..a10f27519 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -36,7 +36,7 @@ proc instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable, elif t.kind == tyGenericParam: localError(a.info, errCannotInstantiateX, q.name.s) t = errorType(c) - elif t.kind == tyGenericInvokation: + elif t.kind == tyGenericInvocation: #t = instGenericContainer(c, a, t) t = generateTypeInstance(c, pt, a, t) #t = ReplaceTypeVarsT(cl, t) @@ -77,11 +77,12 @@ proc removeDefaultParamValues(n: PNode) = proc freshGenSyms(n: PNode, owner: PSym, symMap: var TIdTable) = # we need to create a fresh set of gensym'ed symbols: if n.kind == nkSym and sfGenSym in n.sym.flags: - var x = PSym(idTableGet(symMap, n.sym)) + let s = n.sym + var x = PSym(idTableGet(symMap, s)) if x == nil: - x = copySym(n.sym, false) + x = copySym(s, false) x.owner = owner - idTablePut(symMap, n.sym, x) + idTablePut(symMap, s, x) n.sym = x else: for i in 0 .. <safeLen(n): freshGenSyms(n.sons[i], owner, symMap) @@ -99,13 +100,18 @@ proc addProcDecls(c: PContext, fn: PSym) = maybeAddResult(c, fn, fn.ast) -proc instantiateBody(c: PContext, n: PNode, result: PSym) = +proc instantiateBody(c: PContext, n, params: PNode, result: PSym) = if n.sons[bodyPos].kind != nkEmpty: inc c.inGenericInst # add it here, so that recursive generic procs are possible: var b = n.sons[bodyPos] var symMap: TIdTable initIdTable symMap + if params != nil: + for i in 1 .. <params.len: + let param = params[i].sym + if sfGenSym in param.flags: + idTablePut(symMap, params[i].sym, result.typ.n[param.position+1].sym) freshGenSyms(b, result, symMap) b = semProcBody(c, b) b = hloBody(c, b) @@ -122,7 +128,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) = openScope(c) var n = oldPrc.ast n.sons[bodyPos] = copyTree(s.getBody) - instantiateBody(c, n, oldPrc) + instantiateBody(c, n, nil, oldPrc) closeScope(c) popInfoContext() @@ -169,17 +175,27 @@ proc instantiateProcType(c: PContext, pt: TIdTable, result.n = originalParams.shallowCopy for i in 1 .. <result.len: + # twrong_field_caching requires these 'resetIdTable' calls: + if i > 1: resetIdTable(cl.symMap) result.sons[i] = replaceTypeVarsT(cl, result.sons[i]) propagateToOwner(result, result.sons[i]) - let param = replaceTypeVarsN(cl, originalParams[i]) - result.n.sons[i] = param - if param.kind == nkSym: - # XXX: this won't be true for void params - # implement pass-through of void params and - # the "sort by distance to point" container + internalAssert originalParams[i].kind == nkSym + when true: + let oldParam = originalParams[i].sym + let param = copySym(oldParam) + param.owner = prc + param.typ = result.sons[i] + param.ast = oldParam.ast.copyTree + # don't be lazy here and call replaceTypeVarsN(cl, originalParams[i])! + result.n.sons[i] = newSymNode(param) + addDecl(c, param) + else: + let param = replaceTypeVarsN(cl, originalParams[i]) + result.n.sons[i] = param param.sym.owner = prc - addDecl(c, param.sym) - + addDecl(c, result.n.sons[i].sym) + + resetIdTable(cl.symMap) result.sons[0] = replaceTypeVarsT(cl, result.sons[0]) result.n.sons[0] = originalParams[0].copyTree @@ -234,7 +250,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, pragma(c, result, n.sons[pragmasPos], allRoutinePragmas) if isNil(n.sons[bodyPos]): n.sons[bodyPos] = copyTree(fn.getBody) - instantiateBody(c, n, result) + instantiateBody(c, n, fn.typ.n, result) sideEffectsCheck(c, result) paramsTypeCheck(c, result.typ) else: diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index dcebf86ac..60153e052 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -23,7 +23,7 @@ import # Predefined effects: # io, time (time dependent), gc (performs GC'ed allocation), exceptions, # side effect (accesses global), store (stores into *type*), -# store_unkown (performs some store) --> store(any)|store(x) +# store_unknown (performs some store) --> store(any)|store(x) # load (loads from *type*), recursive (recursive call), unsafe, # endless (has endless loops), --> user effects are defined over *patterns* # --> a TR macro can annotate the proc with user defined annotations @@ -194,6 +194,9 @@ proc warnAboutGcUnsafe(n: PNode) = #assert false message(n.info, warnGcUnsafe, renderTree(n)) +template markGcUnsafe(a: PEffects) = + a.gcUnsafe = true + proc useVar(a: PEffects, n: PNode) = let s = n.sym if isLocalVar(a, s): @@ -209,7 +212,7 @@ proc useVar(a: PEffects, n: PNode) = if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and tfGcSafe notin s.typ.flags: if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) - a.gcUnsafe = true + markGcUnsafe(a) type TIntersection = seq[tuple[id, count: int]] # a simple count table @@ -230,7 +233,7 @@ proc getEbase(): PType = proc excType(n: PNode): PType = # reraise is like raising E_Base: - let t = if n.kind == nkEmpty: getEbase() else: n.typ + let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ result = skipTypes(t, skipPtrs) proc createRaise(n: PNode): PNode = @@ -448,7 +451,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = if notGcSafe(s.typ) and sfImportc notin s.flags: if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) - tracked.gcUnsafe = true + markGcUnsafe(tracked) mergeLockLevels(tracked, n, s.getLockLevel) proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = @@ -502,13 +505,13 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = # assume GcUnsafe unless in its type; 'forward' does not matter: if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner): if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) - tracked.gcUnsafe = true + markGcUnsafe(tracked) else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) if notGcSafe(op): if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n) - tracked.gcUnsafe = true + markGcUnsafe(tracked) notNilCheck(tracked, n, paramType) proc breaksBlock(n: PNode): bool = @@ -656,7 +659,7 @@ proc track(tracked: PEffects, n: PNode) = # and it's not a recursive call: if not (a.kind == nkSym and a.sym == tracked.owner): warnAboutGcUnsafe(n) - tracked.gcUnsafe = true + markGcUnsafe(tracked) for i in 1 .. <len(n): trackOperand(tracked, n.sons[i], paramType(op, i)) if a.kind == nkSym and a.sym.magic in {mNew, mNewFinalize, mNewSeq}: # may not look like an assignment, but it is: @@ -825,7 +828,7 @@ proc trackProc*(s: PSym, body: PNode) = # effects already computed? if sfForward in s.flags: return if effects.len == effectListLen: return - + var t: TEffects initEffects(effects, s, t) track(t, body) @@ -849,19 +852,20 @@ proc trackProc*(s: PSym, body: PNode) = # after the check, use the formal spec: effects.sons[tagEffects] = tagsSpec - if optThreadAnalysis in gGlobalOptions: - if sfThread in s.flags and t.gcUnsafe: - if optThreads in gGlobalOptions: - localError(s.info, "'$1' is not GC-safe" % s.name.s) - else: - localError(s.info, warnGcUnsafe2, s.name.s) - if not t.gcUnsafe: s.typ.flags.incl tfGcSafe - if s.typ.lockLevel == UnspecifiedLockLevel: - s.typ.lockLevel = t.maxLockLevel - elif t.maxLockLevel > s.typ.lockLevel: - localError(s.info, - "declared lock level is $1, but real lock level is $2" % - [$s.typ.lockLevel, $t.maxLockLevel]) + if sfThread in s.flags and t.gcUnsafe: + if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions: + localError(s.info, "'$1' is not GC-safe" % s.name.s) + else: + localError(s.info, warnGcUnsafe2, s.name.s) + if not t.gcUnsafe: + s.typ.flags.incl tfGcSafe + if s.typ.lockLevel == UnspecifiedLockLevel: + s.typ.lockLevel = t.maxLockLevel + elif t.maxLockLevel > s.typ.lockLevel: + #localError(s.info, + message(s.info, warnLockLevel, + "declared lock level is $1, but real lock level is $2" % + [$s.typ.lockLevel, $t.maxLockLevel]) proc trackTopLevelStmt*(module: PSym; n: PNode) = if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index e50a80bcf..4a2e107d7 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -359,13 +359,17 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var def: PNode if a.sons[length-1].kind != nkEmpty: def = semExprWithType(c, a.sons[length-1], {efAllowDestructor}) + if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro: + # prevent the all too common 'var x = int' bug: + localError(def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?") + def.typ = errorType(c) if typ != nil: if typ.isMetaType: def = inferWithMetatype(c, typ, def) typ = def.typ else: # BUGFIX: ``fitNode`` is needed here! - # check type compability between def.typ and typ + # check type compatibility between def.typ and typ def = fitNode(c, typ, def) #changeType(def.skipConv, typ, check=true) else: @@ -666,8 +670,8 @@ proc checkForMetaFields(n: PNode) = let t = n.sym.typ case t.kind of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef, - tyProc, tyGenericInvokation, tyGenericInst: - let start = ord(t.kind in {tyGenericInvokation, tyGenericInst}) + tyProc, tyGenericInvocation, tyGenericInst: + let start = ord(t.kind in {tyGenericInvocation, tyGenericInst}) for i in start .. <t.sons.len: checkMeta(t.sons[i]) else: @@ -756,7 +760,8 @@ proc lookupMacro(c: PContext, n: PNode): PSym = else: result = searchInScopes(c, considerQuotedIdent(n), {skMacro, skTemplate}) -proc semProcAnnotation(c: PContext, prc: PNode): PNode = +proc semProcAnnotation(c: PContext, prc: PNode; + validPragmas: TSpecialWords): PNode = var n = prc.sons[pragmasPos] if n == nil or n.kind == nkEmpty: return for i in countup(0, <n.len): @@ -781,12 +786,18 @@ proc semProcAnnotation(c: PContext, prc: PNode): PNode = x.add(it.sons[1]) x.add(prc) # recursion assures that this works for multiple macro annotations too: - return semStmt(c, x) + result = semStmt(c, x) + # since a proc annotation can set pragmas, we process these here again. + # This is required for SqueakNim-like export pragmas. + if result.kind in procDefs and result[namePos].kind == nkSym and + result[pragmasPos].kind != nkEmpty: + pragma(c, result[namePos].sym, result[pragmasPos], validPragmas) + return proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = # XXX semProcAux should be good enough for this now, we will eventually # remove semLambda - result = semProcAnnotation(c, n) + result = semProcAnnotation(c, n, lambdaPragmas) if result != nil: return result result = n checkSonsLen(n, bodyPos + 1) @@ -816,8 +827,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = # we have a list of implicit type parameters: n.sons[genericParamsPos] = gp else: - s.typ = newTypeS(tyProc, c) - rawAddSon(s.typ, nil) + s.typ = newProcType(c, n.info) if n.sons[pragmasPos].kind != nkEmpty: pragma(c, s, n.sons[pragmasPos], lambdaPragmas) s.options = gOptions @@ -829,9 +839,9 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags): pushProcCon(c, s) addResult(c, s.typ.sons[0], n.info, skProc) + addResultNode(c, n) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) n.sons[bodyPos] = transformBody(c.module, semBody, s) - addResultNode(c, n) popProcCon(c) elif efOperand notin flags: localError(n.info, errGenericLambdaNotAllowed) @@ -842,6 +852,13 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = popOwner() result.typ = s.typ +proc semDo(c: PContext, n: PNode, flags: TExprFlags): PNode = + # 'do' without params produces a stmt: + if n[genericParamsPos].kind == nkEmpty and n[paramsPos].kind == nkEmpty: + result = semStmt(c, n[bodyPos]) + else: + result = semLambda(c, n, flags) + proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = var n = n @@ -857,9 +874,9 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = addParams(c, n.typ.n, skProc) pushProcCon(c, s) addResult(c, n.typ.sons[0], n.info, skProc) + addResultNode(c, n) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) n.sons[bodyPos] = transformBody(c.module, semBody, n.sons[namePos].sym) - addResultNode(c, n) popProcCon(c) popOwner() closeScope(c) @@ -905,7 +922,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = var t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst) while true: if t.kind == tyGenericBody: t = t.lastSon - elif t.kind == tyGenericInvokation: t = t.sons[0] + elif t.kind == tyGenericInvocation: t = t.sons[0] else: break if t.kind in {tyObject, tyDistinct, tyEnum}: if t.deepCopy.isNil: t.deepCopy = s @@ -936,7 +953,7 @@ proc isForwardDecl(s: PSym): bool = proc semProcAux(c: PContext, n: PNode, kind: TSymKind, validPragmas: TSpecialWords, phase = stepRegisterSymbol): PNode = - result = semProcAnnotation(c, n) + result = semProcAnnotation(c, n, validPragmas) if result != nil: return result result = n checkSonsLen(n, bodyPos + 1) @@ -991,8 +1008,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # check for semantics again: # semParamList(c, n.sons[ParamsPos], nil, s) else: - s.typ = newTypeS(tyProc, c) - rawAddSon(s.typ, nil) + s.typ = newProcType(c, n.info) if n.sons[patternPos].kind != nkEmpty: n.sons[patternPos] = semPattern(c, n.sons[patternPos]) if s.kind in skIterators: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 3477d3d6f..a48f045a2 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -436,7 +436,7 @@ proc semTemplBodyDirty(c: var TemplCtx, n: PNode): PNode = of nkEmpty, nkSym..nkNilLit: discard else: - # dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam', + # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam', # so we use the generic code for nkDotExpr too if n.kind == nkDotExpr or n.kind == nkAccQuoted: let s = qualifiedLookUp(c.c, n, {}) @@ -494,7 +494,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = semParamList(c, n.sons[paramsPos], gp, s) # a template's parameters are not gensym'ed even if that was originally the # case as we determine whether it's a template parameter in the template - # body by the absense of the skGenSym flag: + # body by the absence of the sfGenSym flag: for i in 1 .. s.typ.n.len-1: s.typ.n.sons[i].sym.flags.excl sfGenSym if sonsLen(gp) > 0: @@ -640,7 +640,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = for i in countup(0, sonsLen(n) - 1): result.sons[i] = semPatternBody(c, n.sons[i]) else: - # dotExpr is ambiguous: note that we explicitely allow 'x.TemplateParam', + # dotExpr is ambiguous: note that we explicitly allow 'x.TemplateParam', # so we use the generic code for nkDotExpr too case n.kind of nkDotExpr, nkAccQuoted: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 8d1655593..0735b76ce 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -10,14 +10,14 @@ # this module does the semantic checking of type declarations # included from sem.nim -proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = - if prev == nil: +proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType = + if prev == nil: result = newTypeS(kind, c) - else: + else: result = prev if result.kind == tyForward: result.kind = kind -proc newConstraint(c: PContext, k: TTypeKind): PType = +proc newConstraint(c: PContext, k: TTypeKind): PType = result = newTypeS(tyBuiltInTypeClass, c) result.addSonSkipIntLit(newTypeS(k, c)) @@ -32,22 +32,22 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyEnum, prev, c) result.n = newNodeI(nkEnumTy, n.info) checkMinSonsLen(n, 1) - if n.sons[0].kind != nkEmpty: + if n.sons[0].kind != nkEmpty: base = semTypeNode(c, n.sons[0].sons[0], nil) - if base.kind != tyEnum: + if base.kind != tyEnum: localError(n.sons[0].info, errInheritanceOnlyWithEnums) counter = lastOrd(base) + 1 rawAddSon(result, base) let isPure = result.sym != nil and sfPure in result.sym.flags var hasNull = false - for i in countup(1, sonsLen(n) - 1): + for i in countup(1, sonsLen(n) - 1): case n.sons[i].kind - of nkEnumFieldDef: + of nkEnumFieldDef: e = newSymS(skEnumField, n.sons[i].sons[0], c) var v = semConstExpr(c, n.sons[i].sons[1]) var strVal: PNode = nil - case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind - of tyTuple: + case skipTypes(v.typ, abstractInst-{tyTypeDesc}).kind + of tyTuple: if sonsLen(v) == 2: strVal = v.sons[1] # second tuple part is the string value if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}: @@ -63,14 +63,14 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = x = getOrdValue(v) if i != 1: if x != counter: incl(result.flags, tfEnumHasHoles) - if x < counter: + if x < counter: localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s) x = counter e.ast = strVal # might be nil counter = x - of nkSym: + of nkSym: e = n.sons[i].sym - of nkIdent, nkAccQuoted: + of nkIdent, nkAccQuoted: e = newSymS(skEnumField, n.sons[i], c) else: illFormedAst(n[i]) @@ -87,28 +87,28 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = inc(counter) if not hasNull: incl(result.flags, tfNeedsInit) -proc semSet(c: PContext, n: PNode, prev: PType): PType = +proc semSet(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tySet, prev, c) - if sonsLen(n) == 2: + if sonsLen(n) == 2: var base = semTypeNode(c, n.sons[1], nil) addSonSkipIntLit(result, base) if base.kind == tyGenericInst: base = lastSon(base) if base.kind != tyGenericParam: - if not isOrdinalType(base): + if not isOrdinalType(base): localError(n.info, errOrdinalTypeExpected) - elif lengthOrd(base) > MaxSetElements: + elif lengthOrd(base) > MaxSetElements: localError(n.info, errSetTooBig) else: localError(n.info, errXExpectsOneTypeParam, "set") addSonSkipIntLit(result, errorType(c)) - -proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, - prev: PType): PType = + +proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, + prev: PType): PType = result = newOrPrevType(kind, prev, c) - if sonsLen(n) == 2: + if sonsLen(n) == 2: var base = semTypeNode(c, n.sons[1], nil) addSonSkipIntLit(result, base) - else: + else: localError(n.info, errXExpectsOneTypeParam, kindStr) addSonSkipIntLit(result, errorType(c)) @@ -140,23 +140,23 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType = var base = semTypeNode(c, n.lastSon, nil) addSonSkipIntLit(result, base) -proc semVarType(c: PContext, n: PNode, prev: PType): PType = - if sonsLen(n) == 1: +proc semVarType(c: PContext, n: PNode, prev: PType): PType = + if sonsLen(n) == 1: result = newOrPrevType(tyVar, prev, c) var base = semTypeNode(c, n.sons[0], nil) - if base.kind == tyVar: + if base.kind == tyVar: localError(n.info, errVarVarTypeNotAllowed) base = base.sons[0] addSonSkipIntLit(result, base) else: result = newConstraint(c, tyVar) -proc semDistinct(c: PContext, n: PNode, prev: PType): PType = +proc semDistinct(c: PContext, n: PNode, prev: PType): PType = if n.len == 0: return newConstraint(c, tyDistinct) result = newOrPrevType(tyDistinct, prev, c) addSonSkipIntLit(result, semTypeNode(c, n.sons[0], nil)) if n.len > 1: result.n = n[1] - + proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = assert isRange(n) checkSonsLen(n, 3) @@ -164,11 +164,11 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = result.n = newNodeI(nkRange, n.info) if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty): localError(n.info, errRangeIsEmpty) - + var range: array[2, PNode] range[0] = semExprWithType(c, n[1], {efDetermineType}) range[1] = semExprWithType(c, n[2], {efDetermineType}) - + var rangeT: array[2, PType] for i in 0..1: rangeT[i] = range[i].typ.skipTypes({tyStatic}).skipIntLit @@ -179,13 +179,13 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType = localError(n.info, errOrdinalTypeExpected) elif enumHasHoles(rangeT[0]): localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s) - + for i in 0..1: if hasGenericArguments(range[i]): result.n.addSon makeStaticExpr(c, range[i]) else: result.n.addSon semConstExpr(c, range[i]) - + if weakLeValue(result.n[0], result.n[1]) == impNo: localError(n.info, errRangeIsEmpty) @@ -201,10 +201,10 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType = incl(result.flags, tfNeedsInit) elif n.sons[1].kind in {nkCharLit..nkUInt64Lit} and n.sons[1].intVal < 0: incl(result.flags, tfNeedsInit) - elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and + elif n.sons[0].kind in {nkFloatLit..nkFloat64Lit} and n.sons[0].floatVal > 0.0: incl(result.flags, tfNeedsInit) - elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and + elif n.sons[1].kind in {nkFloatLit..nkFloat64Lit} and n.sons[1].floatVal < 0.0: incl(result.flags, tfNeedsInit) else: @@ -243,13 +243,13 @@ proc semArrayIndex(c: PContext, n: PNode): PType = else: let x = semConstExpr(c, e) if x.kind in {nkIntLit..nkUInt64Lit}: - result = makeRangeType(c, 0, x.intVal-1, n.info, + result = makeRangeType(c, 0, x.intVal-1, n.info, x.typ.skipTypes({tyTypeDesc})) else: result = x.typ.skipTypes({tyTypeDesc}) #localError(n[1].info, errConstExprExpected) -proc semArray(c: PContext, n: PNode, prev: PType): PType = +proc semArray(c: PContext, n: PNode, prev: PType): PType = var base: PType result = newOrPrevType(tyArray, prev, c) if sonsLen(n) == 3: @@ -260,20 +260,20 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType = if indx.kind notin {tyGenericParam, tyStatic, tyFromExpr}: if not isOrdinalType(indx): localError(n.sons[1].info, errOrdinalTypeExpected) - elif enumHasHoles(indx): + elif enumHasHoles(indx): localError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s) base = semTypeNode(c, n.sons[2], nil) addSonSkipIntLit(result, base) - else: + else: localError(n.info, errArrayExpectsTwoTypeParams) result = newOrPrevType(tyError, prev, c) - -proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = + +proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyOrdinal, prev, c) - if sonsLen(n) == 2: + if sonsLen(n) == 2: var base = semTypeNode(c, n.sons[1], nil) - if base.kind != tyGenericParam: - if not isOrdinalType(base): + if base.kind != tyGenericParam: + if not isOrdinalType(base): localError(n.sons[1].info, errOrdinalTypeExpected) addSonSkipIntLit(result, base) else: @@ -281,7 +281,7 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyError, prev, c) proc semTypeIdent(c: PContext, n: PNode): PSym = - if n.kind == nkSym: + if n.kind == nkSym: result = n.sym else: when defined(nimfix): @@ -307,7 +307,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = result = result.typ.sym.copySym result.typ = copyType(result.typ, result.typ.owner, true) result.typ.flags.incl tfUnresolved - + if result.kind == skGenericParam: if result.typ.kind == tyGenericParam and result.typ.len == 0 and tfWildcard in result.typ.flags: @@ -319,7 +319,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = localError(n.info, errTypeExpected) return errorSym(c, n) - if result.kind != skType: + if result.kind != skType: # this implements the wanted ``var v: V, x: V`` feature ... var ov: TOverloadIter var amb = initOverloadIter(ov, c, n) @@ -332,55 +332,60 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = if result.typ.kind != tyGenericParam: # XXX get rid of this hack! var oldInfo = n.info + when defined(useNodeIds): + let oldId = n.id reset(n[]) + when defined(useNodeIds): + n.id = oldId n.kind = nkSym n.sym = result n.info = oldInfo + n.typ = result.typ else: localError(n.info, errIdentifierExpected) result = errorSym(c, n) - -proc semTuple(c: PContext, n: PNode, prev: PType): PType = + +proc semTuple(c: PContext, n: PNode, prev: PType): PType = if n.sonsLen == 0: return newConstraint(c, tyTuple) var typ: PType result = newOrPrevType(tyTuple, prev, c) result.n = newNodeI(nkRecList, n.info) var check = initIntSet() var counter = 0 - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if (a.kind != nkIdentDefs): illFormedAst(a) checkMinSonsLen(a, 3) var length = sonsLen(a) - if a.sons[length - 2].kind != nkEmpty: + if a.sons[length - 2].kind != nkEmpty: typ = semTypeNode(c, a.sons[length - 2], nil) else: localError(a.info, errTypeExpected) typ = errorType(c) - if a.sons[length - 1].kind != nkEmpty: + if a.sons[length - 1].kind != nkEmpty: localError(a.sons[length - 1].info, errInitHereNotAllowed) - for j in countup(0, length - 3): + for j in countup(0, length - 3): var field = newSymG(skField, a.sons[j], c) field.typ = typ field.position = counter inc(counter) - if containsOrIncl(check, field.name.id): + if containsOrIncl(check, field.name.id): localError(a.sons[j].info, errAttemptToRedefine, field.name.s) else: addSon(result.n, newSymNode(field)) addSonSkipIntLit(result, typ) if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field) -proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, - allowed: TSymFlags): PSym = +proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, + allowed: TSymFlags): PSym = # identifier with visibility - if n.kind == nkPostfix: - if sonsLen(n) == 2 and n.sons[0].kind == nkIdent: + if n.kind == nkPostfix: + if sonsLen(n) == 2 and n.sons[0].kind == nkIdent: # for gensym'ed identifiers the identifier may already have been # transformed to a symbol and we need to use that here: result = newSymG(kind, n.sons[1], c) var v = n.sons[0].ident - if sfExported in allowed and v.id == ord(wStar): + if sfExported in allowed and v.id == ord(wStar): incl(result.flags, sfExported) else: localError(n.sons[0].info, errInvalidVisibilityX, v.s) @@ -388,7 +393,7 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, illFormedAst(n) else: result = newSymG(kind, n, c) - + proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym = if n.kind == nkPragmaExpr: @@ -410,31 +415,31 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) = let ex = t[branchIndex][currentEx].skipConv for i in countup(1, branchIndex): - for j in countup(0, sonsLen(t.sons[i]) - 2): + for j in countup(0, sonsLen(t.sons[i]) - 2): if i == branchIndex and j == currentEx: break if overlap(t.sons[i].sons[j].skipConv, ex): localError(ex.info, errDuplicateCaseLabel) - + proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode = checkMinSonsLen(t, 1) let ac = semConstExpr(c, a) let bc = semConstExpr(c, b) let at = fitNode(c, t.sons[0].typ, ac).skipConvTakeType let bt = fitNode(c, t.sons[0].typ, bc).skipConvTakeType - + result = newNodeI(nkRange, a.info) result.add(at) result.add(bt) if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty) else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1 -proc semCaseBranchRange(c: PContext, t, b: PNode, - covered: var BiggestInt): PNode = +proc semCaseBranchRange(c: PContext, t, b: PNode, + covered: var BiggestInt): PNode = checkSonsLen(b, 3) result = semBranchRange(c, t, b.sons[1], b.sons[2], covered) -proc semCaseBranchSetElem(c: PContext, t, b: PNode, - covered: var BiggestInt): PNode = +proc semCaseBranchSetElem(c: PContext, t, b: PNode, + covered: var BiggestInt): PNode = if isRange(b): checkSonsLen(b, 3) result = semBranchRange(c, t, b.sons[1], b.sons[2], covered) @@ -445,9 +450,10 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode, result = fitNode(c, t.sons[0].typ, b) inc(covered) -proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, - covered: var BiggestInt) = - for i in countup(0, sonsLen(branch) - 2): +proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, + covered: var BiggestInt) = + + for i in countup(0, sonsLen(branch) - 2): var b = branch.sons[i] if b.kind == nkRange: branch.sons[i] = b @@ -456,8 +462,11 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, else: # constant sets and arrays are allowed: var r = semConstExpr(c, b) - # for ``{}`` we want to trigger the type mismatch in ``fitNode``: - if r.kind notin {nkCurly, nkBracket} or len(r) == 0: + if r.kind in {nkCurly, nkBracket} and len(r) == 0 and sonsLen(branch)==2: + # discarding ``{}`` and ``[]`` branches silently + delSon(branch, 0) + return + elif r.kind notin {nkCurly, nkBracket} or len(r) == 0: checkMinSonsLen(t, 1) branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r)) inc(covered) @@ -471,7 +480,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, var L = branch.len swap(branch.sons[L-2], branch.sons[L-1]) checkForOverlap(c, t, i, branchIndex) - + proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, father: PNode, rectype: PType) proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, @@ -505,11 +514,11 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, else: illFormedAst(n) delSon(b, sonsLen(b) - 1) semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype) - if chckCovered and (covered != lengthOrd(a.sons[0].typ)): + if chckCovered and (covered != lengthOrd(a.sons[0].typ)): localError(a.info, errNotAllCasesCovered) addSon(father, a) -proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, +proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, father: PNode, rectype: PType) = if n == nil: return case n.kind @@ -547,12 +556,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, semRecordNodeAux(c, branch, check, pos, father, rectype) of nkRecCase: semRecordCase(c, n, check, pos, father, rectype) - of nkNilLit: + of nkNilLit: if father.kind != nkRecList: addSon(father, newNodeI(nkRecList, n.info)) of nkRecList: # attempt to keep the nesting at a sane level: var a = if father.kind == nkRecList: father else: copyNode(n) - for i in countup(0, sonsLen(n) - 1): + for i in countup(0, sonsLen(n) - 1): semRecordNodeAux(c, n.sons[i], check, pos, a, rectype) if a != father: addSon(father, a) of nkIdentDefs: @@ -561,10 +570,10 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, var a: PNode if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info) else: a = ast.emptyNode - if n.sons[length-1].kind != nkEmpty: + if n.sons[length-1].kind != nkEmpty: localError(n.sons[length-1].info, errInitHereNotAllowed) var typ: PType - if n.sons[length-2].kind == nkEmpty: + if n.sons[length-2].kind == nkEmpty: localError(n.info, errTypeExpected) typ = errorType(c) else: @@ -577,7 +586,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, f.typ = typ f.position = pos if (rec != nil) and ({sfImportc, sfExportc} * rec.flags != {}) and - (f.loc.r == nil): + (f.loc.r == nil): f.loc.r = toRope(f.name.s) f.flags = f.flags + ({sfImportc, sfExportc} * rec.flags) inc(pos) @@ -589,8 +598,8 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, if a.kind != nkEmpty: addSon(father, a) of nkEmpty: discard else: illFormedAst(n) - -proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int, + +proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int, n: PNode) = case n.kind of nkRecCase: @@ -609,31 +618,31 @@ proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int, inc(pos) else: internalError(n.info, "addInheritedFieldsAux()") -proc skipGenericInvokation(t: PType): PType {.inline.} = +proc skipGenericInvocation(t: PType): PType {.inline.} = result = t - if result.kind == tyGenericInvokation: + if result.kind == tyGenericInvocation: result = result.sons[0] if result.kind == tyGenericBody: result = lastSon(result) -proc addInheritedFields(c: PContext, check: var IntSet, pos: var int, +proc addInheritedFields(c: PContext, check: var IntSet, pos: var int, obj: PType) = assert obj.kind == tyObject - if (sonsLen(obj) > 0) and (obj.sons[0] != nil): - addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvokation) + if (sonsLen(obj) > 0) and (obj.sons[0] != nil): + addInheritedFields(c, check, pos, obj.sons[0].skipGenericInvocation) addInheritedFieldsAux(c, check, pos, obj.n) proc semObjectNode(c: PContext, n: PNode, prev: PType): PType = if n.sonsLen == 0: return newConstraint(c, tyObject) var check = initIntSet() - var pos = 0 + var pos = 0 var base: PType = nil # n.sons[0] contains the pragmas (if any). We process these later... checkSonsLen(n, 3) - if n.sons[1].kind != nkEmpty: + if n.sons[1].kind != nkEmpty: base = skipTypes(semTypeNode(c, n.sons[1].sons[0], nil), skipPtrs) - var concreteBase = skipGenericInvokation(base).skipTypes(skipPtrs) - if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: + var concreteBase = skipGenericInvocation(base).skipTypes(skipPtrs) + if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags: addInheritedFields(c, check, pos, concreteBase) else: if concreteBase.kind != tyError: @@ -672,8 +681,9 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = elif param.typ.kind == tyTypeDesc: addDecl(c, param) else: - # within a macro, every param has the type PNimrodNode! - let nn = getSysSym"PNimrodNode" + # within a macro, every param has the type NimNode! + let nn = if getCompilerProc("NimNode") != nil: getSysSym"NimNode" + else: getSysSym"PNimrodNode" var a = copySym(param) a.typ = nn.typ addDecl(c, a) @@ -713,7 +723,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, genericParams.addSon(newSymNode(s)) result = typeClass addDecl(c, s) - + # XXX: There are codegen errors if this is turned into a nested proc template liftingWalk(typ: PType, anonFlag = false): expr = liftParamType(c, procKind, genericParams, typ, paramName, info, anonFlag) @@ -732,7 +742,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, case paramType.kind: of tyAnything: result = addImplicitGeneric(newTypeS(tyGenericParam, c)) - + of tyStatic: # proc(a: expr{string}, b: expr{nkLambda}) # overload on compile time values and AST trees @@ -743,7 +753,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, localError(info, errMacroBodyDependsOnGenericTypes, paramName) result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base])) result.flags.incl({tfHasStatic, tfUnresolved}) - + of tyTypeDesc: if tfUnresolved notin paramType.flags: # naked typedescs are not bindOnce types @@ -751,12 +761,12 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, paramTypId.id == typedescId.id: paramTypId = nil result = addImplicitGeneric( c.newTypeWithSons(tyTypeDesc, @[paramType.base])) - + of tyDistinct: if paramType.sonsLen == 1: # disable the bindOnce behavior for the type class result = liftingWalk(paramType.sons[0], true) - + of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyPtr, tyRef, tyProc: # XXX: this is a bit strange, but proc(s: seq) @@ -775,21 +785,22 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, if lifted != nil: paramType.sons[i] = lifted result = paramType - + of tyGenericBody: - result = newTypeS(tyGenericInvokation, c) + result = newTypeS(tyGenericInvocation, c) result.rawAddSon(paramType) - + for i in 0 .. paramType.sonsLen - 2: - let dummyType = if paramType.sons[i].kind == tyStatic: tyUnknown - else: tyAnything - result.rawAddSon newTypeS(dummyType, c) - + if paramType.sons[i].kind == tyStatic: + result.rawAddSon makeTypeFromExpr(c, ast.emptyNode) # aka 'tyUnknown' + else: + result.rawAddSon newTypeS(tyAnything, c) + if paramType.lastSon.kind == tyUserTypeClass: result.kind = tyUserTypeClassInst result.rawAddSon paramType.lastSon return addImplicitGeneric(result) - + result = instGenericContainer(c, paramType.sym.info, result, allowMetaTypes = true) result = newTypeWithSons(c, tyCompositeTypeClass, @[paramType, result]) @@ -821,8 +832,8 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, if liftBody != nil: result = liftBody result.shouldHaveMeta - - of tyGenericInvokation: + + of tyGenericInvocation: for i in 1 .. <paramType.sonsLen: let lifted = liftingWalk(paramType.sons[i]) if lifted != nil: paramType.sons[i] = lifted @@ -833,18 +844,18 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true)) - + of tyExpr: if procKind notin {skMacro, skTemplate}: result = addImplicitGeneric(newTypeS(tyAnything, c)) - + of tyGenericParam: markUsed(info, paramType.sym) styleCheckUse(info, paramType.sym) if tfWildcard in paramType.flags: paramType.flags.excl tfWildcard paramType.sym.kind = skType - + else: discard # result = liftingWalk(paramType) @@ -856,25 +867,25 @@ proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType = else: result = semTypeNode(c, n, nil) +proc newProcType(c: PContext; info: TLineInfo; prev: PType = nil): PType = + result = newOrPrevType(tyProc, prev, c) + result.callConv = lastOptionEntry(c).defaultCC + result.n = newNodeI(nkFormalParams, info) + rawAddSon(result, nil) # return type + # result.n[0] used to be `nkType`, but now it's `nkEffectList` because + # the effects are now stored in there too ... this is a bit hacky, but as + # usual we desperately try to save memory: + addSon(result.n, newNodeI(nkEffectList, info)) + proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType, kind: TSymKind; isType=false): PType = # for historical reasons (code grows) this is invoked for parameter # lists too and then 'isType' is false. - var - res: PNode - cl: IntSet + var cl: IntSet checkMinSonsLen(n, 1) - result = newOrPrevType(tyProc, prev, c) - result.callConv = lastOptionEntry(c).defaultCC - result.n = newNodeI(nkFormalParams, n.info) + result = newProcType(c, n.info, prev) if genericParams != nil and sonsLen(genericParams) == 0: cl = initIntSet() - rawAddSon(result, nil) # return type - # result.n[0] used to be `nkType`, but now it's `nkEffectList` because - # the effects are now stored in there too ... this is a bit hacky, but as - # usual we desperately try to save memory: - res = newNodeI(nkEffectList, n.info) - addSon(result.n, res) var check = initIntSet() var counter = 0 for i in countup(1, n.len - 1): @@ -898,8 +909,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, typ = semParamType(c, a.sons[length-2], constraint) if hasDefault: - def = semExprWithType(c, a.sons[length-1]) - # check type compability between def.typ and typ: + def = semExprWithType(c, a.sons[length-1]) + # check type compatibility between def.typ and typ: if typ == nil: typ = def.typ elif def != nil: @@ -911,10 +922,12 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, if not hasType and not hasDefault: if isType: localError(a.info, "':' expected") let tdef = if kind in {skTemplate, skMacro}: tyExpr else: tyAnything + if tdef == tyAnything: + message(a.info, warnTypelessParam, renderTree(n)) typ = newTypeS(tdef, c) if skipTypes(typ, {tyGenericInst}).kind == tyEmpty: continue - for j in countup(0, length-3): + for j in countup(0, length-3): var arg = newSymG(skParam, a.sons[j], c) let lifted = liftParamType(c, kind, genericParams, typ, arg.name.s, arg.info) @@ -924,7 +937,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, arg.constraint = constraint inc(counter) if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def) - if containsOrIncl(check, arg.name.id): + if containsOrIncl(check, arg.name.id): localError(a.sons[j].info, errAttemptToRedefine, arg.name.s) addSon(result.n, newSymNode(arg)) rawAddSon(result, finalType) @@ -937,9 +950,9 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, elif kind == skIterator: # XXX This is special magic we should likely get rid of r = newTypeS(tyExpr, c) - + if r != nil: - # turn explicit 'void' return type into 'nil' because the rest of the + # turn explicit 'void' return type into 'nil' because the rest of the # compiler only checks for 'nil': if skipTypes(r, {tyGenericInst}).kind != tyEmpty: # 'auto' as a return type does not imply a generic: @@ -956,7 +969,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, # we don't need to change the return type to iter[T] if not r.isInlineIterator: r = newTypeWithSons(c, tyIter, @[r]) result.sons[0] = r - res.typ = r + result.n.typ = r if genericParams != nil: for n in genericParams: @@ -975,8 +988,8 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType = n.sons[length - 1].typ = result else: result = nil - -proc semBlockType(c: PContext, n: PNode, prev: PType): PType = + +proc semBlockType(c: PContext, n: PNode, prev: PType): PType = inc(c.p.nestedBlockCounter) checkSonsLen(n, 2) openScope(c) @@ -988,7 +1001,7 @@ proc semBlockType(c: PContext, n: PNode, prev: PType): PType = closeScope(c) dec(c.p.nestedBlockCounter) -proc semGenericParamInInvokation(c: PContext, n: PNode): PType = +proc semGenericParamInInvocation(c: PContext, n: PNode): PType = result = semTypeNode(c, n, nil) proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = @@ -996,12 +1009,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = localError(n.info, "cannot instantiate the '$1' $2" % [s.name.s, ($s.kind).substr(2).toLower]) return newOrPrevType(tyError, prev, c) - + var t = s.typ if t.kind == tyCompositeTypeClass and t.base.kind == tyGenericBody: t = t.base - result = newOrPrevType(tyGenericInvokation, prev, c) + result = newOrPrevType(tyGenericInvocation, prev, c) addSonSkipIntLit(result, t) template addToResult(typ) = @@ -1012,7 +1025,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = if t.kind == tyForward: for i in countup(1, sonsLen(n)-1): - var elem = semGenericParamInInvokation(c, n.sons[i]) + var elem = semGenericParamInInvocation(c, n.sons[i]) addToResult(elem) return elif t.kind != tyGenericBody: @@ -1023,7 +1036,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = else: var m = newCandidate(c, t) matches(c, n, copyTree(n), m) - + if m.state != csMatch: var err = "cannot instantiate " & typeToString(t) & "\n" & "got: (" & describeArgs(c, n) & ")\n" & @@ -1032,12 +1045,12 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType = return newOrPrevType(tyError, prev, c) var isConcrete = true - + for i in 1 .. <m.call.len: let typ = m.call[i].typ.skipTypes({tyTypeDesc}) if containsGenericType(typ): isConcrete = false addToResult(typ) - + if isConcrete: if s.ast == nil and s.typ.kind != tyCompositeTypeClass: # XXX: What kind of error is this? is it still relevant? @@ -1068,7 +1081,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType = let pragmas = n[1] inherited = n[2] - + if inherited.kind != nkEmpty: for n in inherited.sons: let typ = semTypeNode(c, n, nil) @@ -1101,7 +1114,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = checkSonsLen(n, 1) let typExpr = semExprWithType(c, n.sons[0], {efInTypeof}) result = typExpr.typ.skipTypes({tyIter}) - of nkPar: + of nkPar: if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev) else: # XXX support anon tuple here @@ -1132,7 +1145,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = case n.len of 3: result = semTypeNode(c, n.sons[1], prev) - if result.kind in NilableTypes and n.sons[2].kind == nkNilLit: + if result.skipTypes({tyGenericInst}).kind in NilableTypes+GenericTypes and + n.sons[2].kind == nkNilLit: result = freshType(result, prev) result.flags.incl(tfNotNil) else: @@ -1175,14 +1189,15 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = var typeExpr = semExpr(c, n) if typeExpr.typ.kind != tyTypeDesc: localError(n.info, errTypeExpected) - return errorType(c) - result = typeExpr.typ.base - if result.isMetaType: - var preprocessed = semGenericStmt(c, n) - return makeTypeFromExpr(c, preprocessed) + result = errorType(c) + else: + result = typeExpr.typ.base + if result.isMetaType: + var preprocessed = semGenericStmt(c, n) + result = makeTypeFromExpr(c, preprocessed.copyTree) of nkIdent, nkAccQuoted: var s = semTypeIdent(c, n) - if s.typ == nil: + if s.typ == nil: if s.kind != skError: localError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) elif s.kind == skParam and s.typ.kind == tyTypeDesc: @@ -1190,19 +1205,19 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = result = s.typ.base elif prev == nil: result = s.typ - else: + else: assignType(prev, s.typ) # bugfix: keep the fresh id for aliases to integral types: if s.typ.kind notin {tyBool, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, - tyUInt..tyUInt64}: + tyUInt..tyUInt64}: prev.id = s.typ.id result = prev of nkSym: if n.sym.kind == skType and n.sym.typ != nil: var t = n.sym.typ - if prev == nil: + if prev == nil: result = t - else: + else: assignType(prev, t) result = prev markUsed(n.info, n.sym) @@ -1250,13 +1265,14 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = else: localError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) - -proc setMagicType(m: PSym, kind: TTypeKind, size: int) = + n.typ = result + +proc setMagicType(m: PSym, kind: TTypeKind, size: int) = m.typ.kind = kind m.typ.align = size.int16 m.typ.size = size - -proc processMagicType(c: PContext, m: PSym) = + +proc processMagicType(c: PContext, m: PSym) = case m.magic of mInt: setMagicType(m, tyInt, intSize) of mInt8: setMagicType(m, tyInt8, 1) @@ -1274,21 +1290,21 @@ proc processMagicType(c: PContext, m: PSym) = of mFloat128: setMagicType(m, tyFloat128, 16) of mBool: setMagicType(m, tyBool, 1) of mChar: setMagicType(m, tyChar, 1) - of mString: + of mString: setMagicType(m, tyString, ptrSize) rawAddSon(m.typ, getSysType(tyChar)) - of mCstring: + of mCstring: setMagicType(m, tyCString, ptrSize) rawAddSon(m.typ, getSysType(tyChar)) of mPointer: setMagicType(m, tyPointer, ptrSize) - of mEmptySet: + of mEmptySet: setMagicType(m, tySet, 1) rawAddSon(m.typ, newTypeS(tyEmpty, c)) of mIntSetBaseType: setMagicType(m, tyRange, intSize) of mNil: setMagicType(m, tyNil, ptrSize) of mExpr: setMagicType(m, tyExpr, 0) of mStmt: setMagicType(m, tyStmt, 0) - of mTypeDesc: + of mTypeDesc: setMagicType(m, tyTypeDesc, 0) rawAddSon(m.typ, newTypeS(tyNone, c)) of mVoidType: setMagicType(m, tyEmpty, 0) @@ -1302,8 +1318,8 @@ proc processMagicType(c: PContext, m: PSym) = setMagicType(m, tyRange, 0) rawAddSon(m.typ, newTypeS(tyNone, c)) of mSet: - setMagicType(m, tySet, 0) - of mSeq: + setMagicType(m, tySet, 0) + of mSeq: setMagicType(m, tySequence, 0) of mOrdinal: setMagicType(m, tyOrdinal, 0) @@ -1319,13 +1335,13 @@ proc processMagicType(c: PContext, m: PSym) = incl m.typ.flags, tfShared rawAddSon(m.typ, sysTypeFromName"shared") else: localError(m.info, errTypeExpected) - + proc semGenericConstraints(c: PContext, x: PType): PType = result = newTypeWithSons(c, tyGenericParam, @[x]) -proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = +proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = result = copyNode(n) - if n.kind != nkGenericParams: + if n.kind != nkGenericParams: illFormedAst(n) return for i in countup(0, sonsLen(n)-1): @@ -1335,7 +1351,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = var def = a{-1} let constraint = a{-2} var typ: PType - + if constraint.kind != nkEmpty: typ = semTypeNode(c, constraint, nil) if typ.kind != tyStatic or typ.len == 0: @@ -1344,7 +1360,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = typ = newTypeWithSons(c, tyTypeDesc, @[newTypeS(tyNone, c)]) else: typ = semGenericConstraints(c, typ) - + if def.kind != nkEmpty: def = semConstExpr(c, def) if typ == nil: @@ -1356,7 +1372,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = def.typ = def.typ.skipTypes({tyTypeDesc}) if not containsGenericType(def.typ): def = fitNode(c, typ, def) - + if typ == nil: typ = newTypeS(tyGenericParam, c) if father == nil: typ.flags.incl tfWildcard diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 7b8f478ec..57aa6305e 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -61,7 +61,7 @@ proc searchInstTypes*(key: PType): PType = if inst.sons.len < key.sons.len: # XXX: This happens for prematurely cached # types such as TChannel[empty]. Why? - # See the notes for PActor in handleGenericInvokation + # See the notes for PActor in handleGenericInvocation return block matchType: for j in 1 .. high(key.sons): @@ -223,7 +223,7 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = result = errorType(cl.c) # In order to prevent endless recursions, we must remember # this bad lookup and replace it with errorType everywhere. - # These code paths are only active in nimrod check + # These code paths are only active in "nim check" idTablePut(cl.typeMap, t, result) elif result.kind == tyGenericParam and not cl.allowMetaTypes: internalError(cl.info, "substitution with generic parameter") @@ -234,9 +234,9 @@ proc instCopyType*(cl: var TReplTypeVars, t: PType): PType = result.flags.incl tfFromGeneric result.flags.excl tfInstClearedFlags -proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = - # tyGenericInvokation[A, tyGenericInvokation[A, B]] - # is difficult to handle: +proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType = + # tyGenericInvocation[A, tyGenericInvocation[A, B]] + # is difficult to handle: var body = t.sons[0] if body.kind != tyGenericBody: internalError(cl.info, "no generic body") var header: PType = t @@ -245,7 +245,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = result = PType(idTableGet(cl.localCache, t)) else: result = searchInstTypes(t) - if result != nil: return + if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return for i in countup(1, sonsLen(t) - 1): var x = t.sons[i] if x.kind == tyGenericParam: @@ -260,10 +260,10 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = if header != t: # search again after first pass: result = searchInstTypes(header) - if result != nil: return + if result != nil and eqTypeFlags*result.flags == eqTypeFlags*t.flags: return else: header = instCopyType(cl, t) - + result = newType(tyGenericInst, t.sons[0].owner) result.flags = header.flags # be careful not to propagate unnecessary flags here (don't use rawAddSon) @@ -278,7 +278,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = for i in countup(1, sonsLen(t) - 1): var x = replaceTypeVarsT(cl, t.sons[i]) - assert x.kind != tyGenericInvokation + assert x.kind != tyGenericInvocation header.sons[i] = x propagateToOwner(header, x) idTablePut(cl.typeMap, body.sons[i-1], x) @@ -295,7 +295,7 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = #newbody.callConv = body.callConv # This type may be a generic alias and we want to resolve it here. # One step is enough, because the recursive nature of - # handleGenericInvokation will handle the alias-to-alias-to-alias case + # handleGenericInvocation will handle the alias-to-alias-to-alias case if newbody.isGenericAlias: newbody = newbody.skipGenericAlias rawAddSon(result, newbody) checkPartialConstructedType(cl.info, newbody) @@ -359,8 +359,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = if lookup != nil: return lookup case t.kind - of tyGenericInvokation: - result = handleGenericInvokation(cl, t) + of tyGenericInvocation: + result = handleGenericInvocation(cl, t) of tyGenericBody: localError(cl.info, errCannotInstantiateX, typeToString(t)) @@ -369,6 +369,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = of tyFromExpr: if cl.allowMetaTypes: return + assert t.n.typ != t var n = prepareNode(cl, t.n) n = cl.c.semConstExpr(cl.c, n) if n.typ.kind == tyTypeDesc: @@ -389,9 +390,8 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType = else: result = n.typ - of tyInt: + of tyInt, tyFloat: result = skipIntLit(t) - # XXX now there are also float literals of tyTypeDesc: let lookup = PType(idTableGet(cl.typeMap, t)) # lookupTypeVar(cl, t) diff --git a/compiler/service.nim b/compiler/service.nim index 1d51ef2a1..7cb9d7d29 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -33,7 +33,12 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string) = parseopt.next(p) case p.kind of cmdEnd: break - of cmdLongoption, cmdShortOption: processSwitch(pass, p) + of cmdLongoption, cmdShortOption: + if p.key == " ": + p.key = "-" + if processArgument(pass, p, argsCount): break + else: + processSwitch(pass, p) of cmdArgument: if processArgument(pass, p, argsCount): break if pass == passCmd2: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 2e37f3bf1..a1b5c8dc9 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -91,7 +91,7 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PType) = initIdTable(c.bindings) proc put(t: var TIdTable, key, val: PType) {.inline.} = - idTablePut(t, key, val) + idTablePut(t, key, val.skipIntLit) proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1) = @@ -153,12 +153,12 @@ proc sumGeneric(t: PType): int = of tyVar: # but do not make 'var T' more specific than 'T'! t = t.sons[0] - of tyGenericInvokation, tyTuple: - result = ord(t.kind == tyGenericInvokation) + of tyGenericInvocation, tyTuple: + result = ord(t.kind == tyGenericInvocation) for i in 0 .. <t.len: result += t.sons[i].sumGeneric break of tyProc: - # proc matche proc better than 'stmt' to disambiguate 'spawn' + # proc matches proc better than 'stmt' to disambiguate 'spawn' return 1 of tyGenericParam, tyExpr, tyStatic, tyStmt, tyTypeDesc: break else: return 0 @@ -262,7 +262,7 @@ proc concreteType(c: TCandidate, t: PType): PType = # example code that triggers it: # proc sort[T](cmp: proc(a, b: T): int = cmp) if result.kind != tyGenericParam: break - of tyGenericInvokation: + of tyGenericInvocation: internalError("cannot resolve type: " & typeToString(t)) result = t else: @@ -418,7 +418,8 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation = if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags: return isNone - elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {}: + elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and + optThreadAnalysis in gGlobalOptions: # noSideEffect implies ``tfThread``! return isNone elif f.flags * {tfIterator} != a.flags * {tfIterator}: @@ -461,7 +462,7 @@ proc matchUserTypeClass*(c: PContext, m: var TCandidate, openScope(c) inc c.inTypeClass - finally: + defer: dec c.inTypeClass closeScope(c) @@ -570,7 +571,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = assert(f != nil) if f.kind == tyExpr: - put(c.bindings, f, aOrig) + if aOrig != nil: put(c.bindings, f, aOrig) return isGeneric assert(aOrig != nil) @@ -584,7 +585,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if a.kind == tyGenericInst and skipTypes(f, {tyVar}).kind notin { - tyGenericBody, tyGenericInvokation, + tyGenericBody, tyGenericInvocation, tyGenericInst, tyGenericParam} + tyTypeClasses: return typeRel(c, f, lastSon(a)) @@ -864,8 +865,8 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = result = typeRel(c, ff, aa) if result == isNone: return if ff.kind == tyRange and result != isEqual: return isNone - result = isGeneric + # XXX See bug #2220. A[int] should match A[int] better than some generic X else: result = typeRel(c, lastSon(f), a) @@ -876,10 +877,10 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = let ff = lastSon(f) if ff != nil: result = typeRel(c, ff, a) - of tyGenericInvokation: + of tyGenericInvocation: var x = a.skipGenericAlias - if x.kind == tyGenericInvokation or f.sons[0].kind != tyGenericBody: - #InternalError("typeRel: tyGenericInvokation -> tyGenericInvokation") + if x.kind == tyGenericInvocation or f.sons[0].kind != tyGenericBody: + #InternalError("typeRel: tyGenericInvocation -> tyGenericInvocation") # simply no match for now: discard elif x.kind == tyGenericInst and @@ -896,7 +897,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = # we steal the generic parameters from the tyGenericBody: for i in countup(1, sonsLen(f) - 1): var x = PType(idTableGet(c.bindings, f.sons[0].sons[i - 1])) - if x == nil or x.kind in {tyGenericInvokation, tyGenericParam}: + if x == nil or x.kind in {tyGenericInvocation, tyGenericParam}: internalError("wrong instantiated type!") put(c.bindings, f.sons[i], x) @@ -1015,9 +1016,17 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = if result != isNone: put(c.bindings, f, aOrig) else: result = isNone + elif prev.kind == tyStatic: + if aOrig.kind == tyStatic: + result = typeRel(c, prev.lastSon, a) + if result != isNone and prev.n != nil: + if not exprStructuralEquivalent(prev.n, aOrig.n): + result = isNone + else: result = isNone else: - result = typeRel(c, prev, aOrig) - + # XXX endless recursion? + #result = typeRel(c, prev, aOrig) + result = isNone of tyTypeDesc: var prev = PType(idTableGet(c.bindings, f)) if prev == nil: @@ -1056,7 +1065,7 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation = of tyFromExpr: # fix the expression, so it contains the already instantiated types - if f.n == nil: return isGeneric + if f.n == nil or f.n.kind == nkEmpty: return isGeneric let reevaluated = tryResolvingStaticExpr(c, f.n) case reevaluated.typ.kind of tyTypeDesc: @@ -1156,6 +1165,15 @@ proc isInlineIterator*(t: PType): bool = result = t.kind == tyIter or (t.kind == tyBuiltInTypeClass and t.base.kind == tyIter) +proc isEmptyContainer*(t: PType): bool = + case t.kind + of tyExpr, tyNil: result = true + of tyArray, tyArrayConstr: result = t.sons[1].kind == tyEmpty + of tySet, tySequence, tyOpenArray, tyVarargs: + result = t.sons[0].kind == tyEmpty + of tyGenericInst: result = isEmptyContainer(t.lastSon) + else: result = false + proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, argSemantized, argOrig: PNode): PNode = var @@ -1178,8 +1196,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, if argType.kind == tyStatic: if m.callee.kind == tyGenericBody and tfGenericTypeParam notin argType.flags: - result = newNodeI(nkType, argOrig.info) - result.typ = makeTypeFromExpr(c, arg) + result = newNodeIT(nkType, argOrig.info, makeTypeFromExpr(c, arg)) return else: var evaluated = c.semTryConstExpr(c, arg) @@ -1252,12 +1269,25 @@ proc paramTypesMatchAux(m: var TCandidate, f, argType: PType, result = implicitConv(nkHiddenStdConv, f, result, m, c) of isGeneric: inc(m.genericMatches) - result = copyTree(arg) - result.typ = getInstantiatedType(c, arg, m, f) - # BUG: f may not be the right key! - if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}: - result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) - # BUGFIX: use ``result.typ`` and not `f` here + when true: + if arg.typ == nil: + result = arg + elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple: + result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + elif arg.typ.isEmptyContainer: + result = arg.copyTree + result.typ = getInstantiatedType(c, arg, m, f) + else: + result = arg + else: + # XXX Why is this ever necessary? arg's type should not be retrofitted + # to match formal's type in this way! + result = copyTree(arg) + result.typ = getInstantiatedType(c, arg, m, f) + # BUG: f may not be the right key! + if skipTypes(result.typ, abstractVar-{tyTypeDesc}).kind in {tyTuple}: + result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c) + # BUGFIX: use ``result.typ`` and not `f` here of isFromIntLit: # too lazy to introduce another ``*matches`` field, so we conflate # ``isIntConv`` and ``isIntLit`` here: @@ -1441,13 +1471,14 @@ proc matchesAux(c: PContext, n, nOrig: PNode, return checkConstraint(n.sons[a].sons[1]) if m.baseTypeMatch: - assert(container == nil) + #assert(container == nil) container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) addSon(container, arg) setSon(m.call, formal.position + 1, container) if f != formalLen - 1: container = nil - else: + else: setSon(m.call, formal.position + 1, arg) + inc f else: # unnamed param if f >= formalLen: @@ -1466,7 +1497,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, n.sons[a] = prepareOperand(c, formal.typ, n.sons[a]) var arg = paramTypesMatch(m, formal.typ, n.sons[a].typ, n.sons[a], nOrig.sons[a]) - if (arg != nil) and m.baseTypeMatch and (container != nil): + if arg != nil and m.baseTypeMatch and container != nil: addSon(container, arg) incrIndexType(container.typ) else: @@ -1480,7 +1511,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode, internalError(n.sons[a].info, "matches") return formal = m.callee.n.sons[f].sym - if containsOrIncl(marker, formal.position): + if containsOrIncl(marker, formal.position) and container.isNil: # already in namedParams: localError(n.sons[a].info, errCannotBindXTwice, formal.name.s) m.state = csNoMatch @@ -1493,17 +1524,22 @@ proc matchesAux(c: PContext, n, nOrig: PNode, m.state = csNoMatch return if m.baseTypeMatch: - assert(container == nil) - container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) + #assert(container == nil) + if container.isNil: + container = newNodeIT(nkBracket, n.sons[a].info, arrayConstr(c, arg)) addSon(container, arg) setSon(m.call, formal.position + 1, implicitConv(nkHiddenStdConv, formal.typ, container, m, c)) - if f != formalLen - 1: container = nil + #if f != formalLen - 1: container = nil + + # pick the formal from the end, so that 'x, y, varargs, z' works: + f = max(f, formalLen - n.len + a + 1) else: setSon(m.call, formal.position + 1, arg) + inc(f) + container = nil checkConstraint(n.sons[a]) inc(a) - inc(f) proc semFinishOperands*(c: PContext, n: PNode) = # this needs to be called to ensure that after overloading resolution every diff --git a/compiler/transf.nim b/compiler/transf.nim index f511ed69f..2f520aa20 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -321,6 +321,7 @@ proc transformYield(c: PTransf, n: PNode): PTransNode = proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode = result = transformSons(c, n) + if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return var n = result.PNode case n.sons[0].kind of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64: @@ -491,7 +492,8 @@ proc transformFor(c: PTransf, n: PNode): PTransNode = var newC = newTransCon(getCurrOwner(c)) newC.forStmt = n newC.forLoopBody = loopBody - internalAssert iter.kind == skIterator + # this can fail for 'nimsuggest' and 'check': + if iter.kind != skIterator: return result # generate access statements for the parameters (unless they are constant) pushTransCon(c, newC) for i in countup(1, sonsLen(call) - 1): diff --git a/compiler/treetab.nim b/compiler/treetab.nim index 63f3fc6e2..8d66d56c7 100644 --- a/compiler/treetab.nim +++ b/compiler/treetab.nim @@ -28,8 +28,9 @@ proc hashTree(n: PNode): THash = of nkFloatLit..nkFloat64Lit: if (n.floatVal >= - 1000000.0) and (n.floatVal <= 1000000.0): result = result !& toInt(n.floatVal) - of nkStrLit..nkTripleStrLit: - result = result !& hash(n.strVal) + of nkStrLit..nkTripleStrLit: + if not n.strVal.isNil: + result = result !& hash(n.strVal) else: for i in countup(0, sonsLen(n) - 1): result = result !& hashTree(n.sons[i]) diff --git a/compiler/types.nim b/compiler/types.nim index 78d390f13..5c3be7553 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -250,7 +250,7 @@ proc containsObject(t: PType): bool = proc isObjectWithTypeFieldPredicate(t: PType): bool = result = t.kind == tyObject and t.sons[0] == nil and - not (t.sym != nil and sfPure in t.sym.flags) and + not (t.sym != nil and {sfPure, sfInfixCall} * t.sym.flags != {}) and tfFinal notin t.flags proc analyseObjectWithTypeFieldAux(t: PType, @@ -396,7 +396,7 @@ proc rangeToStr(n: PNode): string = const typeToStr: array[TTypeKind, string] = ["None", "bool", "Char", "empty", "Array Constructor [$1]", "nil", "expr", "stmt", "typeDesc", - "GenericInvokation", "GenericBody", "GenericInst", "GenericParam", + "GenericInvocation", "GenericBody", "GenericInst", "GenericParam", "distinct $1", "enum", "ordinal[$1]", "array[$1, $2]", "object", "tuple", "set[$1]", "range[$1]", "ptr ", "ref ", "var ", "seq[$1]", "proc", "pointer", "OpenArray[$1]", "string", "CString", "Forward", @@ -432,9 +432,9 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = result = $t.n.intVal else: result = "int literal(" & $t.n.intVal & ")" - of tyGenericBody, tyGenericInst, tyGenericInvokation: + of tyGenericBody, tyGenericInst, tyGenericInvocation: result = typeToString(t.sons[0]) & '[' - for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)): + for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvocation)): if i > 1: add(result, ", ") add(result, typeToString(t.sons[i], preferGenericArg)) add(result, ']') @@ -649,7 +649,7 @@ proc lengthOrd(t: PType): BiggestInt = type TDistinctCompare* = enum ## how distinct types are to be compared dcEq, ## a and b should be the same type - dcEqIgnoreDistinct, ## compare symetrically: (distinct a) == b, a == b + dcEqIgnoreDistinct, ## compare symmetrically: (distinct a) == b, a == b ## or a == (distinct b) dcEqOrDistinctOf ## a equals b or a is distinct of b @@ -796,7 +796,7 @@ template ifFastObjectTypeCheckFailed(a, b: PType, body: stmt) {.immediate.} = else: # expensive structural equality test; however due to the way generic and # objects work, if one of the types does **not** contain tfFromGeneric, - # they cannot be equal. The check ``a.sym.Id == b.sym.Id`` checks + # they cannot be equal. The check ``a.sym.id == b.sym.id`` checks # for the same origin and is essential because we don't want "pure" # structural type equivalence: # @@ -941,7 +941,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool = result = sameChildrenAux(a, b, c) and sameFlags(a, b) if result and ExactGenericParams in c.flags: result = a.sym.position == b.sym.position - of tyGenericInvokation, tyGenericBody, tySequence, + of tyGenericInvocation, tyGenericBody, tySequence, tyOpenArray, tySet, tyRef, tyPtr, tyVar, tyArrayConstr, tyArray, tyProc, tyConst, tyMutable, tyVarargs, tyIter, tyOrdinal, tyTypeClasses, tyFieldAccessor: @@ -1029,16 +1029,18 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind, flags: TTypeAllowedFlags = {}): PType = - if n != nil: + if n != nil: result = typeAllowedAux(marker, n.typ, kind, flags) #if not result: debug(n.typ) if result == nil: case n.kind - of nkNone..nkNilLit: + of nkNone..nkNilLit: discard else: for i in countup(0, sonsLen(n) - 1): - result = typeAllowedNode(marker, n.sons[i], kind, flags) + let it = n.sons[i] + if it.kind == nkRecCase and kind == skConst: return n.typ + result = typeAllowedNode(marker, it, kind, flags) if result != nil: break proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], @@ -1085,7 +1087,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, if taField notin flags: result = t of tyTypeClasses: if not (tfGenericTypeParam in t.flags or taField notin flags): result = t - of tyGenericBody, tyGenericParam, tyGenericInvokation, + of tyGenericBody, tyGenericParam, tyGenericInvocation, tyNone, tyForward, tyFromExpr, tyFieldAccessor: result = t of tyNil: @@ -1098,7 +1100,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = typeAllowedAux(marker, lastSon(t), kind, flags) of tyRange: if skipTypes(t.sons[0], abstractInst-{tyTypeDesc}).kind notin - {tyChar, tyEnum, tyInt..tyFloat128}: result = t + {tyChar, tyEnum, tyInt..tyFloat128, tyUInt8..tyUInt32}: result = t of tyOpenArray, tyVarargs: if kind != skParam: result = t else: result = typeAllowedAux(marker, t.sons[0], skVar, flags) @@ -1118,7 +1120,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, result = typeAllowedAux(marker, t.sons[i], kind, flags) if result != nil: break of tyObject, tyTuple: - if kind == skConst and t.kind == tyObject: return t + if kind == skConst and t.kind == tyObject and t.sons[0] != nil: return t let flags = flags+{taField} for i in countup(0, sonsLen(t) - 1): result = typeAllowedAux(marker, t.sons[i], kind, flags) diff --git a/compiler/vm.nim b/compiler/vm.nim index 7edbb3fd2..a36de1c20 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -123,8 +123,12 @@ proc createStrKeepNode(x: var TFullReg) = if x.node.isNil: x.node = newNode(nkStrLit) elif x.node.kind == nkNilLit: + when defined(useNodeIds): + let id = x.node.id system.reset(x.node[]) x.node.kind = nkStrLit + when defined(useNodeIds): + x.node.id = id elif x.node.kind notin {nkStrLit..nkTripleStrLit} or nfAllConst in x.node.flags: # XXX this is hacky; tests/txmlgen triggers it: @@ -154,7 +158,7 @@ proc moveConst(x: var TFullReg, y: TFullReg) = of rkNodeAddr: x.nodeAddr = y.nodeAddr # this seems to be the best way to model the reference semantics -# of PNimrodNode: +# of system.NimNode: template asgnRef(x, y: expr) = moveConst(x, y) proc copyValue(src: PNode): PNode = @@ -772,10 +776,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = stackTrace(c, tos, pc, errNilAccess) of opcEcho: let rb = instr.regB - for i in ra..ra+rb-1: - #if regs[i].kind != rkNode: debug regs[i] - write(stdout, regs[i].node.strVal) - writeln(stdout, "") + if rb == 1: + msgWriteln(regs[ra].node.strVal) + else: + var outp = "" + for i in ra..ra+rb-1: + #if regs[i].kind != rkNode: debug regs[i] + outp.add(regs[i].node.strVal) + msgWriteln(outp) of opcContainsSet: decodeBC(rkInt) regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode)) @@ -1087,14 +1095,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcNAdd: decodeBC(rkNode) var u = regs[rb].node - u.add(regs[rc].node) + if u.kind notin {nkEmpty..nkNilLit}: + u.add(regs[rc].node) + else: + stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind) regs[ra].node = u of opcNAddMultiple: decodeBC(rkNode) let x = regs[rc].node var u = regs[rb].node - # XXX can be optimized: - for i in 0.. <x.len: u.add(x.sons[i]) + if u.kind notin {nkEmpty..nkNilLit}: + # XXX can be optimized: + for i in 0.. <x.len: u.add(x.sons[i]) + else: + stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind) regs[ra].node = u of opcNKind: decodeB(rkInt) @@ -1127,7 +1141,21 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = else: stackTrace(c, tos, pc, errFieldXNotFound, "ident") of opcNGetType: - internalError(c.debug[pc], "unknown opcode " & $instr.opcode) + let rb = instr.regB + let rc = instr.regC + if rc == 0: + ensureKind(rkNode) + if regs[rb].kind == rkNode and regs[rb].node.typ != nil: + regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc]) + else: + stackTrace(c, tos, pc, errGenerated, "node has no type") + else: + # typeKind opcode: + ensureKind(rkInt) + if regs[rb].kind == rkNode and regs[rb].node.typ != nil: + regs[ra].intVal = ord(regs[rb].node.typ.kind) + #else: + # stackTrace(c, tos, pc, errGenerated, "node has no type") of opcNStrVal: decodeB(rkNode) createStr regs[ra] @@ -1364,9 +1392,11 @@ var globalCtx: PCtx proc setupGlobalCtx(module: PSym) = - if globalCtx.isNil: globalCtx = newCtx(module) - else: refresh(globalCtx, module) - registerAdditionalOps(globalCtx) + if globalCtx.isNil: + globalCtx = newCtx(module) + registerAdditionalOps(globalCtx) + else: + refresh(globalCtx, module) proc myOpen(module: PSym): PPassContext = #var c = newEvalContext(module, emRepl) @@ -1436,7 +1466,9 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode = # immediate macros can bypass any type and arity checking so we check the # arity here too: if sym.typ.len > n.safeLen and sym.typ.len > 1: - globalError(n.info, "got $#, but expected $# argument(s)" % [$ <n.safeLen, $ <sym.typ.len]) + globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [ + n.renderTree, + $ <n.safeLen, $ <sym.typ.len]) setupGlobalCtx(module) var c = globalCtx diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 3d49cb130..90b9f2517 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -213,6 +213,7 @@ proc newCtx*(module: PSym): PCtx = proc refresh*(c: PCtx, module: PSym) = c.module = module c.prc = PProc(blocks: @[]) + c.loopIterations = MaxLoopIterations proc registerCallback*(c: PCtx; name: string; callback: VmCallback) = c.callbacks.add((name, callback)) diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index 6673d0bd2..11d839c41 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -1,13 +1,13 @@ # # # The Nim Compiler -# (c) Copyright 2013 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -import ast, types, msgs, osproc, streams, options +import ast, types, msgs, osproc, streams, options, idents proc readOutput(p: Process): string = result = "" @@ -19,11 +19,14 @@ proc readOutput(p: Process): string = discard p.waitForExit proc opGorge*(cmd, input: string): string = - var p = startCmd(cmd) - if input.len != 0: - p.inputStream.write(input) - p.inputStream.close() - result = p.readOutput + try: + var p = startProcess(cmd, options={poEvalCommand}) + if input.len != 0: + p.inputStream.write(input) + p.inputStream.close() + result = p.readOutput + except IOError, OSError: + result = "" proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = try: @@ -36,3 +39,116 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = except IOError: localError(info, errCannotOpenFile, file) result = "" + +proc atomicTypeX(name: string; t: PType; info: TLineInfo): PNode = + let sym = newSym(skType, getIdent(name), t.owner, info) + result = newSymNode(sym) + result.typ = t + +proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode + +proc mapTypeToBracket(name: string; t: PType; info: TLineInfo): PNode = + result = newNodeIT(nkBracketExpr, info, t) + result.add atomicTypeX(name, t, info) + for i in 0 .. < t.len: + if t.sons[i] == nil: + let void = atomicTypeX("void", t, info) + void.typ = newType(tyEmpty, t.owner) + result.add void + else: + result.add mapTypeToAst(t.sons[i], info) + +proc mapTypeToAst(t: PType, info: TLineInfo; allowRecursion=false): PNode = + template atomicType(name): expr = atomicTypeX(name, t, info) + + case t.kind + of tyNone: result = atomicType("none") + of tyBool: result = atomicType("bool") + of tyChar: result = atomicType("char") + of tyNil: result = atomicType("nil") + of tyExpr: result = atomicType("expr") + of tyStmt: result = atomicType("stmt") + of tyEmpty: result = atomicType"void" + of tyArrayConstr, tyArray: + result = newNodeIT(nkBracketExpr, info, t) + result.add atomicType("array") + result.add mapTypeToAst(t.sons[0], info) + result.add mapTypeToAst(t.sons[1], info) + of tyTypeDesc: + if t.base != nil: + result = newNodeIT(nkBracketExpr, info, t) + result.add atomicType("typeDesc") + result.add mapTypeToAst(t.base, info) + else: + result = atomicType"typeDesc" + of tyGenericInvocation: + result = newNodeIT(nkBracketExpr, info, t) + for i in 0 .. < t.len: + result.add mapTypeToAst(t.sons[i], info) + of tyGenericInst, tyGenericBody, tyOrdinal, tyUserTypeClassInst: + result = mapTypeToAst(t.lastSon, info) + of tyGenericParam, tyDistinct, tyForward: result = atomicType(t.sym.name.s) + of tyObject: + if allowRecursion: + result = newNodeIT(nkObjectTy, info, t) + if t.sons[0] == nil: + result.add ast.emptyNode + else: + result.add mapTypeToAst(t.sons[0], info) + result.add copyTree(t.n) + else: + result = atomicType(t.sym.name.s) + of tyEnum: + result = newNodeIT(nkEnumTy, info, t) + result.add copyTree(t.n) + of tyTuple: result = mapTypeToBracket("tuple", t, info) + of tySet: result = mapTypeToBracket("set", t, info) + of tyPtr: result = mapTypeToBracket("ptr", t, info) + of tyRef: result = mapTypeToBracket("ref", t, info) + of tyVar: result = mapTypeToBracket("var", t, info) + of tySequence: result = mapTypeToBracket("seq", t, info) + of tyProc: result = mapTypeToBracket("proc", t, info) + of tyOpenArray: result = mapTypeToBracket("openArray", t, info) + of tyRange: + result = newNodeIT(nkBracketExpr, info, t) + result.add atomicType("range") + result.add t.n.sons[0].copyTree + result.add t.n.sons[1].copyTree + of tyPointer: result = atomicType"pointer" + of tyString: result = atomicType"string" + of tyCString: result = atomicType"cstring" + of tyInt: result = atomicType"int" + of tyInt8: result = atomicType"int8" + of tyInt16: result = atomicType"int16" + of tyInt32: result = atomicType"int32" + of tyInt64: result = atomicType"int64" + of tyFloat: result = atomicType"float" + of tyFloat32: result = atomicType"float32" + of tyFloat64: result = atomicType"float64" + of tyFloat128: result = atomicType"float128" + of tyUInt: result = atomicType"uint" + of tyUInt8: result = atomicType"uint8" + of tyUInt16: result = atomicType"uint16" + of tyUInt32: result = atomicType"uint32" + of tyUInt64: result = atomicType"uint64" + of tyBigNum: result = atomicType"bignum" + of tyConst: result = mapTypeToBracket("const", t, info) + of tyMutable: result = mapTypeToBracket("mutable", t, info) + of tyVarargs: result = mapTypeToBracket("varargs", t, info) + of tyIter: result = mapTypeToBracket("iter", t, info) + of tyProxy: result = atomicType"error" + of tyBuiltInTypeClass: result = mapTypeToBracket("builtinTypeClass", t, info) + of tyUserTypeClass: result = mapTypeToBracket("userTypeClass", t, info) + of tyCompositeTypeClass: result = mapTypeToBracket("compositeTypeClass", t, info) + of tyAnd: result = mapTypeToBracket("and", t, info) + of tyOr: result = mapTypeToBracket("or", t, info) + of tyNot: result = mapTypeToBracket("not", t, info) + of tyAnything: result = atomicType"anything" + of tyStatic, tyFromExpr, tyFieldAccessor: + result = newNodeIT(nkBracketExpr, info, t) + result.add atomicType("static") + if t.n != nil: + result.add t.n.copyTree + +proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode = + result = mapTypeToAst(t, info, true) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 120120879..5b7b0b0fd 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -604,7 +604,8 @@ proc genNarrowU(c: PCtx; n: PNode; dest: TDest) = let t = skipTypes(n.typ, abstractVar-{tyTypeDesc}) # uint is uint64 in the VM, we we only need to mask the result for # other unsigned types: - if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32}: + if t.kind in {tyUInt8..tyUInt32, tyInt8..tyInt32} or + (t.kind == tyInt and t.size == 4): c.gABC(n, opcNarrowU, dest, TRegister(t.size*8)) proc genBinaryABCnarrow(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = @@ -893,7 +894,8 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = of mHigh: if dest < 0: dest = c.getTemp(n.typ) let tmp = c.genx(n.sons[1]) - if n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind == tyString: + case n.sons[1].typ.skipTypes(abstractVar-{tyTypeDesc}).kind: + of tyString, tyCString: c.gABI(n, opcLenStr, dest, tmp, 1) else: c.gABI(n, opcLenSeq, dest, tmp, 1) @@ -948,7 +950,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal) of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol) of mNIdent: genUnaryABC(c, n, dest, opcNIdent) - of mNGetType: genUnaryABC(c, n, dest, opcNGetType) + of mNGetType: + let tmp = c.genx(n.sons[1]) + if dest < 0: dest = c.getTemp(n.typ) + c.gABC(n, opcNGetType, dest, tmp, if n[0].sym.name.s == "typeKind": 1 else: 0) + c.freeTemp(tmp) + #genUnaryABC(c, n, dest, opcNGetType) of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal) of mNSetIntVal: unused(n, dest) @@ -1244,8 +1251,8 @@ proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = c.globals.add(getNullValue(s.typ, n.info)) s.position = c.globals.len # This is rather hard to support, due to the laziness of the VM code - # generator. See tests/compile/tmacro2 for why this is necesary: - # var decls{.compileTime.}: seq[PNimrodNode] = @[] + # generator. See tests/compile/tmacro2 for why this is necessary: + # var decls{.compileTime.}: seq[NimNode] = @[] let dest = c.getTemp(s.typ) c.gABx(n, opcLdGlobal, dest, s.position) let tmp = c.genx(s.ast) diff --git a/config/nim.cfg b/config/nim.cfg index 54c77e573..32709137d 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -5,10 +5,17 @@ # You may set environment variables with # @putenv "key" "val" -# Environment variables cannot be used in the options, however! +# Environment variables can be accessed like so: +# gcc.path %= "$CC_PATH" cc = gcc +# additional options always passed to the compiler: +--parallel_build: "0" # 0 to auto-detect number of processors + +hint[LineTooLong]=off +#hint[XDeclaredButNotUsed]=off + # example of how to setup a cross-compiler: arm.linux.gcc.exe = "arm-linux-gcc" arm.linux.gcc.linkerexe = "arm-linux-gcc" @@ -21,6 +28,7 @@ mips.linux.gcc.linkerexe = "mips-openwrt-linux-gcc" @end path="$lib/core" + path="$lib/pure" path="$lib/pure/collections" path="$lib/pure/concurrency" @@ -64,12 +72,6 @@ path="$lib/pure/unidecode" opt:speed @end -# additional options always passed to the compiler: ---parallel_build: "0" # 0 to auto-detect number of processors - -hint[LineTooLong]=off -#hint[XDeclaredButNotUsed]=off - @if unix: @if not bsd: # -fopenmp @@ -103,13 +105,27 @@ hint[LineTooLong]=off @if macosx or freebsd: cc = clang tlsEmulation:on - gcc.options.always = "-w -fasm-blocks" - gcc.cpp.options.always = "-w -fasm-blocks -fpermissive" + gcc.options.always = "-w" + gcc.cpp.options.always = "-w -fpermissive" @else: gcc.options.always = "-w" gcc.cpp.options.always = "-w -fpermissive" @end +# Configuration for the VxWorks +# This has been tested with VxWorks 6.9 only +@if vxworks: + # For now we only support compiling RTPs applications (i.e. no DKMs) + gcc.options.always = "-mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings" + # The linker config must add the VxWorks common library for the selected + # processor which is usually found in: + # "$WIND_BASE/target/lib/usr/lib/PROCESSOR_FAMILY/PROCESSOR_TYPE/common", + # where PROCESSOR_FAMILY and PROCESSOR_TYPE are those supported by the VxWorks + # compiler (e.g. ppc/PPC32 or mips/MIPSI64, etc) + # For now we only support the PowerPC CPU + gcc.options.linker %= "-L $WIND_BASE/target/lib/usr/lib/ppc/PPC32/common -mrtp -fno-strict-aliasing -D_C99 -D_HAS_C9X -std=c99 -fasm -Wall -Wno-write-strings" +@end + gcc.options.speed = "-O3 -fno-strict-aliasing" gcc.options.size = "-Os" gcc.options.debug = "-g3 -O0" diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 2e0bf62a0..e036c3b9a 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -24,7 +24,7 @@ doc.section.toc = """ </li> """ -# Chunk of HTML emmited for each entry in the HTML table of contents. +# Chunk of HTML emitted for each entry in the HTML table of contents. # Available variables are: # * $desc: the actual docstring of the item. # * $header: the full version of name, including types, pragmas, tags, etc. @@ -45,7 +45,7 @@ $seeSrc </dd> """ -# Chunk of HTML emmited for each entry in the HTML table of contents. +# Chunk of HTML emitted for each entry in the HTML table of contents. # See doc.item for available substitution variables. doc.item.toc = """ <li><a class="reference" href="#$itemSymOrID" diff --git a/config/nimrod.cfg b/config/nimrod.cfg deleted file mode 100644 index 62a7b16cc..000000000 --- a/config/nimrod.cfg +++ /dev/null @@ -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" diff --git a/copying.txt b/copying.txt index 908625e18..d89bace0b 100644 --- a/copying.txt +++ b/copying.txt @@ -1,7 +1,7 @@ ===================================================== Nim -- a Compiler for Nim. http://nim-lang.org/ -Copyright (C) 2006-2014 Andreas Rumpf. All rights reserved. +Copyright (C) 2006-2015 Andreas Rumpf. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/doc/advopt.txt b/doc/advopt.txt index 78c3d571a..d4b1b7e57 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -18,7 +18,7 @@ Advanced commands: track a file, currently not saved to disk --suggest suggest all possible symbols at position --def list all possible definitions at position - --context list possible invokation context + --context list possible invocation context --usages list all usages of the symbol at position --eval evaluates an expression //serve start the compiler as a service mode (CAAS) @@ -48,7 +48,6 @@ Advanced options: --os:SYMBOL set the target operating system (cross-compilation) --cpu:SYMBOL set the target processor (cross-compilation) --debuginfo enables debug information - --debugger:on|off turn Embedded Nim Debugger on|off -t, --passC:OPTION pass an option to the C compiler -l, --passL:OPTION pass an option to the linker --cincludes:DIR modify the C compiler header search path @@ -66,7 +65,6 @@ Advanced options: --threadanalysis:on|off turn thread analysis on|off --tlsEmulation:on|off turn thread local storage emulation on|off --taintMode:on|off turn taint mode on|off - --symbolFiles:on|off turn symbol files on|off (experimental) --implicitStatic:on|off turn implicit compile time evaluation on|off --patterns:on|off turn pattern matching on|off --skipCfg do not read the general configuration file @@ -86,10 +84,8 @@ Advanced options: that --dynlibOverride:lua matches dynlib: "liblua.so.3" --listCmd list the commands used to execute external programs - --parallelBuild=0|1|... perform a parallel build + --parallelBuild:0|1|... perform a parallel build value = number of processors (0 for auto-detect) --verbosity:0|1|2|3 set Nim's verbosity level (1 is default) - --cs:none|partial set case sensitivity level (default: none); - do not use! this setting affects the whole language --experimental enable experimental language features -v, --version show detailed version information diff --git a/doc/apis.txt b/doc/apis.txt index e0510d85f..165279490 100644 --- a/doc/apis.txt +++ b/doc/apis.txt @@ -79,10 +79,3 @@ string str identifier ident indentation indent ------------------- ------------ -------------------------------------- - - -Coding Guidelines -================= - -For coding guidelines see the `Internals of the Nim Compiler -<intern.html#coding-guidelines>`_ documentation. diff --git a/doc/astspec.txt b/doc/astspec.txt index 5c4274093..4c27272e2 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -1,14 +1,14 @@ The AST in Nim ================= This section describes how the AST is modelled with Nim's type system. -The AST consists of nodes (``PNimrodNode``) with a variable number of +The AST consists of nodes (``NimNode``) with a variable number of children. Each node has a field named ``kind`` which describes what the node contains: .. code-block:: nim type - TNimrodNodeKind = enum ## kind of a node; only explanatory + NimNodeKind = enum ## kind of a node; only explanatory nnkNone, ## invalid node kind nnkEmpty, ## empty node nnkIdent, ## node contains an identifier @@ -18,11 +18,11 @@ contains: nnkCaseStmt, ## node represents a case statement ... ## many more - PNimrodNode = ref TNimrodNode - TNimrodNode {.final.} = object - case kind: TNimrodNodeKind ## the node's kind + NimNode = ref NimNodeObj + NimNodeObj = object + case kind: NimNodeKind ## the node's kind of nnkNone, nnkEmpty, nnkNilLit: - nil ## node contains no additional fields + discard ## node contains no additional fields of nnkCharLit..nnkInt64Lit: intVal: biggestInt ## the int literal of nnkFloatLit..nnkFloat64Lit: @@ -30,13 +30,13 @@ contains: of nnkStrLit..nnkTripleStrLit: strVal: string ## the string literal of nnkIdent: - ident: TNimrodIdent ## the identifier + ident: NimIdent ## the identifier of nnkSym: - symbol: PNimrodSymbol ## the symbol (after symbol lookup phase) + symbol: NimSymbol ## the symbol (after symbol lookup phase) else: - sons: seq[PNimrodNode] ## the node's sons (or children) + sons: seq[NimNode] ## the node's sons (or children) -For the ``PNimrodNode`` type, the ``[]`` operator has been overloaded: +For the ``NimNode`` type, the ``[]`` operator has been overloaded: ``n[i]`` is ``n``'s ``i``-th child. To specify the AST for the different Nim constructs, the notation @@ -73,10 +73,7 @@ Nim expression corresponding AST ----------------- --------------------------------------------- Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes -get transferred into ``nnkSym`` nodes. However, a macro receives an AST that -has not been checked for semantics and thus the identifiers have not been -looked up. Macros should deal with ``nnkIdent`` nodes and do not need to deal -with ``nnkSym`` nodes. +get transferred into ``nnkSym`` nodes. Calls/expressions @@ -171,13 +168,13 @@ AST: nnkStrLit("hallo")) -Dereference operator ``^`` --------------------------- +Dereference operator ``[]`` +--------------------------- Concrete syntax: .. code-block:: nim - x^ + x[] AST: @@ -573,4 +570,3 @@ Other node kinds are especially designed to make AST manipulations easier. These are explained here. To be written. - diff --git a/doc/backends.txt b/doc/backends.txt index c7b60da26..c7939baec 100644 --- a/doc/backends.txt +++ b/doc/backends.txt @@ -225,7 +225,7 @@ The JavaScript target doesn't have any further interfacing considerations since it also has garbage collection, but the C targets require you to initialize Nim's internals, which is done calling a ``NimMain`` function. Also, C code requires you to specify a forward declaration for functions or -the compiler will asume certain types for the return value and parameters +the compiler will assume certain types for the return value and parameters which will likely make your program crash at runtime. The Nim compiler can generate a C interface header through the ``--header`` @@ -427,7 +427,7 @@ Custom data types ----------------- Just like strings, custom data types that are to be shared between Nim and -the backend will need careful consideration of who controlls who. If you want +the backend will need careful consideration of who controls who. If you want to hand a Nim reference to C code, you will need to use `GC_ref <system.html#GC_ref>`_ to mark the reference as used, so it does not get freed. And for the C backend you will need to expose the `GC_unref diff --git a/doc/basicopt.txt b/doc/basicopt.txt index e366b2718..7d08f1159 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -6,7 +6,6 @@ Command: //compile, c compile project with default code generator (C) //doc generate the documentation for inputfile //doc2 generate the documentation for the whole project - //i start Nim in interactive mode (limited) Arguments: arguments are passed to the program being run (if --run option is selected) @@ -14,7 +13,6 @@ Options: -p, --path:PATH add path to search paths -d, --define:SYMBOL define a conditional symbol -u, --undef:SYMBOL undefine a conditional symbol - --symbol:SYMBOL declare a conditional symbol -f, --forceBuild force rebuilding of all modules --stackTrace:on|off turn stack tracing on|off --lineTrace:on|off turn line tracing on|off @@ -31,6 +29,7 @@ Options: --infChecks:on|off turn Inf checks on|off --deadCodeElim:on|off whole program dead code elimination on|off --opt:none|speed|size optimize not at all or for speed|size + --debugger:native|endb use native debugger (gdb) | ENDB (experimental) --app:console|gui|lib|staticlib generate a console app|GUI app|DLL|static library -r, --run run the compiled program with given arguments diff --git a/doc/gc.txt b/doc/gc.txt index ac8d46cfa..f51421bcd 100644 --- a/doc/gc.txt +++ b/doc/gc.txt @@ -87,14 +87,14 @@ is triggered. Time measurement ---------------- -The GC's way of measing time uses (see ``lib/system/timers.nim`` for the +The GC's way of measuring time uses (see ``lib/system/timers.nim`` for the implementation): 1) ``QueryPerformanceCounter`` and ``QueryPerformanceFrequency`` on Windows. 2) ``mach_absolute_time`` on Mac OS X. 3) ``gettimeofday`` on Posix systems. -As such it supports a resolution of nano seconds internally; however the API +As such it supports a resolution of nanoseconds internally; however the API uses microseconds for convenience. diff --git a/doc/idetools.txt b/doc/idetools.txt index 48197f8bf..2ffe46d4b 100644 --- a/doc/idetools.txt +++ b/doc/idetools.txt @@ -27,7 +27,7 @@ integrations <https://github.com/Araq/Nim/wiki/Editor-Support>`_ already available. -Idetools invokation +Idetools invocation =================== Specifying the location of the query @@ -35,7 +35,7 @@ Specifying the location of the query All of the available idetools commands require you to specify a query location through the ``--track`` or ``--trackDirty`` switches. -The general idetools invokations are:: +The general idetools invocations are:: nim idetools --track:FILE,LINE,COL <switches> proj.nim @@ -129,7 +129,7 @@ the suggestions sorted first by scope (from innermost to outermost) and then by item name. -Invokation context +Invocation context ------------------ The ``--context`` idetools switch is very similar to the suggestions @@ -163,7 +163,7 @@ running/debugged user project. Compiler as a service (CAAS) ============================ -The ocasional use of idetools is acceptable for things like +The occasional use of idetools is acceptable for things like definitions, where the user puts the cursor on a symbol or double clicks it and after a second or two the IDE displays where that symbol is defined. Such latencies would be terrible for features @@ -533,10 +533,10 @@ run it manually. First you have to compile the tester:: Running the ``caasdriver`` without parameters will attempt to process all the test cases in all three operation modes. If a test succeeds nothing will be printed and the process will exit with zero. If any -test fails, the specific line of the test preceeding the failure +test fails, the specific line of the test preceding the failure and the failure itself will be dumped to stdout, along with a final indicator of the success state and operation mode. You can pass the -parameter ``verbose`` to force all output even on successfull tests. +parameter ``verbose`` to force all output even on successful tests. The normal operation mode is called ``ProcRun`` and it involves starting a process for each command or query, similar to running diff --git a/doc/intern.txt b/doc/intern.txt index a103703d7..9582fc96f 100644 --- a/doc/intern.txt +++ b/doc/intern.txt @@ -236,7 +236,7 @@ too. Type converters fall into this category: If in the above example module ``B`` is re-compiled, but ``A`` is not then ``B`` needs to be aware of ``toBool`` even though ``toBool`` is not referenced -in ``B`` *explicitely*. +in ``B`` *explicitly*. Both the multi method and the type converter problems are solved by storing them in special sections in the ROD file that are loaded *unconditionally* @@ -370,7 +370,7 @@ needed as the data structures needs to be rebuilt periodically anyway. Complete traversal is done in this way:: - for each page decriptor d: + for each page descriptor d: for each bit in d: if bit == 1: traverse the pointer belonging to this bit @@ -406,7 +406,7 @@ The generated code looks roughly like this: setRef(&r->left) } -Note that for systems with a continous stack (which most systems have) +Note that for systems with a continuous stack (which most systems have) the check whether the ref is on the stack is very cheap (only two comparisons). diff --git a/doc/lib.txt b/doc/lib.txt index b7c94b505..76920c6a9 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -185,10 +185,19 @@ Math libraries * `complex <complex.html>`_ This module implements complex numbers and their mathematical operations. +* `rationals <rationals.html>`_ + This module implements rational numbers and their mathematical operations. + * `fenv <fenv.html>`_ Floating-point environment. Handling of floating-point rounding and exceptions (overflow, zero-devide, etc.). +* `basic2d <basic2d.html>`_ + Basic 2d support with vectors, points, matrices and some basic utilities. + +* `basic3d <basic3d.html>`_ + Basic 3d support with vectors, points, matrices and some basic utilities. + Internet Protocols and Support ------------------------------ @@ -218,9 +227,6 @@ Internet Protocols and Support * `smtp <smtp.html>`_ This module implement a simple SMTP client. -* `irc <irc.html>`_ - This module implements an asynchronous IRC client. - * `ftpclient <ftpclient.html>`_ This module implements an FTP client. @@ -367,7 +373,7 @@ Miscellaneous ------------- * `events <events.html>`_ - This module implements an event system that is not dependant on external + This module implements an event system that is not dependent on external graphical toolkits. * `oids <oids.html>`_ diff --git a/doc/manual/about.txt b/doc/manual/about.txt index 13307279b..78167efe3 100644 --- a/doc/manual/about.txt +++ b/doc/manual/about.txt @@ -25,9 +25,9 @@ with ``'``. An example:: ifStmt = 'if' expr ':' stmts ('elif' expr ':' stmts)* ('else' stmts)? -The binary ``^*`` operator is used as a shorthand for 0 or more occurances +The binary ``^*`` operator is used as a shorthand for 0 or more occurrences separated by its second argument; likewise ``^+`` means 1 or more -occurances: ``a ^+ b`` is short for ``a (b a)*`` +occurrences: ``a ^+ b`` is short for ``a (b a)*`` and ``a ^* b`` is short for ``(a (b a)*)?``. Example:: arrayConstructor = '[' expr ^* ',' ']' diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt index c975e7f48..cf44eb588 100644 --- a/doc/manual/syntax.txt +++ b/doc/manual/syntax.txt @@ -12,10 +12,8 @@ Binary operators have 11 different levels of precedence. Associativity ------------- -Binary operators whose first character is ``^`` or its last character -is ``>`` are right-associative, all other binary operators are left-associative. - -Exception: The single "greater than" ``>`` operator is left-associative too. +Binary operators whose first character is ``^`` are right-associative, all +other binary operators are left-associative. Operators ending in ``>`` but longer than a single character are called `arrow like`:idx:. @@ -61,7 +59,7 @@ Precedence level Operators First charact Strong spaces ------------- -The number of spaces preceeding a non-keyword operator affects precedence +The number of spaces preceding a non-keyword operator affects precedence if the experimental parser directive ``#!strongSpaces`` is used. Indentation is not used to determine the number of spaces. If 2 or more operators have the same number of preceding spaces the precedence table applies, so ``1 + 3 * 4`` diff --git a/doc/manual/typedesc.txt b/doc/manual/typedesc.txt index 97ab18b56..5087c1204 100644 --- a/doc/manual/typedesc.txt +++ b/doc/manual/typedesc.txt @@ -25,7 +25,7 @@ For the purposes of code generation, all static params are treated as generic params - the proc will be compiled separately for each unique supplied value (or combination of values). -Furthermore, the system module defines a `semistatic[T]` type than can be +Furthermore, the system module defines a `semistatic[T]` type that can be used to declare procs accepting both static and run-time values, which can optimize their body according to the supplied param using the `isStatic(p)` predicate: diff --git a/doc/manual/types.txt b/doc/manual/types.txt index 32ff19f75..a20701121 100644 --- a/doc/manual/types.txt +++ b/doc/manual/types.txt @@ -1142,7 +1142,7 @@ modules like `db_sqlite <db_sqlite.html>`_. Void type --------- -The ``void`` type denotes the absense of any type. Parameters of +The ``void`` type denotes the absence of any type. Parameters of type ``void`` are treated as non-existent, ``void`` as a return type means that the procedure does not return a value: diff --git a/doc/nimc.txt b/doc/nimc.txt index 80fcf927b..c6b0b5255 100644 --- a/doc/nimc.txt +++ b/doc/nimc.txt @@ -1,45 +1,45 @@ -=================================== - Nim Compiler User Guide -=================================== - -:Author: Andreas Rumpf -:Version: |nimversion| - -.. contents:: - - "Look at you, hacker. A pathetic creature of meat and bone, panting and - sweating as you run through my corridors. How can you challenge a perfect, - immortal machine?" - - -Introduction -============ - -This document describes the usage of the *Nim compiler* -on the different supported platforms. It is not a definition of the Nim -programming language (therefore is the `manual <manual.html>`_). - -Nim is free software; it is licensed under the -`MIT License <http://www.opensource.org/licenses/mit-license.php>`_. - - -Compiler Usage -============== - -Command line switches ---------------------- -Basic command line switches are: - -Usage: - -.. include:: basicopt.txt - ----- - -Advanced command line switches are: - -.. include:: advopt.txt - +=================================== + Nim Compiler User Guide +=================================== + +:Author: Andreas Rumpf +:Version: |nimversion| + +.. contents:: + + "Look at you, hacker. A pathetic creature of meat and bone, panting and + sweating as you run through my corridors. How can you challenge a perfect, + immortal machine?" + + +Introduction +============ + +This document describes the usage of the *Nim compiler* +on the different supported platforms. It is not a definition of the Nim +programming language (therefore is the `manual <manual.html>`_). + +Nim is free software; it is licensed under the +`MIT License <http://www.opensource.org/licenses/mit-license.php>`_. + + +Compiler Usage +============== + +Command line switches +--------------------- +Basic command line switches are: + +Usage: + +.. include:: basicopt.txt + +---- + +Advanced command line switches are: + +.. include:: advopt.txt + List of warnings @@ -53,21 +53,16 @@ Name Description ========================== ============================================ CannotOpenFile Some file not essential for the compiler's working could not be opened. -OctalEscape The code contains an unsupported octal +OctalEscape The code contains an unsupported octal sequence. Deprecated The code uses a deprecated symbol. ConfigDeprecated The project makes use of a deprecated config file. -SmallLshouldNotBeUsed The letter 'l' should not be used as an +SmallLshouldNotBeUsed The letter 'l' should not be used as an 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. -ShadowIdent A local variable shadows another local +ShadowIdent A local variable shadows another local variable of an outer scope. User Some user defined warning. ========================== ============================================ @@ -103,30 +98,30 @@ enable builds in release mode (``-d:release``) where certain safety checks are omitted for better performance. Another common use is the ``-d:ssl`` switch to activate `SSL sockets <sockets.html>`_. - -Configuration files -------------------- - -**Note:** The *project file name* is the name of the ``.nim`` file that is -passed as a command line argument to the compiler. - - -The ``nim`` executable processes configuration files in the following -directories (in this order; later files overwrite previous settings): - -1) ``$nim/config/nim.cfg``, ``/etc/nim.cfg`` (UNIX) or ``%NIMROD%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option. -2) ``/home/$user/.config/nim.cfg`` (UNIX) or ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option. -3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option. -4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command line option. -5) A project can also have a project specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option. - - -Command line settings have priority over configuration file settings. - -The default build of a project is a `debug build`:idx:. To compile a -`release build`:idx: define the ``release`` symbol:: - - nim c -d:release myproject.nim + +Configuration files +------------------- + +**Note:** The *project file name* is the name of the ``.nim`` file that is +passed as a command line argument to the compiler. + + +The ``nim`` executable processes configuration files in the following +directories (in this order; later files overwrite previous settings): + +1) ``$nim/config/nim.cfg``, ``/etc/nim.cfg`` (UNIX) or ``%NIMROD%/config/nim.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option. +2) ``/home/$user/.config/nim.cfg`` (UNIX) or ``%APPDATA%/nim.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option. +3) ``$parentDir/nim.cfg`` where ``$parentDir`` stands for any parent directory of the project file's path. These files can be skipped with the ``--skipParentCfg`` command line option. +4) ``$projectDir/nim.cfg`` where ``$projectDir`` stands for the project file's path. This file can be skipped with the ``--skipProjCfg`` command line option. +5) A project can also have a project specific configuration file named ``$project.nim.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option. + + +Command line settings have priority over configuration file settings. + +The default build of a project is a `debug build`:idx:. To compile a +`release build`:idx: define the ``release`` symbol:: + + nim c -d:release myproject.nim Search path handling @@ -138,8 +133,8 @@ found an ambiguity error is produced. ``nim dump`` shows the contents of the PATH. -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 +However before the PATH is used the current directory is checked for the +file's existence. So if PATH contains ``$lib`` and ``$lib/bar`` and the directory structure looks like this:: $lib/x.nim @@ -152,83 +147,83 @@ And ``main`` imports ``x``, ``foo/x`` is imported. If ``other`` imports ``x`` then both ``$lib/x.nim`` and ``$lib/bar/x.nim`` match and so the compiler should reject it. Currently however this check is not implemented and instead the first matching file is used. - - -Generated C code directory --------------------------- + + +Generated C code directory +-------------------------- The generated files that Nim produces all go into a subdirectory called ``nimcache`` in your project directory. This makes it easy to delete all generated files. Files generated in this directory follow a naming logic which you can read about in the `Nim Backend Integration document <backends.html#nimcache-naming-logic>`_. -However, the generated C code is not platform independent. C code generated for -Linux does not compile on Windows, for instance. The comment on top of the -C file lists the OS, CPU and CC the file has been compiled for. - - -Compilation cache -================= - -**Warning**: The compilation cache is still highly experimental! - -The ``nimcache`` directory may also contain so called `rod`:idx: -or `symbol files`:idx:. These files are pre-compiled modules that are used by -the compiler to perform `incremental compilation`:idx:. This means that only -modules that have changed since the last compilation (or the modules depending -on them etc.) are re-compiled. However, per default no symbol files are -generated; use the ``--symbolFiles:on`` command line switch to activate them. - -Unfortunately due to technical reasons the ``--symbolFiles:on`` needs -to *aggregate* some generated C code. This means that the resulting executable -might contain some cruft even when dead code elimination is turned on. So -the final release build should be done with ``--symbolFiles:off``. - -Due to the aggregation of C code it is also recommended that each project -resides in its own directory so that the generated ``nimcache`` directory -is not shared between different projects. - - -Cross compilation -================= - -To cross compile, use for example:: - - nim c --cpu:i386 --os:linux --compile_only --gen_script myproject.nim - -Then move the C code and the compile script ``compile_myproject.sh`` to your +However, the generated C code is not platform independent. C code generated for +Linux does not compile on Windows, for instance. The comment on top of the +C file lists the OS, CPU and CC the file has been compiled for. + + +Compilation cache +================= + +**Warning**: The compilation cache is still highly experimental! + +The ``nimcache`` directory may also contain so called `rod`:idx: +or `symbol files`:idx:. These files are pre-compiled modules that are used by +the compiler to perform `incremental compilation`:idx:. This means that only +modules that have changed since the last compilation (or the modules depending +on them etc.) are re-compiled. However, per default no symbol files are +generated; use the ``--symbolFiles:on`` command line switch to activate them. + +Unfortunately due to technical reasons the ``--symbolFiles:on`` needs +to *aggregate* some generated C code. This means that the resulting executable +might contain some cruft even when dead code elimination is turned on. So +the final release build should be done with ``--symbolFiles:off``. + +Due to the aggregation of C code it is also recommended that each project +resides in its own directory so that the generated ``nimcache`` directory +is not shared between different projects. + + +Cross compilation +================= + +To cross compile, use for example:: + + nim c --cpu:i386 --os:linux --compile_only --gen_script myproject.nim + +Then move the C code and the compile script ``compile_myproject.sh`` to your Linux i386 machine and run the script. Another way is to make Nim invoke a cross compiler toolchain:: - - nim c --cpu:arm --os:linux myproject.nim - -For cross compilation, the compiler invokes a C compiler named -like ``$cpu.$os.$cc`` (for example arm.linux.gcc) and the configuration + + nim c --cpu:arm --os:linux myproject.nim + +For cross compilation, the compiler invokes a C compiler named +like ``$cpu.$os.$cc`` (for example arm.linux.gcc) and the configuration system is used to provide meaningful defaults. For example for ``ARM`` your configuration file should contain something like:: arm.linux.gcc.path = "/usr/bin" arm.linux.gcc.exe = "arm-linux-gcc" arm.linux.gcc.linkerexe = "arm-linux-gcc" - - -DLL generation -============== - -Nim supports the generation of DLLs. However, there must be only one -instance of the GC per process/address space. This instance is contained in -``nimrtl.dll``. This means that every generated Nim DLL depends -on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command:: - - nim c -d:release lib/nimrtl.nim - -To link against ``nimrtl.dll`` use the command:: - - nim c -d:useNimRtl myprog.nim - -**Note**: Currently the creation of ``nimrtl.dll`` with thread support has -never been tested and is unlikely to work! + + +DLL generation +============== + +Nim supports the generation of DLLs. However, there must be only one +instance of the GC per process/address space. This instance is contained in +``nimrtl.dll``. This means that every generated Nim DLL depends +on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command:: + + nim c -d:release lib/nimrtl.nim + +To link against ``nimrtl.dll`` use the command:: + + nim c -d:useNimRtl myprog.nim + +**Note**: Currently the creation of ``nimrtl.dll`` with thread support has +never been tested and is unlikely to work! Additional compilation switches @@ -247,10 +242,10 @@ Define Effect version. ``useFork`` Makes ``osproc`` use ``fork`` instead of ``posix_spawn``. ``useNimRtl`` Compile and link against ``nimrtl.dll``. -``useMalloc`` Makes Nim use C's `malloc`:idx: instead of Nim's +``useMalloc`` Makes Nim use C's `malloc`:idx: instead of Nim's own memory manager. This only works with ``gc:none``. -``useRealtimeGC`` Enables support of Nim's GC for *soft* realtime - systems. See the documentation of the `gc <gc.html>`_ +``useRealtimeGC`` Enables support of Nim's GC for *soft* realtime + systems. See the documentation of the `gc <gc.html>`_ for further information. ``nodejs`` The JS target is actually ``node.js``. ``ssl`` Enables OpenSSL support for the sockets module. @@ -258,84 +253,84 @@ Define Effect ``uClibc`` Use uClibc instead of libc. (Relevant for Unix-like OSes) ================== ========================================================= - - -Additional Features -=================== - -This section describes Nim's additional features that are not listed in the -Nim manual. Some of the features here only make sense for the C code -generator and are subject to change. - - -NoDecl pragma -------------- -The ``noDecl`` pragma can be applied to almost any symbol (variable, proc, -type, etc.) and is sometimes useful for interoperability with C: -It tells Nim that it should not generate a declaration for the symbol in -the C code. For example: - -.. code-block:: Nim - var - EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as - # Nim does not know its value - -However, the ``header`` pragma is often the better alternative. - -**Note**: This will not work for the LLVM backend. - - -Header pragma -------------- -The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be -applied to almost any symbol and specifies that it should not be declared -and instead the generated code should contain an ``#include``: - -.. code-block:: Nim - type - PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer - # import C's FILE* type; Nim will treat it as a new pointer type - -The ``header`` pragma always expects a string constant. The string contant -contains the header file: As usual for C, a system header file is enclosed -in angle brackets: ``<>``. If no angle brackets are given, Nim -encloses the header file in ``""`` in the generated C code. - -**Note**: This will not work for the LLVM backend. - - -IncompleteStruct pragma ------------------------ -The ``incompleteStruct`` pragma tells the compiler to not use the -underlying C ``struct`` in a ``sizeof`` expression: - -.. code-block:: Nim - type - DIR* {.importc: "DIR", header: "<dirent.h>", - final, pure, incompleteStruct.} = object - - -Compile pragma --------------- -The ``compile`` pragma can be used to compile and link a C/C++ source file -with the project: - -.. code-block:: Nim - {.compile: "myfile.cpp".} - -**Note**: Nim computes a CRC checksum and only recompiles the file if it -has changed. You can use the ``-f`` command line option to force recompilation -of the file. - - -Link pragma ------------ -The ``link`` pragma can be used to link an additional file with the project: - -.. code-block:: Nim - {.link: "myfile.o".} - - + + +Additional Features +=================== + +This section describes Nim's additional features that are not listed in the +Nim manual. Some of the features here only make sense for the C code +generator and are subject to change. + + +NoDecl pragma +------------- +The ``noDecl`` pragma can be applied to almost any symbol (variable, proc, +type, etc.) and is sometimes useful for interoperability with C: +It tells Nim that it should not generate a declaration for the symbol in +the C code. For example: + +.. code-block:: Nim + var + EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as + # Nim does not know its value + +However, the ``header`` pragma is often the better alternative. + +**Note**: This will not work for the LLVM backend. + + +Header pragma +------------- +The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be +applied to almost any symbol and specifies that it should not be declared +and instead the generated code should contain an ``#include``: + +.. code-block:: Nim + type + PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer + # import C's FILE* type; Nim will treat it as a new pointer type + +The ``header`` pragma always expects a string constant. The string contant +contains the header file: As usual for C, a system header file is enclosed +in angle brackets: ``<>``. If no angle brackets are given, Nim +encloses the header file in ``""`` in the generated C code. + +**Note**: This will not work for the LLVM backend. + + +IncompleteStruct pragma +----------------------- +The ``incompleteStruct`` pragma tells the compiler to not use the +underlying C ``struct`` in a ``sizeof`` expression: + +.. code-block:: Nim + type + DIR* {.importc: "DIR", header: "<dirent.h>", + final, pure, incompleteStruct.} = object + + +Compile pragma +-------------- +The ``compile`` pragma can be used to compile and link a C/C++ source file +with the project: + +.. code-block:: Nim + {.compile: "myfile.cpp".} + +**Note**: Nim computes a CRC checksum and only recompiles the file if it +has changed. You can use the ``-f`` command line option to force recompilation +of the file. + + +Link pragma +----------- +The ``link`` pragma can be used to link an additional file with the project: + +.. code-block:: Nim + {.link: "myfile.o".} + + PassC pragma ------------ The ``passC`` pragma can be used to pass additional parameters to the C @@ -365,76 +360,76 @@ embed parameters from an external command at compile time: {.passL: gorge("pkg-config --libs sdl").} -Emit pragma ------------ -The ``emit`` pragma can be used to directly affect the output of the -compiler's code generator. So it makes your code unportable to other code -generators/backends. Its usage is highly discouraged! However, it can be -extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code. - -Example: - -.. code-block:: Nim - {.emit: """ - static int cvariable = 420; - """.} - +Emit pragma +----------- +The ``emit`` pragma can be used to directly affect the output of the +compiler's code generator. So it makes your code unportable to other code +generators/backends. Its usage is highly discouraged! However, it can be +extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code. + +Example: + +.. code-block:: Nim + {.emit: """ + static int cvariable = 420; + """.} + {.push stackTrace:off.} - proc embedsC() = - var nimVar = 89 - # use backticks to access Nim symbols within an emit section: - {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".} + proc embedsC() = + var nimVar = 89 + # use backticks to access Nim symbols within an emit section: + {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".} {.pop.} - - embedsC() + + embedsC() As can be seen from the example, to Nim symbols can be referred via backticks. Use two backticks to produce a single verbatim backtick. - -ImportCpp pragma + +ImportCpp pragma ---------------- **Note**: `c2nim <c2nim.html>`_ can parse a large subset of C++ and knows about the ``importcpp`` pragma pattern language. It is not necessary to know all the details described here. - + Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the ``importcpp`` pragma can be used to import `C++`:idx: methods or C++ symbols -in general. The generated code then uses the C++ method calling +in general. The generated code then uses the C++ method calling syntax: ``obj->method(arg)``. In combination with the ``header`` and ``emit`` pragmas this allows *sloppy* interfacing with libraries written in C++: - -.. code-block:: Nim - # Horrible example of how to interface with a C++ engine ... ;-) - - {.link: "/usr/lib/libIrrlicht.so".} - - {.emit: """ - using namespace irr; - using namespace core; - using namespace scene; - using namespace video; - using namespace io; - using namespace gui; - """.} - - const - irr = "<irrlicht/irrlicht.h>" - - type + +.. code-block:: Nim + # Horrible example of how to interface with a C++ engine ... ;-) + + {.link: "/usr/lib/libIrrlicht.so".} + + {.emit: """ + using namespace irr; + using namespace core; + using namespace scene; + using namespace video; + using namespace io; + using namespace gui; + """.} + + const + irr = "<irrlicht/irrlicht.h>" + + type IrrlichtDeviceObj {.final, header: irr, - importcpp: "IrrlichtDevice".} = object - IrrlichtDevice = ptr IrrlichtDeviceObj - - proc createDevice(): IrrlichtDevice {. - header: irr, importcpp: "createDevice(@)".} - proc run(device: IrrlichtDevice): bool {. + importcpp: "IrrlichtDevice".} = object + IrrlichtDevice = ptr IrrlichtDeviceObj + + proc createDevice(): IrrlichtDevice {. + header: irr, importcpp: "createDevice(@)".} + proc run(device: IrrlichtDevice): bool {. header: irr, importcpp: "#.run(@)".} - -The compiler needs to be told to generate C++ (command ``cpp``) for -this to work. The conditional symbol ``cpp`` is defined when the compiler + +The compiler needs to be told to generate C++ (command ``cpp``) for +this to work. The conditional symbol ``cpp`` is defined when the compiler emits C++ code. @@ -446,9 +441,9 @@ declarations. It is usually much better to instead refer to the imported name via the ``namespace::identifier`` notation: .. code-block:: nim - type + type IrrlichtDeviceObj {.final, header: irr, - importcpp: "irr::IrrlichtDevice".} = object + importcpp: "irr::IrrlichtDevice".} = object Importcpp for enums @@ -574,7 +569,7 @@ language for object types: type StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {. - importcpp: "#[#] = #".} + importcpp: "#[#] = #", header: "<map>".} var x: StdMap[cint, cdouble] x[6] = 91.4 @@ -586,61 +581,61 @@ Produces: std::map<int, double> x; x[6] = 91.4; - -ImportObjC pragma ------------------ + +ImportObjC pragma +----------------- Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the ``importobjc`` pragma can be used to import `Objective C`:idx: methods. The generated code then uses the Objective C method calling syntax: ``[obj method param1: arg]``. In addition with the ``header`` and ``emit`` pragmas this allows *sloppy* interfacing with libraries written in Objective C: - -.. code-block:: Nim - # horrible example of how to interface with GNUStep ... - - {.passL: "-lobjc".} - {.emit: """ - #include <objc/Object.h> - @interface Greeter:Object - { - } - - - (void)greet:(long)x y:(long)dummy; - @end - - #include <stdio.h> - @implementation Greeter - - - (void)greet:(long)x y:(long)dummy - { - printf("Hello, World!\n"); - } - @end - - #include <stdlib.h> - """.} - - type - Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int - - proc newGreeter: Id {.importobjc: "Greeter new", nodecl.} - proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.} - proc free(self: Id) {.importobjc: "free", nodecl.} - - var g = newGreeter() - g.greet(12, 34) - g.free() - -The compiler needs to be told to generate Objective C (command ``objc``) for -this to work. The conditional symbol ``objc`` is defined when the compiler -emits Objective C code. + +.. code-block:: Nim + # horrible example of how to interface with GNUStep ... + + {.passL: "-lobjc".} + {.emit: """ + #include <objc/Object.h> + @interface Greeter:Object + { + } + + - (void)greet:(long)x y:(long)dummy; + @end + + #include <stdio.h> + @implementation Greeter + + - (void)greet:(long)x y:(long)dummy + { + printf("Hello, World!\n"); + } + @end + + #include <stdlib.h> + """.} + + type + Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int + + proc newGreeter: Id {.importobjc: "Greeter new", nodecl.} + proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.} + proc free(self: Id) {.importobjc: "free", nodecl.} + + var g = newGreeter() + g.greet(12, 34) + g.free() + +The compiler needs to be told to generate Objective C (command ``objc``) for +this to work. The conditional symbol ``objc`` is defined when the compiler +emits Objective C code. CodegenDecl pragma ------------------ The ``codegenDecl`` pragma can be used to directly influence Nim's code -generator. It receives a format string that determines how the variable or +generator. It receives a format string that determines how the variable or proc is declared in the generated code: .. code-block:: nim @@ -660,56 +655,56 @@ debugging: .. code-block:: nim {.injectStmt: gcInvariants().} - + # ... complex code here that produces crashes ... - - -LineDir option --------------- -The ``lineDir`` option can be turned on or off. If turned on the -generated C code contains ``#line`` directives. This may be helpful for -debugging with GDB. - - -StackTrace option ------------------ -If the ``stackTrace`` option is turned on, the generated C contains code to -ensure that proper stack traces are given if the program crashes or an -uncaught exception is raised. - - -LineTrace option ----------------- -The ``lineTrace`` option implies the ``stackTrace`` option. If turned on, -the generated C contains code to ensure that proper stack traces with line -number information are given if the program crashes or an uncaught exception -is raised. - -Debugger option ---------------- -The ``debugger`` option enables or disables the *Embedded Nim Debugger*. -See the documentation of endb_ for further information. - - -Breakpoint pragma ------------------ -The *breakpoint* pragma was specially added for the sake of debugging with -ENDB. See the documentation of `endb <endb.html>`_ for further information. - - -Volatile pragma ---------------- -The ``volatile`` pragma is for variables only. It declares the variable as -``volatile``, whatever that means in C/C++ (its semantics are not well defined -in C/C++). - -**Note**: This pragma will not exist for the LLVM backend. + + +LineDir option +-------------- +The ``lineDir`` option can be turned on or off. If turned on the +generated C code contains ``#line`` directives. This may be helpful for +debugging with GDB. + + +StackTrace option +----------------- +If the ``stackTrace`` option is turned on, the generated C contains code to +ensure that proper stack traces are given if the program crashes or an +uncaught exception is raised. + + +LineTrace option +---------------- +The ``lineTrace`` option implies the ``stackTrace`` option. If turned on, +the generated C contains code to ensure that proper stack traces with line +number information are given if the program crashes or an uncaught exception +is raised. + +Debugger option +--------------- +The ``debugger`` option enables or disables the *Embedded Nim Debugger*. +See the documentation of endb_ for further information. + + +Breakpoint pragma +----------------- +The *breakpoint* pragma was specially added for the sake of debugging with +ENDB. See the documentation of `endb <endb.html>`_ for further information. + + +Volatile pragma +--------------- +The ``volatile`` pragma is for variables only. It declares the variable as +``volatile``, whatever that means in C/C++ (its semantics are not well defined +in C/C++). + +**Note**: This pragma will not exist for the LLVM backend. DynlibOverride ============== -By default Nim's ``dynlib`` pragma causes the compiler to generate +By default Nim's ``dynlib`` pragma causes the compiler to generate ``GetProcAddress`` (or their Unix counterparts) calls to bind to a DLL. With the ``dynlibOverride`` command line switch this can be prevented and then via ``--passL`` the static library can be linked @@ -736,28 +731,28 @@ Nim provides the `doc`:idx: and `doc2`:idx: commands to generate HTML documentation from ``.nim`` source files. Only exported symbols will appear in the output. For more details `see the docgen documentation <docgen.html>`_. -Nim idetools integration -======================== - -Nim provides language integration with external IDEs through the -idetools command. See the documentation of `idetools <idetools.html>`_ -for further information. - - -Nim interactive mode -==================== - -The Nim compiler supports an interactive mode. This is also known as -a `REPL`:idx: (*read eval print loop*). If Nim has been built with the -``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal -input management. To start Nim in interactive mode use the command -``nim i``. To quit use the ``quit()`` command. To determine whether an input -line is an incomplete statement to be continued these rules are used: - -1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace). -2. The line starts with a space (indentation). -3. The line is within a triple quoted string literal. However, the detection - does not work if the line contains more than one ``"""``. +Nim idetools integration +======================== + +Nim provides language integration with external IDEs through the +idetools command. See the documentation of `idetools <idetools.html>`_ +for further information. + + +Nim interactive mode +==================== + +The Nim compiler supports an interactive mode. This is also known as +a `REPL`:idx: (*read eval print loop*). If Nim has been built with the +``-d:useGnuReadline`` switch, it uses the GNU readline library for terminal +input management. To start Nim in interactive mode use the command +``nim i``. To quit use the ``quit()`` command. To determine whether an input +line is an incomplete statement to be continued these rules are used: + +1. The line ends with ``[-+*/\\<>!\?\|%&$@~,;:=#^]\s*$`` (operator symbol followed by optional whitespace). +2. The line starts with a space (indentation). +3. The line is within a triple quoted string literal. However, the detection + does not work if the line contains more than one ``"""``. Nim for embedded systems @@ -768,107 +763,107 @@ for 16bit micro controllers is feasible. Use the `standalone`:idx: target (``--os:standalone``) for a bare bones standard library that lacks any OS features. -To make the compiler output code for a 16bit target use the ``--cpu:avr`` +To make the compiler output code for a 16bit target use the ``--cpu:avr`` target. For example, to generate code for an `AVR`:idx: processor use this command:: - + nim c --cpu:avr --os:standalone --deadCodeElim:on --genScript x.nim For the ``standalone`` target one needs to provide a file ``panicoverride.nim``. See ``tests/manyloc/standalone/panicoverride.nim`` for an example implementation. - + Nim for realtime systems ======================== -See the documentation of Nim's soft realtime `GC <gc.html>`_ for further +See the documentation of Nim's soft realtime `GC <gc.html>`_ for further information. - -Debugging with Nim -================== - -Nim comes with its own *Embedded Nim Debugger*. See -the documentation of endb_ for further information. - - -Optimizing for Nim -================== - -Nim has no separate optimizer, but the C code that is produced is very -efficient. Most C compilers have excellent optimizers, so usually it is -not needed to optimize one's code. Nim has been designed to encourage -efficient code: The most readable code in Nim is often the most efficient -too. - -However, sometimes one has to optimize. Do it in the following order: - -1. switch off the embedded debugger (it is **slow**!) -2. turn on the optimizer and turn off runtime checks -3. profile your code to find where the bottlenecks are -4. try to find a better algorithm -5. do low-level optimizations - -This section can only help you with the last item. - - -Optimizing string handling --------------------------- - -String assignments are sometimes expensive in Nim: They are required to -copy the whole string. However, the compiler is often smart enough to not copy -strings. Due to the argument passing semantics, strings are never copied when -passed to subroutines. The compiler does not copy strings that are a result from -a procedure call, because the callee returns a new string anyway. -Thus it is efficient to do: - -.. code-block:: Nim - var s = procA() # assignment will not copy the string; procA allocates a new - # string already - -However it is not efficient to do: - -.. code-block:: Nim - var s = varA # assignment has to copy the whole string into a new buffer! - -For ``let`` symbols a copy is not always necessary: - -.. code-block:: Nim - let s = varA # may only copy a pointer if it safe to do so - - -If you know what you're doing, you can also mark single string (or sequence) -objects as `shallow`:idx:\: - -.. code-block:: Nim - var s = "abc" - shallow(s) # mark 's' as shallow string - var x = s # now might not copy the string! - -Usage of ``shallow`` is always safe once you know the string won't be modified -anymore, similar to Ruby's `freeze`:idx:. - - -The compiler optimizes string case statements: A hashing scheme is used for them -if several different string constants are used. So code like this is reasonably -efficient: - -.. code-block:: Nim - case normalize(k.key) - of "name": c.name = v - of "displayname": c.displayName = v - of "version": c.version = v - of "os": c.oses = split(v, {';'}) - of "cpu": c.cpus = split(v, {';'}) - of "authors": c.authors = split(v, {';'}) - of "description": c.description = v - of "app": - case normalize(v) - of "console": c.app = appConsole - of "gui": c.app = appGUI - else: quit(errorStr(p, "expected: console or gui")) - of "license": c.license = UnixToNativePath(k.value) - else: quit(errorStr(p, "unknown variable: " & k.key)) + +Debugging with Nim +================== + +Nim comes with its own *Embedded Nim Debugger*. See +the documentation of endb_ for further information. + + +Optimizing for Nim +================== + +Nim has no separate optimizer, but the C code that is produced is very +efficient. Most C compilers have excellent optimizers, so usually it is +not needed to optimize one's code. Nim has been designed to encourage +efficient code: The most readable code in Nim is often the most efficient +too. + +However, sometimes one has to optimize. Do it in the following order: + +1. switch off the embedded debugger (it is **slow**!) +2. turn on the optimizer and turn off runtime checks +3. profile your code to find where the bottlenecks are +4. try to find a better algorithm +5. do low-level optimizations + +This section can only help you with the last item. + + +Optimizing string handling +-------------------------- + +String assignments are sometimes expensive in Nim: They are required to +copy the whole string. However, the compiler is often smart enough to not copy +strings. Due to the argument passing semantics, strings are never copied when +passed to subroutines. The compiler does not copy strings that are a result from +a procedure call, because the callee returns a new string anyway. +Thus it is efficient to do: + +.. code-block:: Nim + var s = procA() # assignment will not copy the string; procA allocates a new + # string already + +However it is not efficient to do: + +.. code-block:: Nim + var s = varA # assignment has to copy the whole string into a new buffer! + +For ``let`` symbols a copy is not always necessary: + +.. code-block:: Nim + let s = varA # may only copy a pointer if it safe to do so + + +If you know what you're doing, you can also mark single string (or sequence) +objects as `shallow`:idx:\: + +.. code-block:: Nim + var s = "abc" + shallow(s) # mark 's' as shallow string + var x = s # now might not copy the string! + +Usage of ``shallow`` is always safe once you know the string won't be modified +anymore, similar to Ruby's `freeze`:idx:. + + +The compiler optimizes string case statements: A hashing scheme is used for them +if several different string constants are used. So code like this is reasonably +efficient: + +.. code-block:: Nim + case normalize(k.key) + of "name": c.name = v + of "displayname": c.displayName = v + of "version": c.version = v + of "os": c.oses = split(v, {';'}) + of "cpu": c.cpus = split(v, {';'}) + of "authors": c.authors = split(v, {';'}) + of "description": c.description = v + of "app": + case normalize(v) + of "console": c.app = appConsole + of "gui": c.app = appGUI + else: quit(errorStr(p, "expected: console or gui")) + of "license": c.license = UnixToNativePath(k.value) + else: quit(errorStr(p, "unknown variable: " & k.key)) diff --git a/doc/nimgrep.txt b/doc/nimgrep.txt index e2f7b228f..2d429e8b5 100644 --- a/doc/nimgrep.txt +++ b/doc/nimgrep.txt @@ -25,9 +25,9 @@ Compile nimgrep with the command:: And copy the executable somewhere in your ``$PATH``. -Command line switches -===================== - +Command line switches +===================== + Usage: nimgrep [options] [pattern] [replacement] (file/directory)* Options: @@ -37,7 +37,7 @@ Options: --re pattern is a regular expression (default); extended syntax for the regular expression is always turned on --recursive process directories recursively - --confirm confirm each occurence/replacement; there is a chance + --confirm confirm each occurrence/replacement; there is a chance to abort any time without touching the file --stdin read pattern from stdin (to avoid the shell's confusing quoting rules) diff --git a/doc/niminst.txt b/doc/niminst.txt index d743c5187..ca05cc514 100644 --- a/doc/niminst.txt +++ b/doc/niminst.txt @@ -190,6 +190,6 @@ Real world example The installers for the Nim compiler itself are generated by niminst. Have a look at its configuration file: -.. include:: compiler/nim.ini +.. include:: compiler/installer.ini :literal: diff --git a/doc/tut1.txt b/doc/tut1.txt index b2991ba80..cb5a0c8dd 100644 --- a/doc/tut1.txt +++ b/doc/tut1.txt @@ -749,7 +749,8 @@ Forward declarations -------------------- Every variable, procedure, etc. needs to be declared before it can be used. -(The reason for this is compilation efficiency.) +(The reason for this is that it is non-trivial to do better than that in a +language that supports meta programming as extensively as Nim does.) However, this cannot be done for mutually recursive procedures: .. code-block:: nim @@ -767,7 +768,7 @@ introduced to the compiler before it is completely defined. The syntax for such a forward declaration is simple: just omit the ``=`` and the procedure's body. -Later versions of the language may get rid of the need for forward +Later versions of the language will weaken the requirements for forward declarations. The example also shows that a proc's body can consist of a single expression diff --git a/doc/tut2.txt b/doc/tut2.txt index dbf50894b..4d30b1445 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -37,7 +37,7 @@ Object Oriented Programming While Nim's support for object oriented programming (OOP) is minimalistic, powerful OOP techniques can be used. OOP is seen as *one* way to design a program, not *the only* way. Often a procedural approach leads to simpler -and more efficient code. In particular, prefering composition over inheritance +and more efficient code. In particular, preferring composition over inheritance is often the better design. @@ -142,7 +142,7 @@ An example: .. code-block:: nim - # This is an example how an abstract syntax tree could be modeled in Nim + # This is an example how an abstract syntax tree could be modelled in Nim type NodeKind = enum # the different node types nkInt, # a leaf with an integer value @@ -335,7 +335,7 @@ As the example demonstrates, invocation of a multi-method cannot be ambiguous: Collide 2 is preferred over collide 1 because the resolution works from left to right. Thus ``Unit, Thing`` is preferred over ``Thing, Unit``. -**Perfomance note**: Nim does not produce a virtual method table, but +**Performance note**: Nim does not produce a virtual method table, but generates dispatch trees. This avoids the expensive indirect branch for method calls and enables inlining. However, other optimizations like compile time evaluation or dead code elimination do not work with methods. @@ -735,14 +735,6 @@ regular expressions: return tkUnknown -Term rewriting macros ---------------------- - -Term rewriting macros can be used to enhance the compilation process -with user defined optimizations; see this `document <trmacros.html>`_ for -further information. - - Building your first macro ------------------------- diff --git a/examples/cross_calculator/android/readme.txt b/examples/cross_calculator/android/readme.txt index c04d1d304..51fa9c6fd 100644 --- a/examples/cross_calculator/android/readme.txt +++ b/examples/cross_calculator/android/readme.txt @@ -10,7 +10,7 @@ just declared as a native method which will be resolved at runtime. The scripts nimbuild.sh and jnibuild.sh are in charge of building the Nim code and generating the jni bridge from the java code respectively. Finally, the ndk-build command from the android ndk tools has to be run to build the binary -libary which will be installed along the final apk. +library which will be installed along the final apk. All these steps are wrapped in the ant build script through the customization of the -post-compile rule. If you have the android ndk tools installed and you diff --git a/examples/cross_calculator/ios/src/NRViewController.m b/examples/cross_calculator/ios/src/NRViewController.m index 1f92f2d38..f629bfc09 100644 --- a/examples/cross_calculator/ios/src/NRViewController.m +++ b/examples/cross_calculator/ios/src/NRViewController.m @@ -55,7 +55,7 @@ [self.bText resignFirstResponder]; } -/** Custom loadView method for backwards compatiblity. +/** Custom loadView method for backwards compatibility. * Unfortunately I've been unable to coerce Xcode 4.4 to generate nib files * which are compatible with my trusty iOS 3.0 ipod touch so in order to be * fully compatible for all devices we have to build the interface manually in diff --git a/examples/cross_calculator/nimrod_backend/backend.nim b/examples/cross_calculator/nim_backend/backend.nim index ffa4311f9..ffa4311f9 100644 --- a/examples/cross_calculator/nimrod_backend/backend.nim +++ b/examples/cross_calculator/nim_backend/backend.nim diff --git a/examples/cross_todo/nimrod_commandline/nimrod.cfg b/examples/cross_calculator/nim_commandline/nim.cfg index c1aedcf6a..41c034430 100644 --- a/examples/cross_todo/nimrod_commandline/nimrod.cfg +++ b/examples/cross_calculator/nim_commandline/nim.cfg @@ -1,4 +1,4 @@ # Nimrod configuration file. # The file is used only to add the path of the backend to the compiler options. -path="../nimrod_backend" +path="../nim_backend" diff --git a/examples/cross_calculator/nimrod_commandline/nimcalculator.nim b/examples/cross_calculator/nim_commandline/nimcalculator.nim index 440834ca8..69d62a90c 100644 --- a/examples/cross_calculator/nimrod_commandline/nimcalculator.nim +++ b/examples/cross_calculator/nim_commandline/nimcalculator.nim @@ -21,7 +21,7 @@ type cmdParams, # Two valid parameters were provided cmdInteractive # No parameters were provided, run interactive mode - TParamConfig = object of TObject + TParamConfig = object of RootObj action: TCommand # store the type of operation paramA, paramB: int # possibly store the valid parameters @@ -63,7 +63,7 @@ proc parseCmdLine(): TParamConfig = stdout.write USAGE quit "Unexpected option: " & key, 2 of cmdEnd: break - except EInvalidValue: + except ValueError: stdout.write USAGE quit "Invalid value " & val & " for parameter " & key, 3 @@ -85,7 +85,7 @@ proc parseUserInput(question: string): int = try: result = input.parseInt break - except EInvalidValue: + except ValueError: if input.len < 1: quit "Blank line detected, quitting.", 0 echo "Sorry, `$1' doesn't seem to be a valid integer" % input diff --git a/examples/cross_calculator/nimrod_commandline/readme.txt b/examples/cross_calculator/nim_commandline/readme.txt index 5430e7b47..f95bd962e 100644 --- a/examples/cross_calculator/nimrod_commandline/readme.txt +++ b/examples/cross_calculator/nim_commandline/readme.txt @@ -1,10 +1,10 @@ -In this directory you will find the nimrod commandline version of the +In this directory you will find the nim commandline version of the cross-calculator sample. The commandline interface can be used non interactively through switches, or interactively when running the command without parameters. Compilation is fairly easy despite having the source split in different -directories. Thanks to the nimrod.cfg file, which adds the ../nimrod_backend +directories. Thanks to the nim.cfg file, which adds the ../nim_backend directory as a search path, you can compile and run the example just fine from -the command line with 'nimrod c -r nimcalculator.nim'. +the command line with 'nim c -r nimcalculator.nim'. diff --git a/examples/cross_todo/nimrod_backend/backend.nim b/examples/cross_todo/nim_backend/backend.nim index 89e7d0b7e..5b49bc4a9 100644 --- a/examples/cross_todo/nimrod_backend/backend.nim +++ b/examples/cross_todo/nim_backend/backend.nim @@ -13,7 +13,7 @@ type text*: string ## Description of the task to do. priority*: int ## The priority can be any user defined integer. isDone*: bool ## Done todos are still kept marked. - modificationDate: TTime ## The modification time can't be modified from + modificationDate: Time ## The modification time can't be modified from ## outside of this module, use the ## getModificationDate accessor. @@ -64,7 +64,7 @@ proc openDatabase*(path: string): TDbConn = # - Procs related to TTodo objects # proc initFromDB(id: int64; text: string; priority: int, isDone: bool; - modificationDate: TTime): TTodo = + modificationDate: Time): TTodo = ## Returns an initialized TTodo object created from database parameters. ## ## The proc assumes all values are right. Note this proc is NOT exported. @@ -81,7 +81,7 @@ proc getId*(todo: TTodo): int64 = return todo.id -proc getModificationDate*(todo: TTodo): TTime = +proc getModificationDate*(todo: TTodo): Time = ## Returns the last modification date of a TTodo entry. return todo.modificationDate @@ -91,7 +91,7 @@ proc update*(todo: var TTodo; conn: TDbConn): bool = ## ## Use this method if you (or another entity) have modified the database and ## want to update the object you have with whatever the database has stored. - ## Returns true if the update suceeded, or false if the object was not found + ## Returns true if the update succeeded, or false if the object was not found ## in the database any more, in which case you should probably get rid of the ## TTodo object. assert(todo.id >= 0, "The identifier of the todo entry can't be negative") @@ -99,14 +99,14 @@ proc update*(todo: var TTodo; conn: TDbConn): bool = FROM Todos WHERE id = ?""" try: - let rows = conn.GetAllRows(query, $todo.id) + let rows = conn.getAllRows(query, $todo.id) if len(rows) < 1: return assert(1 == len(rows), "Woah, didn't expect so many rows") todo.text = rows[0][0] todo.priority = rows[0][1].parseInt todo.isDone = rows[0][2].parseBool - todo.modificationDate = TTime(rows[0][3].parseInt) + todo.modificationDate = Time(rows[0][3].parseInt) result = true except: echo("Something went wrong selecting for id " & $todo.id) @@ -202,12 +202,12 @@ proc getPagedTodos*(conn: TDbConn; params: TPagedParams; #echo("Query " & string(query)) #echo("args: " & args.join(", ")) - var newId: biggestInt + var newId: BiggestInt for row in conn.fastRows(query, args): let numChars = row[0].parseBiggestInt(newId) assert(numChars > 0, "Huh, couldn't parse identifier from database?") result.add(initFromDB(int64(newId), row[1], row[2].parseInt, - row[3].parseBool, TTime(row[4].parseInt))) + row[3].parseBool, Time(row[4].parseInt))) proc getTodo*(conn: TDbConn; todoId: int64): ref TTodo = diff --git a/examples/cross_todo/nimrod_backend/readme.txt b/examples/cross_todo/nim_backend/readme.txt index 6529f2e67..16cb592fc 100644 --- a/examples/cross_todo/nimrod_backend/readme.txt +++ b/examples/cross_todo/nim_backend/readme.txt @@ -1,4 +1,4 @@ -This directory contains the nimrod backend code for the todo cross platform +This directory contains the nim backend code for the todo cross platform example. Unlike the cross platform calculator example, this backend features more code, @@ -8,7 +8,7 @@ The test is not embedded directly in the backend.nim file to avoid being able to access internal data types and procs not exported and replicate the environment of client code. -In a bigger project with several people you could run `nimrod doc backend.nim` +In a bigger project with several people you could run `nim doc backend.nim` (or use the doc2 command for a whole project) and provide the generated html documentation to another programer for her to implement an interface without having to look at the source code. diff --git a/examples/cross_todo/nimrod_backend/testbackend.nim b/examples/cross_todo/nim_backend/testbackend.nim index 131dda1cf..131dda1cf 100644 --- a/examples/cross_todo/nimrod_backend/testbackend.nim +++ b/examples/cross_todo/nim_backend/testbackend.nim diff --git a/examples/cross_calculator/nimrod_commandline/nimrod.cfg b/examples/cross_todo/nim_commandline/nim.cfg index c1aedcf6a..41c034430 100644 --- a/examples/cross_calculator/nimrod_commandline/nimrod.cfg +++ b/examples/cross_todo/nim_commandline/nim.cfg @@ -1,4 +1,4 @@ # Nimrod configuration file. # The file is used only to add the path of the backend to the compiler options. -path="../nimrod_backend" +path="../nim_backend" diff --git a/examples/cross_todo/nimrod_commandline/nimtodo.nim b/examples/cross_todo/nim_commandline/nimtodo.nim index 1067177c3..4ab17e7a2 100644 --- a/examples/cross_todo/nimrod_commandline/nimtodo.nim +++ b/examples/cross_todo/nim_commandline/nimtodo.nim @@ -69,11 +69,11 @@ template parseTodoIdAndSetCommand(newCommand: TCommand): stmt = ## Helper to parse a big todo identifier into todoId and set command. try: let numChars = val.parseBiggestInt(newId) - if numChars < 1: raise newException(EInvalidValue, "Empty string?") + if numChars < 1: raise newException(ValueError, "Empty string?") result.command = newCommand result.todoId = newId - except EOverflow: - raise newException(EInvalidValue, "Value $1 too big" % val) + except OverflowError: + raise newException(ValueError, "Value $1 too big" % val) template verifySingleCommand(actions: stmt): stmt = @@ -111,7 +111,7 @@ proc parseCmdLine(): TParamConfig = usesListParams = false p = initOptParser() key, val: TaintedString - newId: biggestInt + newId: BiggestInt result.initDefaults @@ -178,7 +178,7 @@ proc parseCmdLine(): TParamConfig = abort("Unexpected option '$1'." % [key], 6) of cmdEnd: break - except EInvalidValue: + except ValueError: abort("Invalid integer value '$1' for parameter '$2'." % [val, key], 7) if not specifiedCommand: diff --git a/examples/cross_todo/nimrod_commandline/readme.txt b/examples/cross_todo/nim_commandline/readme.txt index ca4b67521..ca4b67521 100644 --- a/examples/cross_todo/nimrod_commandline/readme.txt +++ b/examples/cross_todo/nim_commandline/readme.txt diff --git a/examples/talk/hoisting.nim b/examples/talk/hoisting.nim index df13ba2cb..54e00884f 100644 --- a/examples/talk/hoisting.nim +++ b/examples/talk/hoisting.nim @@ -14,7 +14,7 @@ template optRe{re(x)}(x: string{lit}): Regex = g template `=~`(s: string, pattern: Regex): bool = - when not definedInScope(matches): + when not declaredInScope(matches): var matches {.inject.}: array[maxSubPatterns, string] match(s, pattern, matches) diff --git a/icons/nimrod.ico b/icons/nim.ico index 58cc4314c..58cc4314c 100644 --- a/icons/nimrod.ico +++ b/icons/nim.ico Binary files differdiff --git a/icons/nim.rc b/icons/nim.rc new file mode 100644 index 000000000..c053e08e9 --- /dev/null +++ b/icons/nim.rc @@ -0,0 +1,3 @@ +nimicon ICON "nim.ico" + + diff --git a/icons/nimrod.res b/icons/nim.res index 6eddd053b..6eddd053b 100644 --- a/icons/nimrod.res +++ b/icons/nim.res Binary files differdiff --git a/icons/nimrod_icon.o b/icons/nim_icon.o index c8c364412..c8c364412 100644 --- a/icons/nimrod_icon.o +++ b/icons/nim_icon.o Binary files differdiff --git a/icons/nimrod.rc b/icons/nimrod.rc deleted file mode 100644 index 6f36b8145..000000000 --- a/icons/nimrod.rc +++ /dev/null @@ -1,3 +0,0 @@ -nimrodicon ICON "nimrod.ico" - - diff --git a/koch.nim b/koch.nim index bc7631bcc..d365262c1 100644 --- a/koch.nim +++ b/koch.nim @@ -40,7 +40,7 @@ Options: --help, -h shows this help and quits Possible Commands: boot [options] bootstraps with given command line options - install [bindir] installs to given directory + install [bindir] installs to given directory; Unix only! clean cleans Nimrod project; removes generated files web [options] generates the website and the full documentation website [options] generates only the website @@ -97,13 +97,13 @@ const compileNimInst = "-d:useLibzipSrc tools/niminst/niminst" proc csource(args: string) = - exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource compiler/nim.ini $1" % + exec("$4 cc $1 -r $3 --var:version=$2 --var:mingw=none csource compiler/installer.ini $1" % [args, VersionAsString, compileNimInst, findNim()]) proc zip(args: string) = - exec("$3 cc -r $2 --var:version=$1 --var:mingw=none scripts compiler/nim.ini" % + exec("$3 cc -r $2 --var:version=$1 --var:mingw=none scripts compiler/installer.ini" % [VersionAsString, compileNimInst, findNim()]) - exec("$# --var:version=$# --var:mingw=none zip compiler/nim.ini" % + exec("$# --var:version=$# --var:mingw=none zip compiler/installer.ini" % ["tools/niminst/niminst".exe, VersionAsString]) proc buildTool(toolname, args: string) = @@ -121,27 +121,24 @@ proc nsis(args: string) = " nsis compiler/nim") % [VersionAsString, $(sizeof(pointer)*8)]) proc install(args: string) = - exec("$# cc -r $# --var:version=$# --var:mingw=none scripts compiler/nim.ini" % + exec("$# cc -r $# --var:version=$# --var:mingw=none scripts compiler/installer.ini" % [findNim(), compileNimInst, VersionAsString]) exec("sh ./install.sh $#" % args) proc web(args: string) = - exec("$# cc -r tools/nimweb.nim $# web/nim --putenv:nimversion=$#" % + exec("$# cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" % [findNim(), args, VersionAsString]) proc website(args: string) = - exec("$# cc -r tools/nimweb.nim $# --website web/nim --putenv:nimversion=$#" % + exec("$# cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" % [findNim(), args, VersionAsString]) proc pdf(args="") = - exec("$# cc -r tools/nimweb.nim $# --pdf web/nim --putenv:nimversion=$#" % + exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" % [findNim(), args, VersionAsString]) # -------------- boot --------------------------------------------------------- -const - bootOptions = "" # options to pass to the bootstrap process - proc findStartNim: string = # we try several things before giving up: # * bin/nim @@ -180,11 +177,13 @@ proc thVersion(i: int): string = proc boot(args: string) = var output = "compiler" / "nim".exe var finalDest = "bin" / "nim".exe + # default to use the 'c' command: + let bootOptions = if args.len == 0 or args.startsWith("-"): "c" else: "" copyExe(findStartNim(), 0.thVersion) for i in 0..2: echo "iteration: ", i+1 - exec i.thVersion & " c $# $# compiler" / "nim.nim" % [bootOptions, args] + exec i.thVersion & " $# $# compiler" / "nim.nim" % [bootOptions, args] if sameFileContent(output, i.thVersion): copyExe(output, finalDest) echo "executables are equal: SUCCESS!" @@ -270,13 +269,13 @@ when defined(withUpdate): echo("Fetching updates from repo...") var pullout = execCmdEx(git & " pull origin master") if pullout[1] != 0: - quit("An error has occured.") + quit("An error has occurred.") else: if pullout[0].startsWith("Already up-to-date."): quit("No new changes fetched from the repo. " & "Local branch must be ahead of it. Exiting...") else: - quit("An error has occured.") + quit("An error has occurred.") else: echo("No repo or executable found!") @@ -360,7 +359,7 @@ of cmdArgument: of "boot": boot(op.cmdLineRest) of "clean": clean(op.cmdLineRest) of "web": web(op.cmdLineRest) - of "website": website(op.cmdLineRest) + of "website": website(op.cmdLineRest & " --googleAnalytics:UA-48159761-1") of "web0": # undocumented command for Araq-the-merciful: web(op.cmdLineRest & " --googleAnalytics:UA-48159761-1") diff --git a/koch.nimrod.cfg b/koch.nim.cfg index 1d7acf579..1d7acf579 100644 --- a/koch.nimrod.cfg +++ b/koch.nim.cfg diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 766b7b536..8a809fc84 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -21,7 +21,7 @@ type ## is performed. Deprecated, do not use anymore! AquireEffect* {.deprecated.} = object of LockEffect ## \ ## effect that denotes that some lock is - ## aquired. Deprecated, do not use anymore! + ## acquired. Deprecated, do not use anymore! ReleaseEffect* {.deprecated.} = object of LockEffect ## \ ## effect that denotes that some lock is ## released. Deprecated, do not use anymore! diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 3e0da79be..0888a8767 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1,7 +1,7 @@ # # # Nim's Runtime Library -# (c) Copyright 2013 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -15,7 +15,7 @@ include "system/inclrtl" ## .. include:: ../doc/astspec.txt type - TNimrodNodeKind* = enum + NimNodeKind* = enum nnkNone, nnkEmpty, nnkIdent, nnkSym, nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit, nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit, @@ -72,20 +72,26 @@ type nnkEnumFieldDef, nnkArglist, nnkPattern nnkReturnToken - TNimNodeKinds* = set[TNimrodNodeKind] - TNimrodTypeKind* = enum + NimNodeKinds* = set[NimNodeKind] + NimTypeKind* = enum ntyNone, ntyBool, ntyChar, ntyEmpty, ntyArrayConstr, ntyNil, ntyExpr, ntyStmt, - ntyTypeDesc, ntyGenericInvokation, ntyGenericBody, ntyGenericInst, + ntyTypeDesc, ntyGenericInvocation, ntyGenericBody, ntyGenericInst, ntyGenericParam, ntyDistinct, ntyEnum, ntyOrdinal, ntyArray, ntyObject, ntyTuple, ntySet, ntyRange, ntyPtr, ntyRef, ntyVar, ntySequence, ntyProc, ntyPointer, ntyOpenArray, ntyString, ntyCString, ntyForward, ntyInt, ntyInt8, ntyInt16, ntyInt32, ntyInt64, - ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128 - TNimTypeKinds* = set[TNimrodTypeKind] - TNimrodSymKind* = enum + ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128, + ntyUInt, ntyUInt8, ntyUInt16, ntyUInt32, ntyUInt64, + ntyBigNum, + ntyConst, ntyMutable, ntyVarargs, + ntyIter, + ntyError + + TNimTypeKinds* {.deprecated.} = set[NimTypeKind] + NimSymKind* = enum nskUnknown, nskConditional, nskDynLib, nskParam, nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet, nskConst, nskResult, @@ -94,22 +100,28 @@ type nskEnumField, nskForVar, nskLabel, nskStub - TNimSymKinds* = set[TNimrodSymKind] + TNimSymKinds* {.deprecated.} = set[NimSymKind] type - TNimrodIdent* = object of RootObj - ## represents a Nimrod identifier in the AST + NimIdent* = object of RootObj + ## represents a Nim identifier in the AST - TNimrodSymbol {.final.} = object # hidden - PNimrodSymbol* {.compilerproc.} = ref TNimrodSymbol - ## represents a Nimrod *symbol* in the compiler; a *symbol* is a looked-up + NimSymObj = object # hidden + NimSym* = ref NimSymObj + ## represents a Nim *symbol* in the compiler; a *symbol* is a looked-up ## *ident*. +{.deprecated: [TNimrodNodeKind: NimNodeKind, TNimNodeKinds: NimNodeKinds, + TNimrodTypeKind: NimTypeKind, TNimrodSymKind: NimSymKind, + TNimrodIdent: NimIdent, PNimrodSymbol: NimSym].} + const nnkLiterals* = {nnkCharLit..nnkNilLit} nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallStrLit} +{.push warning[deprecated]: off.} + proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild", noSideEffect.} ## get `n`'s `i`'th child. @@ -117,31 +129,31 @@ proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild", noSideEffect.} ## set `n`'s `i`'th child to `child`. -proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent", noSideEffect.} +proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.} ## constructs an identifier from the string `s` -proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr", noSideEffect.} - ## converts a Nimrod identifier to a string +proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.} + ## converts a Nim identifier to a string -proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr", noSideEffect.} - ## converts a Nimrod symbol to a string +proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.} + ## converts a Nim symbol to a string -proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.} - ## compares two Nimrod identifiers +proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect.} + ## compares two Nim identifiers proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.} - ## compares two Nimrod nodes + ## compares two Nim nodes proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.} ## returns the number of children of `n`. proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable, - noSideEffect.} + noSideEffect, locks: 0.} ## Adds the `child` to the `father` node. Returns the ## father node so that calls can be nested. proc add*(father: PNimrodNode, children: varargs[PNimrodNode]): PNimrodNode {. - magic: "NAddMultiple", discardable, noSideEffect.} + magic: "NAddMultiple", discardable, noSideEffect, locks: 0.} ## Adds each child of `children` to the `father` node. ## Returns the `father` node so that calls can be nested. @@ -153,15 +165,27 @@ proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind", noSideEffect.} proc intVal*(n: PNimrodNode): BiggestInt {.magic: "NIntVal", noSideEffect.} proc floatVal*(n: PNimrodNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.} -proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol", noSideEffect.} -proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent", noSideEffect.} -proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType", noSideEffect.} +proc symbol*(n: PNimrodNode): NimSym {.magic: "NSymbol", noSideEffect.} +proc ident*(n: PNimrodNode): NimIdent {.magic: "NIdent", noSideEffect.} + +proc getType*(n: PNimrodNode): PNimrodNode {.magic: "NGetType", noSideEffect.} + ## with 'getType' you can access the node's `type`:idx:. A Nim type is + ## mapped to a Nim AST too, so it's slightly confusing but it means the same + ## API can be used to traverse types. Recursive types are flattened for you + ## so there is no danger of infinite recursions during traversal. To + ## resolve recursive types, you have to call 'getType' again. To see what + ## kind of type it is, call `typeKind` on getType's result. + +proc typeKind*(n: PNimrodNode): NimTypeKind {.magic: "NGetType", noSideEffect.} + ## Returns the type kind of the node 'n' that should represent a type, that + ## means the node should have been obtained via `getType`. + proc strVal*(n: PNimrodNode): string {.magic: "NStrVal", noSideEffect.} proc `intVal=`*(n: PNimrodNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.} proc `floatVal=`*(n: PNimrodNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.} -proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol", noSideEffect.} -proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent", noSideEffect.} +proc `symbol=`*(n: PNimrodNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect.} +proc `ident=`*(n: PNimrodNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.} #proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".} # this is not sound! Unfortunately forbidding 'typ=' is not enough, as you # can easily do: @@ -177,13 +201,13 @@ proc newNimNode*(kind: TNimrodNodeKind, proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode", noSideEffect.} proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree", noSideEffect.} -proc error*(msg: string) {.magic: "NError", gcsafe.} +proc error*(msg: string) {.magic: "NError", benign.} ## writes an error message at compile time -proc warning*(msg: string) {.magic: "NWarning", gcsafe.} +proc warning*(msg: string) {.magic: "NWarning", benign.} ## writes a warning message at compile time -proc hint*(msg: string) {.magic: "NHint", gcsafe.} +proc hint*(msg: string) {.magic: "NHint", benign.} ## writes a hint message at compile time proc newStrLitNode*(s: string): PNimrodNode {.compileTime, noSideEffect.} = @@ -201,7 +225,7 @@ proc newFloatLitNode*(f: BiggestFloat): PNimrodNode {.compileTime.} = result = newNimNode(nnkFloatLit) result.floatVal = f -proc newIdentNode*(i: TNimrodIdent): PNimrodNode {.compileTime.} = +proc newIdentNode*(i: NimIdent): PNimrodNode {.compileTime.} = ## creates an identifier node from `i` result = newNimNode(nnkIdent) result.ident = i @@ -212,7 +236,7 @@ proc newIdentNode*(i: string): PNimrodNode {.compileTime.} = result.ident = !i type - TBindSymRule* = enum ## specifies how ``bindSym`` behaves + BindSymRule* = enum ## specifies how ``bindSym`` behaves brClosed, ## only the symbols in current scope are bound brOpen, ## open wrt overloaded symbols, but may be a single ## symbol if not ambiguous (the rules match that of @@ -221,7 +245,9 @@ type ## if not ambiguous (this cannot be achieved with ## any other means in the language currently) -proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {. +{.deprecated: [TBindSymRule: BindSymRule].} + +proc bindSym*(ident: string, rule: BindSymRule = brClosed): PNimrodNode {. magic: "NBindSym", noSideEffect.} ## creates a node that binds `ident` to a symbol node. The bound symbol ## may be an overloaded symbol. @@ -232,16 +258,16 @@ proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {. ## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is ## returned even if the symbol is not ambiguous. -proc genSym*(kind: TNimrodSymKind = nskLet; ident = ""): PNimrodNode {. +proc genSym*(kind: NimSymKind = nskLet; ident = ""): PNimrodNode {. magic: "NGenSym", noSideEffect.} ## generates a fresh symbol that is guaranteed to be unique. The symbol ## needs to occur in a declaration context. -proc callsite*(): PNimrodNode {.magic: "NCallSite", gcsafe.} - ## returns the AST if the invokation expression that invoked this macro. +proc callsite*(): PNimrodNode {.magic: "NCallSite", benign.} + ## returns the AST of the invocation expression that invoked this macro. proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} = - ## converts the AST `n` to the concrete Nimrod code and wraps that + ## converts the AST `n` to the concrete Nim code and wraps that ## in a string literal node return newStrLitNode(repr(n)) @@ -317,7 +343,7 @@ proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} = ## checks that `n` is of kind `k`. If this is not the case, ## compilation aborts with an error message. This is useful for writing ## macros that check the AST that is passed to them. - if n.kind != k: error("macro expects a node of kind: " & $k) + if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind) proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} = ## checks that `n` has at least `min` children. If this is not the case, @@ -339,7 +365,7 @@ proc newCall*(theProc: PNimrodNode, result.add(theProc) result.add(args) -proc newCall*(theProc: TNimrodIdent, +proc newCall*(theProc: NimIdent, args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} = ## produces a new call node. `theProc` is the proc that is called with ## the arguments ``args[0..]``. @@ -375,7 +401,7 @@ proc newLit*(s: string): PNimrodNode {.compileTime.} = result = newNimNode(nnkStrLit) result.strVal = s -proc nestList*(theProc: TNimrodIdent, +proc nestList*(theProc: NimIdent, x: PNimrodNode): PNimrodNode {.compileTime.} = ## nests the list `x` into a tree of call expressions: ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``. @@ -387,11 +413,11 @@ proc nestList*(theProc: TNimrodIdent, # This could easily user code and so should be fixed in evals.nim somehow. result = newCall(theProc, x[i], copyNimTree(result)) -proc treeRepr*(n: PNimrodNode): string {.compileTime.} = +proc treeRepr*(n: PNimrodNode): string {.compileTime, benign.} = ## Convert the AST `n` to a human-readable tree-like string. ## ## See also `repr` and `lispRepr`. - proc traverse(res: var string, level: int, n: PNimrodNode) = + proc traverse(res: var string, level: int, n: PNimrodNode) {.benign.} = for i in 0..level-1: res.add " " res.add(($n.kind).substr(3)) @@ -412,7 +438,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} = result = "" traverse(result, 0, n) -proc lispRepr*(n: PNimrodNode): string {.compileTime.} = +proc lispRepr*(n: PNimrodNode): string {.compileTime, benign.} = ## Convert the AST `n` to a human-readable lisp-like string, ## ## See also `repr` and `treeRepr`. @@ -430,10 +456,11 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} = of nnkSym: add(result, $n.symbol) of nnkNone: assert false else: - add(result, lispRepr(n[0])) - for j in 1..n.len-1: - add(result, ", ") - add(result, lispRepr(n[j])) + if n.len > 0: + add(result, lispRepr(n[0])) + for j in 1..n.len-1: + add(result, ", ") + add(result, lispRepr(n[j])) add(result, ")") @@ -554,10 +581,8 @@ const CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallStrLit, nnkHiddenCallConv} -from strutils import cmpIgnoreStyle, format - proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} = - assert n.kind in k, "Expected one of $1, got $2".format(k, n.kind) + assert n.kind in k, "Expected one of " & $k & ", got " & $n.kind proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()]; body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} = @@ -627,7 +652,7 @@ proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}= template badNodeKind(k; f): stmt{.immediate.} = - assert false, "Invalid node kind $# for macros.`$2`".format(k, f) + assert false, "Invalid node kind " & $k & " for macros.`" & $f & "`" proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} = case someProc.kind: @@ -651,7 +676,7 @@ proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} = else: badNodeKind someProc.kind, "body=" -proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.} +proc basename*(a: PNimrodNode): PNimrodNode {.compiletime, benign.} proc `$`*(node: PNimrodNode): string {.compileTime.} = @@ -749,6 +774,22 @@ proc copy*(node: PNimrodNode): PNimrodNode {.compileTime.} = ## An alias for copyNimTree(). return node.copyNimTree() +proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} = + proc toLower(c: char): char {.inline.} = + if c in {'A'..'Z'}: result = chr(ord(c) + (ord('a') - ord('A'))) + else: result = c + var i = 0 + var j = 0 + while true: + while a[i] == '_': inc(i) + while b[j] == '_': inc(j) # BUGFIX: typo + var aa = toLower(a[i]) + var bb = toLower(b[j]) + result = ord(aa) - ord(bb) + if result != 0 or aa == '\0': break + inc(i) + inc(j) + proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0 ## Check if two idents are identical. @@ -784,3 +825,5 @@ when not defined(booting): macro payload: stmt {.gensym.} = result = parseStmt(e) payload() + +{.pop.} diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 0046924a1..c3ff66591 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -66,9 +66,9 @@ type ppointer = ptr pointer pbyteArray = ptr array[0.. 0xffff, int8] - TGenSeq = object + TGenericSeq {.importc.} = object len, space: int - PGenSeq = ptr TGenSeq + PGenSeq = ptr TGenericSeq const GenericSeqSize = (2 * sizeof(int)) diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index 968a2923a..dab84c2d5 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -16,11 +16,11 @@ type TDbConn* = PMySQL ## encapsulates a database connection TRow* = seq[string] ## a row of a dataset. NULL database values will be ## transformed always to the empty string. - EDb* = object of EIO ## exception that is raised if a database error occurs + EDb* = object of IOError ## exception that is raised if a database error occurs TSqlQuery* = distinct string ## an SQL query string - FDb* = object of FIO ## effect that denotes a database operation + FDb* = object of IOEffect ## effect that denotes a database operation FReadDb* = object of FDb ## effect that denotes a read operation FWriteDb* = object of FDb ## effect that denotes a write operation diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 07ef13fd9..aaf2ed1ca 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -1,7 +1,7 @@ # # # Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -13,6 +13,8 @@ ## is used. This suffices because Windows' console already provides the ## wanted functionality. +{.deadCodeElim: on.} + when defined(Windows): proc readLineFromStdin*(prompt: string): TaintedString {. tags: [ReadIOEffect, WriteIOEffect].} = @@ -31,9 +33,31 @@ when defined(Windows): stdout.write(prompt) result = readLine(stdin, line) + proc readPasswordFromStdin*(prompt: string, password: var TaintedString): + bool {.tags: [ReadIOEffect, WriteIOEffect].} = + ## Reads a `password` from stdin without printing it. `password` must not + ## be ``nil``! Returns ``false`` if the end of the file has been reached, + ## ``true`` otherwise. + proc getch(): cint {.header: "<conio.h>", importc: "_getch".} + + password.setLen(0) + var c: char + stdout.write(prompt) + while true: + c = getch().char + case c + of '\r', chr(0xA): + break + of '\b': + password.setLen(password.len - 1) + else: + password.add(c) + stdout.write "\n" + # TODO: How to detect EOF on Windows? + else: - import readline, history - + import readline, history, termios, unsigned + proc readLineFromStdin*(prompt: string): TaintedString {. tags: [ReadIOEffect, WriteIOEffect].} = var buffer = readline.readLine(prompt) @@ -55,8 +79,26 @@ else: result = true # initialization: - # disable auto-complete: + # disable auto-complete: proc doNothing(a, b: cint): cint {.cdecl, procvar.} = discard - + discard readline.bind_key('\t'.ord, doNothing) + proc readPasswordFromStdin*(prompt: string, password: var TaintedString): + bool {.tags: [ReadIOEffect, WriteIOEffect].} = + password.setLen(0) + let fd = stdin.getFileHandle() + var cur, old: Termios + discard fd.tcgetattr(cur.addr) + old = cur + cur.lflag = cur.lflag and not Tcflag(ECHO) + discard fd.tcsetattr(TCSADRAIN, cur.addr) + stdout.write prompt + result = stdin.readLine(password) + stdout.write "\n" + discard fd.tcsetattr(TCSADRAIN, old.addr) + +proc readPasswordFromStdin*(prompt: string): TaintedString = + ## Reads a password from stdin without printing it. + result = TaintedString("") + discard readPasswordFromStdin(prompt, result) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index a7bebb81c..7d5ff8948 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -9,6 +9,12 @@ ## Regular expression support for Nim. Consider using the pegs module ## instead. +## +## **Note:** The 're' proc defaults to the **extended regular expression +## syntax** which lets you use whitespace freely to make your regexes readable. +## However, this means to match whitespace ``\s`` or something similar has +## to be used. +## ## This module is implemented by providing a wrapper around the ## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_ ## C library. This means that your application will depend on the PRCE diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 91b260a64..870213db3 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -55,6 +55,7 @@ type status*: cstring toolbar*: ref TToolBar + addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.} alert*: proc (msg: cstring) {.nimcall.} back*: proc () {.nimcall.} blur*: proc () {.nimcall.} @@ -91,6 +92,7 @@ type TFrame* {.importc.} = object of TWindow TDocument* {.importc.} = object of TEventHandlers + addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent) ) {.nimcall.} alinkColor*: cstring bgColor*: cstring charset*: cstring @@ -110,6 +112,7 @@ type getElementById*: proc (id: cstring): ref TNode {.nimcall.} getElementsByName*: proc (name: cstring): seq[ref TNode] {.nimcall.} getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.} + getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.} getSelection*: proc (): cstring {.nimcall.} handleEvent*: proc (event: ref TEvent) {.nimcall.} open*: proc () {.nimcall.} @@ -196,6 +199,12 @@ type width*: int handleEvent*: proc (event: ref TEvent) {.nimcall.} + ClassList* {.importc.} = object of RootObj + add*: proc (class: cstring) {.nimcall.} + remove*: proc (class: cstring) {.nimcall.} + contains*: proc (class: cstring):bool {.nimcall.} + toggle*: proc (class: cstring) {.nimcall.} + TNodeType* = enum ElementNode = 1, AttributeNode, @@ -212,6 +221,8 @@ type TNode* {.importc.} = object of RootObj attributes*: seq[ref TNode] childNodes*: seq[ref TNode] + children*: seq[ref TNode] + classList*: ref Classlist data*: cstring firstChild*: ref TNode lastChild*: ref TNode @@ -223,20 +234,23 @@ type previousSibling*: ref TNode appendChild*: proc (child: ref TNode) {.nimcall.} appendData*: proc (data: cstring) {.nimcall.} - cloneNode*: proc (copyContent: bool) {.nimcall.} + cloneNode*: proc (copyContent: bool): ref TNode {.nimcall.} deleteData*: proc (start, len: int) {.nimcall.} getAttribute*: proc (attr: cstring): cstring {.nimcall.} getAttributeNode*: proc (attr: cstring): ref TNode {.nimcall.} - getElementsByTagName*: proc (): seq[ref TNode] {.nimcall.} + getElementsByTagName*: proc (name: cstring): seq[ref TNode] {.nimcall.} + getElementsByClassName*: proc (name: cstring): seq[ref TNode] {.nimcall.} hasChildNodes*: proc (): bool {.nimcall.} innerHTML*: cstring insertBefore*: proc (newNode, before: ref TNode) {.nimcall.} insertData*: proc (position: int, data: cstring) {.nimcall.} + addEventListener*: proc(ev: cstring, cb: proc(ev: ref TEvent)) {.nimcall.} removeAttribute*: proc (attr: cstring) {.nimcall.} removeAttributeNode*: proc (attr: ref TNode) {.nimcall.} removeChild*: proc (child: ref TNode) {.nimcall.} replaceChild*: proc (newNode, oldNode: ref TNode) {.nimcall.} replaceData*: proc (start, len: int, text: cstring) {.nimcall.} + scrollIntoView*: proc () {.nimcall.} setAttribute*: proc (name, value: cstring) {.nimcall.} setAttributeNode*: proc (attr: ref TNode) {.nimcall.} style*: ref TStyle @@ -336,6 +350,7 @@ type setAttribute*: proc (attr, value: cstring, caseSensitive=false) {.nimcall.} TEvent* {.importc.} = object of RootObj + target*: ref TNode altKey*, ctrlKey*, shiftKey*: bool button*: int clientX*, clientY*: int @@ -450,3 +465,4 @@ proc isFinite*(x: BiggestFloat): bool {.importc, nodecl.} proc isNaN*(x: BiggestFloat): bool {.importc, nodecl.} proc parseFloat*(s: cstring): BiggestFloat {.importc, nodecl.} proc parseInt*(s: cstring): int {.importc, nodecl.} +proc parseInt*(s: cstring, radix: int):int {.importc, nodecl.} diff --git a/lib/nimbase.h b/lib/nimbase.h index b72e60ac2..50c7968ac 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -379,7 +379,7 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); } # define GC_GUARD #endif -/* Test to see if nimrod and the C compiler agree on the size of a pointer. +/* Test to see if Nim and the C compiler agree on the size of a pointer. On disagreement, your C compiler will say something like: "error: 'assert_numbits' declared as an array with a negative size" */ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof(NI)*8 ? 1 : -1]; @@ -390,3 +390,12 @@ typedef int assert_numbits[sizeof(NI) == sizeof(void*) && NIM_INTBITS == sizeof( #else # define NIM_EXTERNC #endif + +/* ---------------- platform specific includes ----------------------- */ + +/* VxWorks related includes */ +#if defined(__VXWORKS__) +# include <sys/types.h> +# include <types/vxWind.h> +# include <tool/gnu/toolMacros.h> +#endif diff --git a/lib/nimrtl.nimrod.cfg b/lib/nimrtl.nim.cfg index b60de183a..b60de183a 100644 --- a/lib/nimrtl.nimrod.cfg +++ b/lib/nimrtl.nim.cfg diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 14614b2ed..e1e590877 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1145,7 +1145,7 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string], proc defaultConfig*(): StringTableRef = ## Returns a default configuration for embedded HTML generation. ## - ## The returned ``StringTableRef`` contains the paramters used by the HTML + ## The returned ``StringTableRef`` contains the parameters used by the HTML ## engine to build the final output. For information on what these parameters ## are and their purpose, please look up the file ``config/nimdoc.cfg`` ## bundled with the compiler. diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index fbd07ca25..7d3e3ddba 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -70,17 +70,20 @@ const STDIN_FILENO* = 0 ## File number of stdin; STDOUT_FILENO* = 1 ## File number of stdout; -when defined(endb): - # to not break bootstrapping again ... - type - TDIR* {.importc: "DIR", header: "<dirent.h>", - final, pure, incompleteStruct.} = object - ## A type representing a directory stream. -else: - type - TDIR* {.importc: "DIR", header: "<dirent.h>", - final, pure.} = object - ## A type representing a directory stream. + DT_UNKNOWN* = 0 ## Unknown file type. + DT_FIFO* = 1 ## Named pipe, or FIFO. + DT_CHR* = 2 ## Character device. + DT_DIR* = 4 ## Directory. + DT_BLK* = 6 ## Block device. + DT_REG* = 8 ## Regular file. + DT_LNK* = 10 ## Symbolic link. + DT_SOCK* = 12 ## UNIX domain socket. + DT_WHT* = 14 + +type + TDIR* {.importc: "DIR", header: "<dirent.h>", + incompleteStruct.} = object + ## A type representing a directory stream. type SocketHandle* = distinct cint # The type used to represent socket descriptors @@ -91,6 +94,10 @@ type Tdirent* {.importc: "struct dirent", header: "<dirent.h>", final, pure.} = object ## dirent_t struct d_ino*: Tino ## File serial number. + d_off*: TOff ## Not an offset. Value that ``telldir()`` would return. + d_reclen*: cshort ## Length of this record. (not POSIX) + d_type*: int8 ## Type of file; not supported by all filesystem types. + ## (not POSIX) d_name*: array [0..255, char] ## Name of entry. Tflock* {.importc: "struct flock", final, pure, @@ -1739,12 +1746,10 @@ when hasSpawnH: when defined(linux): # better be safe than sorry; Linux has this flag, macosx doesn't, don't # know about the other OSes - when defined(tcc): - # TCC doesn't define __USE_GNU, so we can't get the magic number from - # spawn.h - const POSIX_SPAWN_USEVFORK* = cint(0x40) - else: - var POSIX_SPAWN_USEVFORK* {.importc, header: "<spawn.h>".}: cint + + # Non-GNU systems like TCC and musl-libc don't define __USE_GNU, so we + # can't get the magic number from spawn.h + const POSIX_SPAWN_USEVFORK* = cint(0x40) else: # macosx lacks this, so we define the constant to be 0 to not affect # OR'ing of flags: diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim new file mode 100644 index 000000000..830e8a207 --- /dev/null +++ b/lib/posix/termios.nim @@ -0,0 +1,264 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +{.deadCodeElim: on.} +import posix + +type + Speed* = cuint + Tcflag* = cuint + +const + NCCS* = 32 + +type + Termios* = object {.importc: "struct termios", header: "<termios.h>", final, pure.} + iflag*: Tcflag # input mode flags + oflag*: Tcflag # output mode flags + cflag*: Tcflag # control mode flags + lflag*: Tcflag # local mode flags + line*: cuchar # line discipline + cc*: array[NCCS, cuchar] # control characters + ispeed*: Speed # input speed + ospeed*: Speed # output speed + + +# cc characters + +const + VINTR* = 0 + VQUIT* = 1 + VERASE* = 2 + VKILL* = 3 + VEOF* = 4 + VTIME* = 5 + VMIN* = 6 + VSWTC* = 7 + VSTART* = 8 + VSTOP* = 9 + VSUSP* = 10 + VEOL* = 11 + VREPRINT* = 12 + VDISCARD* = 13 + VWERASE* = 14 + VLNEXT* = 15 + VEOL2* = 16 + +# iflag bits + +const + IGNBRK* = 1 + BRKINT* = 2 + IGNPAR* = 4 + PARMRK* = 10 + INPCK* = 20 + ISTRIP* = 40 + INLCR* = 100 + IGNCR* = 200 + ICRNL* = 400 + IUCLC* = 1000 + IXON* = 2000 + IXANY* = 4000 + IXOFF* = 10000 + IMAXBEL* = 20000 + IUTF8* = 40000 + +# oflag bits + +const + OPOST* = 1 + OLCUC* = 2 + ONLCR* = 4 + OCRNL* = 10 + ONOCR* = 20 + ONLRET* = 40 + OFILL* = 100 + OFDEL* = 200 + NLDLY* = 400 + NL0* = 0 + NL1* = 400 + CRDLY* = 3000 + CR0* = 0 + CR1* = 1000 + CR2* = 2000 + CR3* = 3000 + TABDLY* = 14000 + TAB0* = 0 + TAB1* = 4000 + TAB2* = 10000 + TAB3* = 14000 + BSDLY* = 20000 + BS0* = 0 + BS1* = 20000 + FFDLY* = 0o000000100000 + FF0* = 0 + FF1* = 0o000000100000 + VTDLY* = 40000 + VT0* = 0 + VT1* = 40000 + XTABS* = 14000 + +# cflag bit meaning + +const + CBAUD* = 10017 + B0* = 0 + B50* = 1 + B75* = 2 + B110* = 3 + B134* = 4 + B150* = 5 + B200* = 6 + B300* = 7 + B600* = 10 + B1200* = 11 + B1800* = 12 + B2400* = 13 + B4800* = 14 + B9600* = 15 + B19200* = 16 + B38400* = 17 + EXTA* = B19200 + EXTB* = B38400 + CSIZE* = 60 + CS5* = 0 + CS6* = 20 + CS7* = 40 + CS8* = 60 + CSTOPB* = 100 + CREAD* = 200 + PARENB* = 400 + PARODD* = 1000 + HUPCL* = 2000 + CLOCAL* = 4000 + CBAUDEX* = 10000 + B57600* = 10001 + B115200* = 10002 + B230400* = 10003 + B460800* = 10004 + B500000* = 10005 + B576000* = 10006 + B921600* = 10007 + B1000000* = 10010 + B1152000* = 10011 + B1500000* = 10012 + B2000000* = 10013 + B2500000* = 10014 + B3000000* = 10015 + B3500000* = 10016 + B4000000* = 10017 + MAX_BAUD* = B4000000 + CIBAUD* = 2003600000 + CMSPAR* = 0o010000000000 + CRTSCTS* = 0o020000000000 + +# lflag bits + +const + ISIG* = 1 + ICANON* = 2 + XCASE* = 4 + ECHO* = 10 + ECHOE* = 20 + ECHOK* = 40 + ECHONL* = 100 + NOFLSH* = 200 + TOSTOP* = 400 + ECHOCTL* = 1000 + ECHOPRT* = 2000 + ECHOKE* = 4000 + FLUSHO* = 10000 + PENDIN* = 40000 + IEXTEN* = 0o000000100000 + EXTPROC* = 0o000000200000 + +# tcflow() and TCXONC use these + +const + TCOOFF* = 0 + TCOON* = 1 + TCIOFF* = 2 + TCION* = 3 + +# tcflush() and TCFLSH use these + +const + TCIFLUSH* = 0 + TCOFLUSH* = 1 + TCIOFLUSH* = 2 + +# tcsetattr uses these + +const + TCSANOW* = 0 + TCSADRAIN* = 1 + TCSAFLUSH* = 2 + +# Compare a character C to a value VAL from the `cc' array in a +# `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it. + +template cceq*(val, c: expr): expr = + c == val and val != POSIX_VDISABLE + +# Return the output baud rate stored in *TERMIOS_P. + +proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed", + header: "<termios.h>".} +# Return the input baud rate stored in *TERMIOS_P. + +proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed", + header: "<termios.h>".} +# Set the output baud rate stored in *TERMIOS_P to SPEED. + +proc cfSetOspeed*(termios: ptr Termios; speed: Speed): cint {. + importc: "cfsetospeed", header: "<termios.h>".} +# Set the input baud rate stored in *TERMIOS_P to SPEED. + +proc cfSetIspeed*(termios: ptr Termios; speed: Speed): cint {. + importc: "cfsetispeed", header: "<termios.h>".} +# Set both the input and output baud rates in *TERMIOS_OP to SPEED. + +proc cfSetSpeed*(termios: ptr Termios; speed: Speed): cint {. + importc: "cfsetspeed", header: "<termios.h>".} +# Put the state of FD into *TERMIOS_P. + +proc tcGetAttr*(fd: cint; termios: ptr Termios): cint {. + importc: "tcgetattr", header: "<termios.h>".} +# Set the state of FD to *TERMIOS_P. +# Values for OPTIONAL_ACTIONS (TCSA*) are in <bits/termios.h>. + +proc tcSetAttr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {. + importc: "tcsetattr", header: "<termios.h>".} +# Set *TERMIOS_P to indicate raw mode. + +proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw", + header: "<termios.h>".} +# Send zero bits on FD. + +proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak", + header: "<termios.h>".} +# Wait for pending output to be written on FD. +# +# This function is a cancellation point and therefore not marked with +# . + +proc tcDrain*(fd: cint): cint {.importc: "tcdrain", header: "<termios.h>".} +# Flush pending data on FD. +# Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in <bits/termios.h>. + +proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush", + header: "<termios.h>".} +# Suspend or restart transmission on FD. +# Values for ACTION (TC[IO]{OFF,ON}) are in <bits/termios.h>. + +proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow", + header: "<termios.h>".} +# Get process group ID for session leader for controlling terminal FD. + +proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "<termios.h>".} diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim index f2c50ce4c..8c61ce7df 100644 --- a/lib/pure/actors.nim +++ b/lib/pure/actors.nim @@ -200,7 +200,7 @@ template schedule = if minIdx >= 0: p.actors[minIdx].i.send(t) else: - raise newException(EDeadThread, "cannot send message; thread died") + raise newException(DeadThreadError, "cannot send message; thread died") proc spawn*[TIn, TOut](p: var TActorPool[TIn, TOut], input: TIn, action: proc (input: TIn): TOut {.thread.} diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 0358a9a81..20bfc5c7c 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -220,3 +220,62 @@ proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = result.add(res) index = 0 indexes[index] -=1 + +proc nextPermutation*[T](x: var openarray[T]): bool {.discardable.} = + ## Calculates the next lexicographic permutation, directly modifying ``x``. + ## The result is whether a permutation happened, otherwise we have reached + ## the last-ordered permutation. + ## + ## .. code-block:: nim + ## + ## var v = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + ## v.nextPermutation() + ## echo v + if x.len < 2: + return false + + var i = x.high + while i > 0 and x[i-1] >= x[i]: + dec i + + if i == 0: + return false + + var j = x.high + while j >= i and x[j] <= x[i-1]: + dec j + + swap x[j], x[i-1] + x.reverse(i, x.high) + + result = true + +proc prevPermutation*[T](x: var openarray[T]): bool {.discardable.} = + ## Calculates the previous lexicographic permutation, directly modifying + ## ``x``. The result is whether a permutation happened, otherwise we have + ## reached the first-ordered permutation. + ## + ## .. code-block:: nim + ## + ## var v = @[0, 1, 2, 3, 4, 5, 6, 7, 9, 8] + ## v.prevPermutation() + ## echo v + if x.len < 2: + return false + + var i = x.high + while i > 0 and x[i-1] <= x[i]: + dec i + + if i == 0: + return false + + x.reverse(i, x.high) + + var j = x.high + while j >= i and x[j-1] < x[i-1]: + dec j + + swap x[i-1], x[j] + + result = true diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index bbd8ed895..d6ed66030 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -606,7 +606,7 @@ when defined(windows) or defined(nimdoc): retFuture.fail(newException(OSError, osErrorMsg(err))) elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0': # We have to ensure that the buffer is empty because WSARecv will tell - # us immediatelly when it was disconnected, even when there is still + # us immediately when it was disconnected, even when there is still # data in the buffer. # We want to give the user as much data as we can. So we only return # the empty string (which signals a disconnection) when there is @@ -1064,6 +1064,17 @@ proc accept*(socket: TAsyncFD, # -- Await Macro +proc skipUntilStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} = + # Skips a nest of StmtList's. + result = node + if node[0].kind == nnkStmtList: + result = skipUntilStmtList(node[0]) + +proc skipStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} = + result = node + if node[0].kind == nnkStmtList: + result = node[0] + template createCb(retFutureSym, iteratorNameSym, name: expr): stmt {.immediate.} = var nameIterVar = iteratorNameSym @@ -1211,26 +1222,53 @@ proc processBody(node, retFutureSym: PNimrodNode, of nnkTryStmt: # try: await x; except: ... result = newNimNode(nnkStmtList, node) + template wrapInTry(n, tryBody: PNimrodNode) = + var temp = n + n[0] = tryBody + tryBody = temp + + # Transform ``except`` body. + # TODO: Could we perform some ``await`` transformation here to get it + # working in ``except``? + tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil) + proc processForTry(n: PNimrodNode, i: var int, res: PNimrodNode): bool {.compileTime.} = + ## Transforms the body of the tryStmt. Does not transform the + ## body in ``except``. + ## Returns true if the tryStmt node was transformed into an ifStmt. result = false - while i < n[0].len: - var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n) - if processed.kind != n[0][i].kind or processed.len != n[0][i].len: + var skipped = n.skipStmtList() + while i < skipped.len: + var processed = processBody(skipped[i], retFutureSym, + subTypeIsVoid, n) + + # Check if we transformed the node into an exception check. + # This suggests skipped[i] contains ``await``. + if processed.kind != skipped[i].kind or processed.len != skipped[i].len: + processed = processed.skipUntilStmtList() expectKind(processed, nnkStmtList) expectKind(processed[2][1], nnkElse) i.inc - discard processForTry(n, i, processed[2][1][0]) + + if not processForTry(n, i, processed[2][1][0]): + # We need to wrap the nnkElse nodes back into a tryStmt. + # As they are executed if an exception does not happen + # inside the awaited future. + # The following code will wrap the nodes inside the + # original tryStmt. + wrapInTry(n, processed[2][1][0]) + res.add processed result = true else: - res.add n[0][i] + res.add skipped[i] i.inc var i = 0 if not processForTry(node, i, result): - var temp = node - temp[0] = result - result = temp + # If the tryStmt hasn't been transformed we can just put the body + # back into it. + wrapInTry(node, result) return else: discard @@ -1329,8 +1367,8 @@ macro async*(prc: stmt): stmt {.immediate.} = result[6] = outerProcBody #echo(treeRepr(result)) - #if prc[0].getName == "catch": - # echo(toStrLit(result)) + if prc[0].getName == "test3": + echo(toStrLit(result)) proc recvLine*(socket: TAsyncFD): Future[string] {.async.} = ## Reads a line of data from ``socket``. Returned future will complete once diff --git a/lib/pure/asyncdispatch.nimrod.cfg b/lib/pure/asyncdispatch.nim.cfg index e88f8eec3..e88f8eec3 100644 --- a/lib/pure/asyncdispatch.nimrod.cfg +++ b/lib/pure/asyncdispatch.nim.cfg diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index f75b6fc43..752c01eac 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -35,7 +35,7 @@ type offset: int64 when defined(windows): - proc getDesiredAccess(mode: TFileMode): int32 = + proc getDesiredAccess(mode: FileMode): int32 = case mode of fmRead: result = GENERIC_READ @@ -44,7 +44,7 @@ when defined(windows): of fmReadWrite, fmReadWriteExisting: result = GENERIC_READ or GENERIC_WRITE - proc getCreationDisposition(mode: TFileMode, filename: string): int32 = + proc getCreationDisposition(mode: FileMode, filename: string): int32 = case mode of fmRead, fmReadWriteExisting: OPEN_EXISTING @@ -54,7 +54,7 @@ when defined(windows): else: CREATE_NEW else: - proc getPosixFlags(mode: TFileMode): cint = + proc getPosixFlags(mode: FileMode): cint = case mode of fmRead: result = O_RDONLY @@ -74,7 +74,7 @@ proc getFileSize(f: AsyncFile): int64 = var high: DWord let low = getFileSize(f.fd.THandle, addr high) if low == INVALID_FILE_SIZE: - raiseOSError() + raiseOSError(osLastError()) return (high shl 32) or low proc openAsync*(filename: string, mode = fmRead): AsyncFile = @@ -95,7 +95,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile = nil, creationDisposition, flags, 0).TAsyncFd if result.fd.THandle == INVALID_HANDLE_VALUE: - raiseOSError() + raiseOSError(osLastError()) register(result.fd) @@ -108,7 +108,7 @@ proc openAsync*(filename: string, mode = fmRead): AsyncFile = let perm = S_IRUSR or S_IWUSR or S_IRGRP or S_IWGRP or S_IROTH result.fd = open(filename, flags, perm).TAsyncFD if result.fd.cint == -1: - raiseOSError() + raiseOSError(osLastError()) register(result.fd) @@ -185,7 +185,7 @@ proc read*(f: AsyncFile, size: int): Future[string] = if res < 0: let lastError = osLastError() if lastError.int32 != EAGAIN: - retFuture.fail(newException(EOS, osErrorMsg(lastError))) + retFuture.fail(newException(OSError, osErrorMsg(lastError))) else: result = false # We still want this callback to be called. elif res == 0: @@ -227,7 +227,7 @@ proc setFilePos*(f: AsyncFile, pos: int64) = when not defined(windows): let ret = lseek(f.fd.cint, pos, SEEK_SET) if ret == -1: - raiseOSError() + raiseOSError(osLastError()) proc readAll*(f: AsyncFile): Future[string] {.async.} = ## Reads all data from the specified file. @@ -299,7 +299,7 @@ proc write*(f: AsyncFile, data: string): Future[void] = if res < 0: let lastError = osLastError() if lastError.int32 != EAGAIN: - retFuture.fail(newException(EOS, osErrorMsg(lastError))) + retFuture.fail(newException(OSError, osErrorMsg(lastError))) else: result = false # We still want this callback to be called. else: @@ -318,8 +318,8 @@ proc close*(f: AsyncFile) = ## Closes the file specified. when defined(windows): if not closeHandle(f.fd.THandle).bool: - raiseOSError() + raiseOSError(osLastError()) else: if close(f.fd.cint) == -1: - raiseOSError() + raiseOSError(osLastError()) diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index 48a6c59b9..8558ad10d 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -149,7 +149,7 @@ proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} = assertReply reply, "257" proc chmod*(ftp: AsyncFtpClient, path: string, - permissions: set[TFilePermission]) {.async.} = + permissions: set[FilePermission]) {.async.} = ## Changes permission of ``path`` to ``permissions``. var userOctal = 0 var groupOctal = 0 @@ -188,7 +188,7 @@ proc retrText*(ftp: AsyncFtpClient, file: string): Future[string] {.async.} = result = await ftp.getLines() -proc getFile(ftp: AsyncFtpClient, file: TFile, total: BiggestInt, +proc getFile(ftp: AsyncFtpClient, file: File, total: BiggestInt, onProgressChanged: ProgressChangedProc) {.async.} = assert ftp.dsockConnected var progress = 0 @@ -240,7 +240,7 @@ proc retrFile*(ftp: AsyncFtpClient, file, dest: string, await getFile(ftp, destFile, fileSize, onProgressChanged) -proc doUpload(ftp: AsyncFtpClient, file: TFile, +proc doUpload(ftp: AsyncFtpClient, file: File, onProgressChanged: ProgressChangedProc) {.async.} = assert ftp.dsockConnected diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim index d40c3849e..6a7cbe396 100644 --- a/lib/pure/asyncio.nim +++ b/lib/pure/asyncio.nim @@ -675,7 +675,7 @@ when isMainModule: echo(data) echo("Finished reading! " & $no) - proc testAccept(s: AsyncSocket, disp: PDispatcher, no: int) = + proc testAccept(s: AsyncSocket, disp: Dispatcher, no: int) = echo("Accepting client! " & $no) var client: AsyncSocket new(client) @@ -691,7 +691,7 @@ when isMainModule: var d = newDispatcher() var s = asyncSocket() - s.connect("amber.tenthbit.net", TPort(6667)) + s.connect("amber.tenthbit.net", Port(6667)) s.handleConnect = proc (s: AsyncSocket) = testConnect(s, 1) @@ -704,7 +704,7 @@ when isMainModule: server.handleAccept = proc (s: AsyncSocket) = testAccept(s, d, 78) - server.bindAddr(TPort(5555)) + server.bindAddr(Port(5555)) server.listen() d.register(server) diff --git a/lib/pure/basic2d.nim b/lib/pure/basic2d.nim index f2fc1566b..a344cd053 100644 --- a/lib/pure/basic2d.nim +++ b/lib/pure/basic2d.nim @@ -18,7 +18,7 @@ import strutils ## ## Quick start example: ## -## # Create a matrix wich first rotates, then scales and at last translates +## # Create a matrix which first rotates, then scales and at last translates ## ## var m:TMatrix2d=rotate(DEG90) & scale(2.0) & move(100.0,200.0) ## @@ -256,7 +256,7 @@ proc `$`* (t:TMatrix2d):string {.noInit.} = proc isUniform*(t:TMatrix2d,tol=1.0e-6):bool= ## Checks if the transform is uniform, that is - ## perpendicular axes of equal lenght, which means (for example) + ## perpendicular axes of equal length, which means (for example) ## it cannot transform a circle into an ellipse. ## `tol` is used as tolerance for both equal length comparison ## and perp. comparison. @@ -305,7 +305,7 @@ proc equals*(m1:TMatrix2d,m2:TMatrix2d,tol=1.0e-6):bool= abs(m1.ty-m2.ty)<=tol proc `=~`*(m1,m2:TMatrix2d):bool= - ## Checks if `m1`and `m2` is aproximately equal, using a + ## Checks if `m1`and `m2` is approximately equal, using a ## tolerance of 1e-6. equals(m1,m2) diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim index c00764fc5..18ebed67b 100644 --- a/lib/pure/basic3d.nim +++ b/lib/pure/basic3d.nim @@ -23,7 +23,7 @@ import times ## ## Quick start example: ## -## # Create a matrix wich first rotates, then scales and at last translates +## # Create a matrix which first rotates, then scales and at last translates ## ## var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0) ## @@ -320,7 +320,7 @@ proc rotateZ*(angle:float):TMatrix3d {.noInit.}= proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool= ## Checks if the transform is uniform, that is - ## perpendicular axes of equal lenght, which means (for example) + ## perpendicular axes of equal length, which means (for example) ## it cannot transform a sphere into an ellipsoid. ## `tol` is used as tolerance for both equal length comparison ## and perpendicular comparison. @@ -483,7 +483,7 @@ proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool= abs(m1.tw-m2.tw)<=tol proc `=~`*(m1,m2:TMatrix3d):bool= - ## Checks if `m1` and `m2` is aproximately equal, using a + ## Checks if `m1` and `m2` is approximately equal, using a ## tolerance of 1e-6. equals(m1,m2) @@ -788,7 +788,7 @@ proc angleTo*(v1,v2:TVector3d):float= proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}= ## Computes the rotation matrix that would transform ## world z vector into `norm`. The inverse of this matrix - ## is useful to tranform a planar 3d object to 2d space. + ## is useful to transform a planar 3d object to 2d space. ## This is the same algorithm used to interpret DXF and DWG files. const lim=1.0/64.0 var ax,ay,az:TVector3d @@ -812,7 +812,7 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}= ## Computes the bisector between v1 and v2 as a normalized vector. ## If one of the input vectors has zero length, a normalized version ## of the other is returned. If both input vectors has zero length, - ## an arbitrary normalized vector `v1`is returned. + ## an arbitrary normalized vector `v1` is returned. var vmag1=v1.len vmag2=v2.len diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index 52035ee48..c6a603318 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -42,7 +42,7 @@ proc openDefaultBrowser*(url: string) = for b in getEnv("BROWSER").string.split(PathSep): try: # we use ``startProcess`` here because we don't want to block! - discard startProcess(command=b, args=[url], options={poUseShell}) + discard startProcess(command=b, args=[url], options={poUsePath}) return except OSError: discard diff --git a/lib/pure/collections/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim index 5640838b1..c3954468a 100644 --- a/lib/pure/collections/LockFreeHash.nim +++ b/lib/pure/collections/LockFreeHash.nim @@ -404,7 +404,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int, #echo("tomb old slot then set in new table") nextTable = copySlotAndCheck(table,idx) return setVal(nextTable, key, val, expVal, match) - # Finaly ready to add new val to table + # Finally ready to add new val to table while true: if match and oldVal != expVal: #echo("set failed, no match oldVal= " & $oldVal & " expVal= " & $expVal) diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 06babc6bb..3d10e39aa 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -174,7 +174,7 @@ proc excl*[T](c: var CritBitTree[T], key: string) = iterator leaves[T](n: Node[T]): Node[T] = if n != nil: # XXX actually we could compute the necessary stack size in advance: - # it's rougly log2(c.count). + # it's roughly log2(c.count). var stack = @[n] while stack.len > 0: var it = stack.pop diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index b46e040ca..7520e6e46 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -191,9 +191,10 @@ proc `$`*(s: IntSet): string = ## The `$` operator for int sets. dollarImpl() -proc empty*(s: IntSet): bool {.inline.} = +proc empty*(s: IntSet): bool {.inline, deprecated.} = ## returns true if `s` is empty. This is safe to call even before - ## the set has been initialized with `initIntSet`. + ## the set has been initialized with `initIntSet`. Note this never + ## worked reliably and so is deprecated. result = s.counter == 0 when isMainModule: diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index befc9bacb..e690e8eba 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -320,7 +320,7 @@ template foldl*(sequence, operation: expr): expr = ## ## The ``operation`` parameter should be an expression which uses the ## variables ``a`` and ``b`` for each step of the fold. Since this is a left - ## fold, for non associative binary operations like substraction think that + ## fold, for non associative binary operations like subtraction think that ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) - ## 3). Example: ## @@ -328,12 +328,12 @@ template foldl*(sequence, operation: expr): expr = ## let ## numbers = @[5, 9, 11] ## addition = foldl(numbers, a + b) - ## substraction = foldl(numbers, a - b) + ## subtraction = foldl(numbers, a - b) ## multiplication = foldl(numbers, a * b) ## words = @["nim", "is", "cool"] ## concatenation = foldl(words, a & b) ## assert addition == 25, "Addition is (((5)+9)+11)" - ## assert substraction == -15, "Substraction is (((5)-9)-11)" + ## assert subtraction == -15, "Subtraction is (((5)-9)-11)" ## assert multiplication == 495, "Multiplication is (((5)*9)*11)" ## assert concatenation == "nimiscool" assert sequence.len > 0, "Can't fold empty sequences" @@ -356,7 +356,7 @@ template foldr*(sequence, operation: expr): expr = ## ## The ``operation`` parameter should be an expression which uses the ## variables ``a`` and ``b`` for each step of the fold. Since this is a right - ## fold, for non associative binary operations like substraction think that + ## fold, for non associative binary operations like subtraction think that ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 - ## (3))). Example: ## @@ -364,12 +364,12 @@ template foldr*(sequence, operation: expr): expr = ## let ## numbers = @[5, 9, 11] ## addition = foldr(numbers, a + b) - ## substraction = foldr(numbers, a - b) + ## subtraction = foldr(numbers, a - b) ## multiplication = foldr(numbers, a * b) ## words = @["nim", "is", "cool"] ## concatenation = foldr(words, a & b) ## assert addition == 25, "Addition is (5+(9+(11)))" - ## assert substraction == 7, "Substraction is (5-(9-(11)))" + ## assert subtraction == 7, "Subtraction is (5-(9-(11)))" ## assert multiplication == 495, "Multiplication is (5*(9*(11)))" ## assert concatenation == "nimiscool" assert sequence.len > 0, "Can't fold empty sequences" @@ -382,7 +382,7 @@ template foldr*(sequence, operation: expr): expr = result = operation result -template mapIt*(seq1, typ, pred: expr): expr = +template mapIt*(seq1, typ, op: expr): expr = ## Convenience template around the ``map`` proc to reduce typing. ## ## The template injects the ``it`` variable which you can use directly in an @@ -397,10 +397,10 @@ template mapIt*(seq1, typ, pred: expr): expr = ## assert strings == @["4", "8", "12", "16"] var result {.gensym.}: seq[typ] = @[] for it {.inject.} in items(seq1): - result.add(pred) + result.add(op) result -template mapIt*(varSeq, pred: expr) = +template mapIt*(varSeq, op: expr) = ## Convenience template around the mutable ``map`` proc to reduce typing. ## ## The template injects the ``it`` variable which you can use directly in an @@ -413,7 +413,7 @@ template mapIt*(varSeq, pred: expr) = ## assert nums[0] + nums[3] == 15 for i in 0 .. <len(varSeq): let it {.inject.} = varSeq[i] - varSeq[i] = pred + varSeq[i] = op template newSeqWith*(len: int, init: expr): expr = ## creates a new sequence, calling `init` to initialize each value. Example: @@ -507,12 +507,12 @@ when isMainModule: let numbers = @[5, 9, 11] addition = foldl(numbers, a + b) - substraction = foldl(numbers, a - b) + subtraction = foldl(numbers, a - b) multiplication = foldl(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldl(words, a & b) assert addition == 25, "Addition is (((5)+9)+11)" - assert substraction == -15, "Substraction is (((5)-9)-11)" + assert subtraction == -15, "Subtraction is (((5)-9)-11)" assert multiplication == 495, "Multiplication is (((5)*9)*11)" assert concatenation == "nimiscool" @@ -520,12 +520,12 @@ when isMainModule: let numbers = @[5, 9, 11] addition = foldr(numbers, a + b) - substraction = foldr(numbers, a - b) + subtraction = foldr(numbers, a - b) multiplication = foldr(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldr(words, a & b) assert addition == 25, "Addition is (5+(9+(11)))" - assert substraction == 7, "Substraction is (5-(9-(11)))" + assert subtraction == 7, "Subtraction is (5-(9-(11)))" assert multiplication == 495, "Multiplication is (5*(9*(11)))" assert concatenation == "nimiscool" diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index 4cc46149e..4a20d00a4 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -24,9 +24,12 @@ import when not defined(nimhygiene): {.pragma: dirty.} +# For "integer-like A" that are too big for intsets/bit-vectors to be practical, +# it would be best to shrink hcode to the same size as the integer. Larger +# codes should never be needed, and this can pack more entries per cache-line. +# Losing hcode entirely is also possible - if some element value is forbidden. type - SlotEnum = enum seEmpty, seFilled, seDeleted - KeyValuePair[A] = tuple[slot: SlotEnum, key: A] + KeyValuePair[A] = tuple[hcode: THash, key: A] KeyValuePairSeq[A] = seq[KeyValuePair[A]] HashSet* {.myShallow.}[A] = object ## \ ## A generic hash set. @@ -38,6 +41,14 @@ type {.deprecated: [TSet: HashSet].} +# hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These +# two procs retain clarity of that encoding without the space cost of an enum. +proc isEmpty(hcode: THash): bool {.inline.} = + result = hcode == 0 + +proc isFilled(hcode: THash): bool {.inline.} = + result = hcode != 0 + proc isValid*[A](s: HashSet[A]): bool = ## Returns `true` if the set has been initialized with `initSet <#initSet>`_. ## @@ -94,7 +105,7 @@ iterator items*[A](s: HashSet[A]): A = ## # --> {(a: 1, b: 3), (a: 0, b: 4)} assert s.isValid, "The set needs to be initialized." for h in 0..high(s.data): - if s.data[h].slot == seFilled: yield s.data[h].key + if isFilled(s.data[h].hcode): yield s.data[h].key const growthFactor = 2 @@ -103,25 +114,44 @@ proc mustRehash(length, counter: int): bool {.inline.} = assert(length > counter) result = (length * 2 < counter * 3) or (length - counter < 4) -proc nextTry(h, maxHash: THash): THash {.inline.} = - result = ((5 * h) + 1) and maxHash +proc rightSize*(count: int): int {.inline.} = + ## Return the value of `initialSize` to support `count` items. + ## + ## If more items are expected to be added, simply add that + ## expected extra amount to the parameter before calling this. + ## + ## Internally, we want mustRehash(rightSize(x), x) == false. + result = nextPowerOfTwo(count * 3 div 2 + 4) -template rawGetImpl() {.dirty.} = - var h: THash = hash(key) and high(s.data) # start with real hash value - while s.data[h].slot != seEmpty: - if s.data[h].key == key and s.data[h].slot == seFilled: +proc nextTry(h, maxHash: THash): THash {.inline.} = + result = (h + 1) and maxHash + +template rawGetKnownHCImpl() {.dirty.} = + var h: THash = hc and high(s.data) # start with real hash value + while isFilled(s.data[h].hcode): + # Compare hc THEN key with boolean short circuit. This makes the common case + # zero ==key's for missing (e.g.inserts) and exactly one ==key for present. + # It does slow down succeeding lookups by one extra THash cmp&and..usually + # just a few clock cycles, generally worth it for any non-integer-like A. + if s.data[h].hcode == hc and s.data[h].key == key: # compare hc THEN key return h h = nextTry(h, high(s.data)) - result = -1 + result = -1 - h # < 0 => MISSING; insert idx = -1 - result + +template rawGetImpl() {.dirty.} = + hc = hash(key) + if hc == 0: # This almost never taken branch should be very predictable. + hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine. + rawGetKnownHCImpl() template rawInsertImpl() {.dirty.} = - var h: THash = hash(key) and high(data) - while data[h].slot == seFilled: - h = nextTry(h, high(data)) data[h].key = key - data[h].slot = seFilled + data[h].hcode = hc + +proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: THash): int {.inline.} = + rawGetKnownHCImpl() -proc rawGet[A](s: HashSet[A], key: A): int = +proc rawGet[A](s: HashSet[A], key: A, hc: var THash): int {.inline.} = rawGetImpl() proc mget*[A](s: var HashSet[A], key: A): var A = @@ -130,7 +160,8 @@ proc mget*[A](s: var HashSet[A], key: A): var A = ## when one overloaded 'hash' and '==' but still needs reference semantics ## for sharing. assert s.isValid, "The set needs to be initialized." - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) if index >= 0: result = s.data[index].key else: raise newException(KeyError, "key not found: " & $key) @@ -147,33 +178,43 @@ proc contains*[A](s: HashSet[A], key: A): bool = ## values.excl(2) ## assert(not values.contains(2)) assert s.isValid, "The set needs to be initialized." - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) result = index >= 0 -proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A) = +proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A, + hc: THash, h: THash) = rawInsertImpl() proc enlarge[A](s: var HashSet[A]) = var n: KeyValuePairSeq[A] newSeq(n, len(s.data) * growthFactor) - for i in countup(0, high(s.data)): - if s.data[i].slot == seFilled: rawInsert(s, n, s.data[i].key) - swap(s.data, n) + swap(s.data, n) # n is now old seq + for i in countup(0, high(n)): + if isFilled(n[i].hcode): + var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode) + rawInsert(s, s.data, n[i].key, n[i].hcode, j) template inclImpl() {.dirty.} = - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) if index < 0: - if mustRehash(len(s.data), s.counter): enlarge(s) - rawInsert(s, s.data, key) + if mustRehash(len(s.data), s.counter): + enlarge(s) + index = rawGetKnownHC(s, key, hc) + rawInsert(s, s.data, key, hc, -1 - index) inc(s.counter) template containsOrInclImpl() {.dirty.} = - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) if index >= 0: result = true else: - if mustRehash(len(s.data), s.counter): enlarge(s) - rawInsert(s, s.data, key) + if mustRehash(len(s.data), s.counter): + enlarge(s) + index = rawGetKnownHC(s, key, hc) + rawInsert(s, s.data, key, hc, -1 - index) inc(s.counter) proc incl*[A](s: var HashSet[A], key: A) = @@ -204,6 +245,11 @@ proc incl*[A](s: var HashSet[A], other: HashSet[A]) = assert other.isValid, "The set `other` needs to be initialized." for item in other: incl(s, item) +template doWhile(a: expr, b: stmt): stmt = + while true: + b + if not a: break + proc excl*[A](s: var HashSet[A], key: A) = ## Excludes `key` from the set `s`. ## @@ -215,10 +261,22 @@ proc excl*[A](s: var HashSet[A], key: A) = ## s.excl(2) ## assert s.len == 3 assert s.isValid, "The set needs to be initialized." - var index = rawGet(s, key) - if index >= 0: - s.data[index].slot = seDeleted + var hc: THash + var i = rawGet(s, key, hc) + var msk = high(s.data) + if i >= 0: + s.data[i].hcode = 0 dec(s.counter) + while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 + var j = i # The correctness of this depends on (h+1) in nextTry, + var r = j # though may be adaptable to other simple sequences. + s.data[i].hcode = 0 # mark current EMPTY + doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): + i = (i + 1) and msk # increment mod table size + if isEmpty(s.data[i].hcode): # end of collision cluster; So all done + return + r = s.data[i].hcode and msk # "home" location of key@i + shallowCopy(s.data[j], s.data[i]) # data[j] will be marked EMPTY next loop proc excl*[A](s: var HashSet[A], other: HashSet[A]) = ## Excludes everything in `other` from `s`. @@ -255,9 +313,9 @@ proc init*[A](s: var HashSet[A], initialSize=64) = ## Initializes a hash set. ## ## The `initialSize` parameter needs to be a power of two. You can use - ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ to guarantee that at - ## runtime. All set variables have to be initialized before you can use them - ## with other procs from this module with the exception of `isValid() + ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to + ## guarantee that at runtime. All set variables must be initialized before + ## use with other procs from this module with the exception of `isValid() ## <#isValid,TSet[A]>`_ and `len() <#len,TSet[A]>`_. ## ## You can call this proc on a previously initialized hash set, which will @@ -295,7 +353,7 @@ proc toSet*[A](keys: openArray[A]): HashSet[A] = ## var numbers = toSet([1, 2, 3, 4, 5]) ## assert numbers.contains(2) ## assert numbers.contains(4) - result = initSet[A](nextPowerOfTwo(keys.len+10)) + result = initSet[A](rightSize(keys.len)) for key in items(keys): result.incl(key) template dollarImpl(): stmt {.dirty.} = @@ -494,7 +552,7 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] = type OrderedKeyValuePair[A] = tuple[ - slot: SlotEnum, next: int, key: A] + hcode: THash, next: int, key: A] OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]] OrderedSet* {.myShallow.}[A] = object ## \ ## A generic hash set that remembers insertion order. @@ -546,7 +604,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} = var h = s.first while h >= 0: var nxt = s.data[h].next - if s.data[h].slot == seFilled: yieldStmt + if isFilled(s.data[h].hcode): yieldStmt h = nxt iterator items*[A](s: OrderedSet[A]): A = @@ -571,7 +629,10 @@ iterator items*[A](s: OrderedSet[A]): A = forAllOrderedPairs: yield s.data[h].key -proc rawGet[A](s: OrderedSet[A], key: A): int = +proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: THash): int {.inline.} = + rawGetKnownHCImpl() + +proc rawGet[A](s: OrderedSet[A], key: A, hc: var THash): int {.inline.} = rawGetImpl() proc contains*[A](s: OrderedSet[A], key: A): bool = @@ -585,11 +646,12 @@ proc contains*[A](s: OrderedSet[A], key: A): bool = ## values.incl(2) ## assert values.contains(2) assert s.isValid, "The set needs to be initialized." - var index = rawGet(s, key) + var hc: THash + var index = rawGet(s, key, hc) result = index >= 0 -proc rawInsert[A](s: var OrderedSet[A], - data: var OrderedKeyValuePairSeq[A], key: A) = +proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A], + key: A, hc: THash, h: THash) = rawInsertImpl() data[h].next = -1 if s.first < 0: s.first = h @@ -602,12 +664,13 @@ proc enlarge[A](s: var OrderedSet[A]) = var h = s.first s.first = -1 s.last = -1 + swap(s.data, n) while h >= 0: - var nxt = s.data[h].next - if s.data[h].slot == seFilled: - rawInsert(s, n, s.data[h].key) + var nxt = n[h].next + if isFilled(n[h].hcode): + var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode) + rawInsert(s, s.data, n[h].key, n[h].hcode, j) h = nxt - swap(s.data, n) proc incl*[A](s: var OrderedSet[A], key: A) = ## Includes an element `key` in `s`. @@ -655,10 +718,10 @@ proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool = proc init*[A](s: var OrderedSet[A], initialSize=64) = ## Initializes an ordered hash set. ## - ## The `initialSize` parameter needs to be a power of too. You can use - ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ to guarantee that at - ## runtime. All set variables have to be initialized before you can use them - ## with other procs from this module with the exception of `isValid() + ## The `initialSize` parameter needs to be a power of two. You can use + ## `math.nextPowerOfTwo() <math.html#nextPowerOfTwo>`_ or `rightSize` to + ## guarantee that at runtime. All set variables must be initialized before + ## use with other procs from this module with the exception of `isValid() ## <#isValid,TOrderedSet[A]>`_ and `len() <#len,TOrderedSet[A]>`_. ## ## You can call this proc on a previously initialized ordered hash set to @@ -698,7 +761,7 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] = ## var numbers = toOrderedSet([1, 2, 3, 4, 5]) ## assert numbers.contains(2) ## assert numbers.contains(4) - result = initOrderedSet[A](nextPowerOfTwo(keys.len+10)) + result = initOrderedSet[A](rightSize(keys.len)) for key in items(keys): result.incl(key) proc `$`*[A](s: OrderedSet[A]): string = @@ -726,7 +789,7 @@ proc `==`*[A](s, t: OrderedSet[A]): bool = while h >= 0 and g >= 0: var nxh = s.data[h].next var nxg = t.data[g].next - if s.data[h].slot == seFilled and s.data[g].slot == seFilled: + if isFilled(s.data[h].hcode) and isFilled(s.data[g].hcode): if s.data[h].key == s.data[g].key: inc compared else: @@ -901,6 +964,11 @@ proc testModule() = b.incl(2) assert b.len == 1 + for i in 0 .. 32: + var s = rightSize(i) + if s <= i or mustRehash(s, i): + echo "performance issue: rightSize() will not elide enlarge() at ", i + echo "Micro tests run successfully." when isMainModule and not defined(release): testModule() diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 9dcc97148..959688d6a 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -11,7 +11,7 @@ ## (also often named `dictionary`:idx: in other programming languages) that is ## a mapping from keys to values. ``Table`` is the usual hash table, ## ``OrderedTable`` is like ``Table`` but remembers insertion order -## and ``CountTable`` is a mapping from a key to its number of occurances. +## and ``CountTable`` is a mapping from a key to its number of occurrences. ## For consistency with every other data type in Nim these have **value** ## semantics, this means that ``=`` performs a copy of the hash table. ## For **reference** semantics use the ``Ref`` variant: ``TableRef``, @@ -71,8 +71,7 @@ import {.pragma: myShallow.} type - SlotEnum = enum seEmpty, seFilled, seDeleted - KeyValuePair[A, B] = tuple[slot: SlotEnum, key: A, val: B] + KeyValuePair[A, B] = tuple[hcode: THash, key: A, val: B] KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]] Table* {.myShallow.}[A, B] = object ## generic hash table data: KeyValuePairSeq[A, B] @@ -84,6 +83,14 @@ type when not defined(nimhygiene): {.pragma: dirty.} +# hcode for real keys cannot be zero. hcode==0 signifies an empty slot. These +# two procs retain clarity of that encoding without the space cost of an enum. +proc isEmpty(hcode: THash): bool {.inline.} = + result = hcode == 0 + +proc isFilled(hcode: THash): bool {.inline.} = + result = hcode != 0 + proc len*[A, B](t: Table[A, B]): int = ## returns the number of keys in `t`. result = t.counter @@ -91,28 +98,28 @@ proc len*[A, B](t: Table[A, B]): int = iterator pairs*[A, B](t: Table[A, B]): tuple[key: A, val: B] = ## iterates over any (key, value) pair in the table `t`. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val) + if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) iterator mpairs*[A, B](t: var Table[A, B]): tuple[key: A, val: var B] = ## iterates over any (key, value) pair in the table `t`. The values ## can be modified. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val) + if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) iterator keys*[A, B](t: Table[A, B]): A = ## iterates over any key in the table `t`. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield t.data[h].key + if isFilled(t.data[h].hcode): yield t.data[h].key iterator values*[A, B](t: Table[A, B]): B = ## iterates over any value in the table `t`. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield t.data[h].val + if isFilled(t.data[h].hcode): yield t.data[h].val iterator mvalues*[A, B](t: var Table[A, B]): var B = ## iterates over any value in the table `t`. The values can be modified. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield t.data[h].val + if isFilled(t.data[h].hcode): yield t.data[h].val const growthFactor = 2 @@ -121,26 +128,57 @@ proc mustRehash(length, counter: int): bool {.inline.} = assert(length > counter) result = (length * 2 < counter * 3) or (length - counter < 4) +proc rightSize*(count: int): int {.inline.} = + ## Return the value of `initialSize` to support `count` items. + ## + ## If more items are expected to be added, simply add that + ## expected extra amount to the parameter before calling this. + ## + ## Internally, we want mustRehash(rightSize(x), x) == false. + result = nextPowerOfTwo(count * 3 div 2 + 4) + proc nextTry(h, maxHash: THash): THash {.inline.} = - result = ((5 * h) + 1) and maxHash + result = (h + 1) and maxHash + +template rawGetKnownHCImpl() {.dirty.} = + var h: THash = hc and high(t.data) # start with real hash value + while isFilled(t.data[h].hcode): + # Compare hc THEN key with boolean short circuit. This makes the common case + # zero ==key's for missing (e.g.inserts) and exactly one ==key for present. + # It does slow down succeeding lookups by one extra THash cmp&and..usually + # just a few clock cycles, generally worth it for any non-integer-like A. + if t.data[h].hcode == hc and t.data[h].key == key: + return h + h = nextTry(h, high(t.data)) + result = -1 - h # < 0 => MISSING; insert idx = -1 - result template rawGetImpl() {.dirty.} = - var h: THash = hash(key) and high(t.data) # start with real hash value - while t.data[h].slot != seEmpty: - if t.data[h].key == key and t.data[h].slot == seFilled: - return h + hc = hash(key) + if hc == 0: # This almost never taken branch should be very predictable. + hc = 314159265 # Value doesn't matter; Any non-zero favorite is fine. + rawGetKnownHCImpl() + +template rawGetDeepImpl() {.dirty.} = # Search algo for unconditional add + hc = hash(key) + if hc == 0: + hc = 314159265 + var h: THash = hc and high(t.data) + while isFilled(t.data[h].hcode): h = nextTry(h, high(t.data)) - result = -1 + result = h template rawInsertImpl() {.dirty.} = - var h: THash = hash(key) and high(data) - while data[h].slot == seFilled: - h = nextTry(h, high(data)) data[h].key = key data[h].val = val - data[h].slot = seFilled + data[h].hcode = hc + +proc rawGetKnownHC[A, B](t: Table[A, B], key: A, hc: THash): int {.inline.} = + rawGetKnownHCImpl() + +proc rawGetDeep[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} = + rawGetDeepImpl() -proc rawGet[A, B](t: Table[A, B], key: A): int = +proc rawGet[A, B](t: Table[A, B], key: A, hc: var THash): int {.inline.} = rawGetImpl() proc `[]`*[A, B](t: Table[A, B], key: A): B = @@ -148,63 +186,87 @@ proc `[]`*[A, B](t: Table[A, B], key: A): B = ## default empty value for the type `B` is returned ## and no exception is raised. One can check with ``hasKey`` whether the key ## exists. - var index = rawGet(t, key) + var hc: THash + var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val proc mget*[A, B](t: var Table[A, B], key: A): var B = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. - var index = rawGet(t, key) + var hc: THash + var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val else: raise newException(KeyError, "key not found: " & $key) iterator allValues*[A, B](t: Table[A, B]; key: A): B = ## iterates over any value in the table `t` that belongs to the given `key`. var h: THash = hash(key) and high(t.data) - while t.data[h].slot != seEmpty: - if t.data[h].key == key and t.data[h].slot == seFilled: + while isFilled(t.data[h].hcode): + if t.data[h].key == key: yield t.data[h].val h = nextTry(h, high(t.data)) proc hasKey*[A, B](t: Table[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. - result = rawGet(t, key) >= 0 + var hc: THash + result = rawGet(t, key, hc) >= 0 proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B], - key: A, val: B) = + key: A, val: B, hc: THash, h: THash) = rawInsertImpl() proc enlarge[A, B](t: var Table[A, B]) = var n: KeyValuePairSeq[A, B] newSeq(n, len(t.data) * growthFactor) - for i in countup(0, high(t.data)): - if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val) swap(t.data, n) + for i in countup(0, high(n)): + if isFilled(n[i].hcode): + var j = -1 - rawGetKnownHC(t, n[i].key, n[i].hcode) + rawInsert(t, t.data, n[i].key, n[i].val, n[i].hcode, j) template addImpl() {.dirty.} = if mustRehash(len(t.data), t.counter): enlarge(t) - rawInsert(t, t.data, key, val) + var hc: THash + var j = rawGetDeep(t, key, hc) + rawInsert(t, t.data, key, val, hc, j) + inc(t.counter) + +template maybeRehashPutImpl() {.dirty.} = + if mustRehash(len(t.data), t.counter): + enlarge(t) + index = rawGetKnownHC(t, key, hc) + index = -1 - index # important to transform for mgetOrPutImpl + rawInsert(t, t.data, key, val, hc, index) inc(t.counter) template putImpl() {.dirty.} = - var index = rawGet(t, key) - if index >= 0: - t.data[index].val = val - else: - addImpl() - -when false: - # not yet used: - template hasKeyOrPutImpl() {.dirty.} = - var index = rawGet(t, key) - if index >= 0: - t.data[index].val = val - result = true - else: - if mustRehash(len(t.data), t.counter): enlarge(t) - rawInsert(t, t.data, key, val) - inc(t.counter) - result = false + var hc: THash + var index = rawGet(t, key, hc) + if index >= 0: t.data[index].val = val + else: maybeRehashPutImpl() + +template mgetOrPutImpl() {.dirty.} = + var hc: THash + var index = rawGet(t, key, hc) + if index < 0: maybeRehashPutImpl() # not present: insert (flipping index) + result = t.data[index].val # either way return modifiable val + +template hasKeyOrPutImpl() {.dirty.} = + var hc: THash + var index = rawGet(t, key, hc) + if index < 0: + result = false + maybeRehashPutImpl() + else: result = true + +proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B = + ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way + ## returning a value which can be modified. + mgetOrPutImpl() + +proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool = + ## returns true iff `key` is in the table, otherwise inserts `value`. + hasKeyOrPutImpl() proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. @@ -213,20 +275,37 @@ proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) = proc add*[A, B](t: var Table[A, B], key: A, val: B) = ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. addImpl() - + +template doWhile(a: expr, b: stmt): stmt = + while true: + b + if not a: break + proc del*[A, B](t: var Table[A, B], key: A) = ## deletes `key` from hash table `t`. - let index = rawGet(t, key) - if index >= 0: - t.data[index].slot = seDeleted + var hc: THash + var i = rawGet(t, key, hc) + let msk = high(t.data) + if i >= 0: + t.data[i].hcode = 0 dec(t.counter) + while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 + var j = i # The correctness of this depends on (h+1) in nextTry, + var r = j # though may be adaptable to other simple sequences. + t.data[i].hcode = 0 # mark current EMPTY + doWhile ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)): + i = (i + 1) and msk # increment mod table size + if isEmpty(t.data[i].hcode): # end of collision cluster; So all done + return + r = t.data[i].hcode and msk # "home" location of key@i + shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop proc initTable*[A, B](initialSize=64): Table[A, B] = ## creates a new hash table that is empty. ## ## `initialSize` needs to be a power of two. If you need to accept runtime ## values for this you could use the ``nextPowerOfTwo`` proc from the - ## `math <math.html>`_ module. + ## `math <math.html>`_ module or the ``rightSize`` proc from this module. assert isPowerOfTwo(initialSize) result.counter = 0 newSeq(result.data, initialSize) @@ -234,7 +313,7 @@ proc initTable*[A, B](initialSize=64): Table[A, B] = proc toTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): Table[A, B] = ## creates a new hash table that contains the given `pairs`. - result = initTable[A, B](nextPowerOfTwo(pairs.len+10)) + result = initTable[A, B](rightSize(pairs.len)) for key, val in items(pairs): result[key] = val template dollarImpl(): stmt {.dirty.} = @@ -252,7 +331,7 @@ template dollarImpl(): stmt {.dirty.} = proc `$`*[A, B](t: Table[A, B]): string = ## The `$` operator for hash tables. dollarImpl() - + template equalsImpl() = if s.counter == t.counter: # different insertion orders mean different 'data' seqs, so we have @@ -262,10 +341,10 @@ template equalsImpl() = if not t.hasKey(key): return false if t[key] != val: return false return true - + proc `==`*[A, B](s, t: Table[A, B]): bool = equalsImpl() - + proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): Table[C, B] = ## Index the collection with the proc provided. # TODO: As soon as supported, change collection: A to collection: A[B] @@ -280,28 +359,28 @@ proc len*[A, B](t: TableRef[A, B]): int = iterator pairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: B] = ## iterates over any (key, value) pair in the table `t`. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val) + if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) iterator mpairs*[A, B](t: TableRef[A, B]): tuple[key: A, val: var B] = ## iterates over any (key, value) pair in the table `t`. The values ## can be modified. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val) + if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val) iterator keys*[A, B](t: TableRef[A, B]): A = ## iterates over any key in the table `t`. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield t.data[h].key + if isFilled(t.data[h].hcode): yield t.data[h].key iterator values*[A, B](t: TableRef[A, B]): B = ## iterates over any value in the table `t`. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield t.data[h].val + if isFilled(t.data[h].hcode): yield t.data[h].val iterator mvalues*[A, B](t: TableRef[A, B]): var B = ## iterates over any value in the table `t`. The values can be modified. for h in 0..high(t.data): - if t.data[h].slot == seFilled: yield t.data[h].val + if isFilled(t.data[h].hcode): yield t.data[h].val proc `[]`*[A, B](t: TableRef[A, B], key: A): B = ## retrieves the value at ``t[key]``. If `key` is not in `t`, @@ -315,6 +394,15 @@ proc mget*[A, B](t: TableRef[A, B], key: A): var B = ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. t[].mget(key) +proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B = + ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way + ## returning a value which can be modified. + t[].mgetOrPut(key, val) + +proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool = + ## returns true iff `key` is in the table, otherwise inserts `value`. + t[].hasKeyOrPut(key, val) + proc hasKey*[A, B](t: TableRef[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) @@ -326,7 +414,7 @@ proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) = proc add*[A, B](t: TableRef[A, B], key: A, val: B) = ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. t[].add(key, val) - + proc del*[A, B](t: TableRef[A, B], key: A) = ## deletes `key` from hash table `t`. t[].del(key) @@ -347,7 +435,7 @@ proc `$`*[A, B](t: TableRef[A, B]): string = proc `==`*[A, B](s, t: TableRef[A, B]): bool = if isNil(s): result = isNil(t) elif isNil(t): result = false - else: result = equalsImpl() + else: equalsImpl() proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] = ## Index the collection with the proc provided. @@ -360,7 +448,7 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] type OrderedKeyValuePair[A, B] = tuple[ - slot: SlotEnum, next: int, key: A, val: B] + hcode: THash, next: int, key: A, val: B] OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]] OrderedTable* {. myShallow.}[A, B] = object ## table that remembers insertion order @@ -378,7 +466,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} = var h = t.first while h >= 0: var nxt = t.data[h].next - if t.data[h].slot == seFilled: yieldStmt + if isFilled(t.data[h].hcode): yieldStmt h = nxt iterator pairs*[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] = @@ -409,7 +497,13 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B = forAllOrderedPairs: yield t.data[h].val -proc rawGet[A, B](t: OrderedTable[A, B], key: A): int = +proc rawGetKnownHC[A, B](t: OrderedTable[A, B], key: A, hc: THash): int = + rawGetKnownHCImpl() + +proc rawGetDeep[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int {.inline.} = + rawGetDeepImpl() + +proc rawGet[A, B](t: OrderedTable[A, B], key: A, hc: var THash): int = rawGetImpl() proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = @@ -417,23 +511,26 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = ## default empty value for the type `B` is returned ## and no exception is raised. One can check with ``hasKey`` whether the key ## exists. - var index = rawGet(t, key) + var hc: THash + var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val proc mget*[A, B](t: var OrderedTable[A, B], key: A): var B = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. - var index = rawGet(t, key) + var hc: THash + var index = rawGet(t, key, hc) if index >= 0: result = t.data[index].val else: raise newException(KeyError, "key not found: " & $key) proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. - result = rawGet(t, key) >= 0 + var hc: THash + result = rawGet(t, key, hc) >= 0 proc rawInsert[A, B](t: var OrderedTable[A, B], data: var OrderedKeyValuePairSeq[A, B], - key: A, val: B) = + key: A, val: B, hc: THash, h: THash) = rawInsertImpl() data[h].next = -1 if t.first < 0: t.first = h @@ -446,12 +543,13 @@ proc enlarge[A, B](t: var OrderedTable[A, B]) = var h = t.first t.first = -1 t.last = -1 + swap(t.data, n) while h >= 0: - var nxt = t.data[h].next - if t.data[h].slot == seFilled: - rawInsert(t, n, t.data[h].key, t.data[h].val) + var nxt = n[h].next + if isFilled(n[h].hcode): + var j = -1 - rawGetKnownHC(t, n[h].key, n[h].hcode) + rawInsert(t, t.data, n[h].key, n[h].val, n[h].hcode, j) h = nxt - swap(t.data, n) proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. @@ -461,12 +559,21 @@ proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) = ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. addImpl() +proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B = + ## retrieves value at ``t[key]`` or puts ``value`` if not present, either way + ## returning a value which can be modified. + mgetOrPutImpl() + +proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool = + ## returns true iff `key` is in the table, otherwise inserts `value`. + hasKeyOrPutImpl() + proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] = ## creates a new ordered hash table that is empty. ## ## `initialSize` needs to be a power of two. If you need to accept runtime ## values for this you could use the ``nextPowerOfTwo`` proc from the - ## `math <math.html>`_ module. + ## `math <math.html>`_ module or the ``rightSize`` proc from this module. assert isPowerOfTwo(initialSize) result.counter = 0 result.first = -1 @@ -476,7 +583,7 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] = proc toOrderedTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): OrderedTable[A, B] = ## creates a new ordered hash table that contains the given `pairs`. - result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10)) + result = initOrderedTable[A, B](rightSize(pairs.len)) for key, val in items(pairs): result[key] = val proc `$`*[A, B](t: OrderedTable[A, B]): string = @@ -537,7 +644,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} = var h = t.first while h >= 0: var nxt = t.data[h].next - if t.data[h].slot == seFilled: yieldStmt + if isFilled(t.data[h].hcode): yieldStmt h = nxt iterator pairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: B] = @@ -580,6 +687,15 @@ proc mget*[A, B](t: OrderedTableRef[A, B], key: A): var B = ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. result = t[].mget(key) +proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B = + ## retrieves value at ``t[key]`` or puts ``val`` if not present, either way + ## returning a value which can be modified. + result = t[].mgetOrPut(key, val) + +proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool = + ## returns true iff `key` is in the table, otherwise inserts `val`. + result = t[].hasKeyOrPut(key, val) + proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) @@ -597,14 +713,14 @@ proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] = ## ## `initialSize` needs to be a power of two. If you need to accept runtime ## values for this you could use the ``nextPowerOfTwo`` proc from the - ## `math <math.html>`_ module. + ## `math <math.html>`_ module or the ``rightSize`` proc from this module. new(result) result[] = initOrderedTable[A, B]() proc newOrderedTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): OrderedTableRef[A, B] = ## creates a new ordered hash table that contains the given `pairs`. - result = newOrderedTable[A, B](nextPowerOfTwo(pairs.len+10)) + result = newOrderedTable[A, B](rightSize(pairs.len)) for key, val in items(pairs): result[key] = val proc `$`*[A, B](t: OrderedTableRef[A, B]): string = @@ -665,7 +781,7 @@ proc rawGet[A](t: CountTable[A], key: A): int = while t.data[h].val != 0: if t.data[h].key == key: return h h = nextTry(h, high(t.data)) - result = -1 + result = -1 - h # < 0 => MISSING; insert idx = -1 - result proc `[]`*[A](t: CountTable[A], key: A): int = ## retrieves the value at ``t[key]``. If `key` is not in `t`, @@ -702,21 +818,27 @@ proc enlarge[A](t: var CountTable[A]) = proc `[]=`*[A](t: var CountTable[A], key: A, val: int) = ## puts a (key, value)-pair into `t`. `val` has to be positive. assert val > 0 - putImpl() + var h = rawGet(t, key) + if h >= 0: + t.data[h].val = val + else: + h = -1 - h + t.data[h].key = key + t.data[h].val = val proc initCountTable*[A](initialSize=64): CountTable[A] = ## creates a new count table that is empty. ## ## `initialSize` needs to be a power of two. If you need to accept runtime ## values for this you could use the ``nextPowerOfTwo`` proc from the - ## `math <math.html>`_ module. + ## `math <math.html>`_ module or the ``rightSize`` proc in this module. assert isPowerOfTwo(initialSize) result.counter = 0 newSeq(result.data, initialSize) proc toCountTable*[A](keys: openArray[A]): CountTable[A] = ## creates a new count table with every key in `keys` having a count of 1. - result = initCountTable[A](nextPowerOfTwo(keys.len+10)) + result = initCountTable[A](rightSize(keys.len)) for key in items(keys): result[key] = 1 proc `$`*[A](t: CountTable[A]): string = @@ -827,13 +949,13 @@ proc newCountTable*[A](initialSize=64): CountTableRef[A] = ## ## `initialSize` needs to be a power of two. If you need to accept runtime ## values for this you could use the ``nextPowerOfTwo`` proc from the - ## `math <math.html>`_ module. + ## `math <math.html>`_ module or the ``rightSize`` method in this module. new(result) result[] = initCountTable[A](initialSize) proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] = ## creates a new count table with every key in `keys` having a count of 1. - result = newCountTable[A](nextPowerOfTwo(keys.len+10)) + result = newCountTable[A](rightSize(keys.len)) for key in items(keys): result[key] = 1 proc `$`*[A](t: CountTableRef[A]): string = diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 7942255cb..f24cc0072 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -46,7 +46,7 @@ proc `+`*(a, b: Color): Color = colorOp(satPlus) proc `-`*(a, b: Color): Color = - ## substracts two colors: This uses saturated artithmetic, so that each color + ## subtracts two colors: This uses saturated artithmetic, so that each color ## component cannot overflow (255 is used as a maximum). colorOp(satMinus) @@ -392,7 +392,7 @@ proc parseColor*(name: string): Color = result = Color(parseHexInt(name)) else: var idx = binaryStrSearch(colorNames, name) - if idx < 0: raise newException(ValueError, "unkown color: " & name) + if idx < 0: raise newException(ValueError, "unknown color: " & name) result = colorNames[idx][1] proc isColor*(name: string): bool = diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 04cffe4e4..8577bf7a1 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -27,6 +27,11 @@ type {.deprecated: [TComplex: Complex].} +proc toComplex*(x: SomeInteger): Complex = + ## Convert some integer ``x`` to a complex number. + result.re = x + result.im = 0 + proc `==` *(x, y: Complex): bool = ## Compare two complex numbers `x` and `y` for equality. result = x.re == y.re and x.im == y.im @@ -269,27 +274,101 @@ proc tan*(z: Complex): Complex = ## Returns the tangent of `z`. result = sin(z)/cos(z) +proc arctan*(z: Complex): Complex = + ## Returns the inverse tangent of `z`. + var i: Complex = (0.0,1.0) + result = 0.5*i*(ln(1-i*z)-ln(1+i*z)) + proc cot*(z: Complex): Complex = ## Returns the cotangent of `z`. result = cos(z)/sin(z) +proc arccot*(z: Complex): Complex = + ## Returns the inverse cotangent of `z`. + var i: Complex = (0.0,1.0) + result = 0.5*i*(ln(1-i/z)-ln(1+i/z)) + proc sec*(z: Complex): Complex = ## Returns the secant of `z`. result = 1.0/cos(z) +proc arcsec*(z: Complex): Complex = + ## Returns the inverse secant of `z`. + var i: Complex = (0.0,1.0) + result = -i*ln(i*sqrt(1-1/(z*z))+1/z) + proc csc*(z: Complex): Complex = ## Returns the cosecant of `z`. result = 1.0/sin(z) +proc arccsc*(z: Complex): Complex = + ## Returns the inverse cosecant of `z`. + var i: Complex = (0.0,1.0) + result = -i*ln(sqrt(1-1/(z*z))+i/z) + proc sinh*(z: Complex): Complex = ## Returns the hyperbolic sine of `z`. result = 0.5*(exp(z)-exp(-z)) +proc arcsinh*(z: Complex): Complex = + ## Returns the inverse hyperbolic sine of `z`. + result = ln(z+sqrt(z*z+1)) + proc cosh*(z: Complex): Complex = ## Returns the hyperbolic cosine of `z`. result = 0.5*(exp(z)+exp(-z)) +proc arccosh*(z: Complex): Complex = + ## Returns the inverse hyperbolic cosine of `z`. + result = ln(z+sqrt(z*z-1)) + +proc tanh*(z: Complex): Complex = + ## Returns the hyperbolic tangent of `z`. + result = sinh(z)/cosh(z) + +proc arctanh*(z: Complex): Complex = + ## Returns the inverse hyperbolic tangent of `z`. + result = 0.5*(ln((1+z)/(1-z))) + +proc sech*(z: Complex): Complex = + ## Returns the hyperbolic secant of `z`. + result = 2/(exp(z)+exp(-z)) + +proc arcsech*(z: Complex): Complex = + ## Returns the inverse hyperbolic secant of `z`. + result = ln(1/z+sqrt(1/z+1)*sqrt(1/z-1)) + +proc csch*(z: Complex): Complex = + ## Returns the hyperbolic cosecant of `z`. + result = 2/(exp(z)-exp(-z)) + +proc arccsch*(z: Complex): Complex = + ## Returns the inverse hyperbolic cosecant of `z`. + result = ln(1/z+sqrt(1/(z*z)+1)) + +proc coth*(z: Complex): Complex = + ## Returns the hyperbolic cotangent of `z`. + result = cosh(z)/sinh(z) + +proc arccoth*(z: Complex): Complex = + ## Returns the inverse hyperbolic cotangent of `z`. + result = 0.5*(ln(1+1/z)-ln(1-1/z)) + +proc phase*(z: Complex): float = + ## Returns the phase of `z`. + arctan2(z.im, z.re) + +proc polar*(z: Complex): tuple[r, phi: float] = + ## Returns `z` in polar coordinates. + result.r = abs(z) + result.phi = phase(z) + +proc rect*(r: float, phi: float): Complex = + ## Returns the complex number with polar coordinates `r` and `phi`. + result.re = r * cos(phi) + result.im = r * sin(phi) + proc `$`*(z: Complex): string = ## Returns `z`'s string representation as ``"(re, im)"``. @@ -343,7 +422,22 @@ when isMainModule: assert( csc(a) =~ 1.0/sin(a) ) assert( arcsin(a) =~ (0.427078586392476, 1.528570919480998) ) assert( arccos(a) =~ (1.14371774040242, -1.52857091948100) ) + assert( arctan(a) =~ (1.338972522294494, 0.402359478108525) ) - assert( cosh(a) =~ (-0.642148124715520, 1.068607421382778) ) + assert( cosh(a) =~ (-0.642148124715520, 1.068607421382778) ) assert( sinh(a) =~ (-0.489056259041294, 1.403119250622040) ) - \ No newline at end of file + assert( tanh(a) =~ (1.1667362572409199,-0.243458201185725) ) + assert( sech(a) =~ 1/cosh(a) ) + assert( csch(a) =~ 1/sinh(a) ) + assert( coth(a) =~ 1/tanh(a) ) + assert( arccosh(a) =~ (1.528570919480998, 1.14371774040242) ) + assert( arcsinh(a) =~ (1.469351744368185, 1.06344002357775) ) + assert( arctanh(a) =~ (0.173286795139986, 1.17809724509617) ) + assert( arcsech(a) =~ arccosh(1/a) ) + assert( arccsch(a) =~ arcsinh(1/a) ) + assert( arccoth(a) =~ arctanh(1/a) ) + + assert( phase(a) == 1.1071487177940904 ) + var t = polar(a) + assert( rect(t.r, t.phi) =~ a ) + assert( rect(1.0, 2.0) =~ (-0.4161468365471424, 0.9092974268256817) ) diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 298a6072d..25c7ad9ef 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -301,7 +301,7 @@ proc getCurrentEncoding*(): string = proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): EncodingConverter = ## opens a converter that can convert from `srcEncoding` to `destEncoding`. - ## Raises `EIO` if it cannot fullfill the request. + ## Raises `EIO` if it cannot fulfill the request. when not defined(windows): result = iconvOpen(destEncoding, srcEncoding) if result == nil: diff --git a/lib/pure/events.nim b/lib/pure/events.nim index 77faa6a66..44e9ed286 100644 --- a/lib/pure/events.nim +++ b/lib/pure/events.nim @@ -9,7 +9,7 @@ ## :Author: Alex Mitchell ## -## 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. It was originally called ``NimEE`` because ## it was inspired by Python's PyEE module. There are two ways you can use ## events: one is a python-inspired way; the other is more of a C-style way. diff --git a/lib/pure/fsmonitor.nim b/lib/pure/fsmonitor.nim index bf4aef61c..e6919b661 100644 --- a/lib/pure/fsmonitor.nim +++ b/lib/pure/fsmonitor.nim @@ -29,7 +29,7 @@ type FSMonitorObj = object of RootObj fd: cint handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.} - targets: TTable[cint, string] + targets: Table[cint, string] MonitorEventType* = enum ## Monitor event type MonitorAccess, ## File was accessed. @@ -64,7 +64,7 @@ type const MaxEvents = 100 -proc newMonitor*(): PFSMonitor = +proc newMonitor*(): FSMonitor = ## Creates a new file system monitor. new(result) result.targets = initTable[cint, string]() @@ -72,7 +72,7 @@ proc newMonitor*(): PFSMonitor = if result.fd < 0: raiseOSError(osLastError()) -proc add*(monitor: PFSMonitor, target: string, +proc add*(monitor: FSMonitor, target: string, filters = {MonitorAll}): cint {.discardable.} = ## Adds ``target`` which may be a directory or a file to the list of ## watched paths of ``monitor``. @@ -99,14 +99,14 @@ proc add*(monitor: PFSMonitor, target: string, raiseOSError(osLastError()) monitor.targets.add(result, target) -proc del*(monitor: PFSMonitor, wd: cint) = +proc del*(monitor: FSMonitor, wd: cint) = ## Removes watched directory or file as specified by ``wd`` from ``monitor``. ## ## If ``wd`` is not a part of ``monitor`` an EOS error is raised. if inotifyRmWatch(monitor.fd, wd) < 0: raiseOSError(osLastError()) -proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] = +proc getEvent(m: FSMonitor, fd: cint): seq[MonitorEvent] = result = @[] let size = (sizeof(TINotifyEvent)+2000)*MaxEvents var buffer = newString(size) @@ -118,7 +118,7 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] = var i = 0 while i < le: var event = cast[ptr TINotifyEvent](addr(buffer[i])) - var mev: TMonitorEvent + var mev: MonitorEvent mev.wd = event.wd if event.len.int != 0: let cstr = event.name.addr.cstring @@ -137,7 +137,7 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] = # Find the MovedFrom event. mev.oldPath = movedFrom[event.cookie.cint].old mev.newPath = "" # Set later - # Delete it from the TTable + # Delete it from the Table movedFrom.del(event.cookie.cint) elif (event.mask.int and IN_ACCESS) != 0: mev.kind = MonitorAccess elif (event.mask.int and IN_ATTRIB) != 0: mev.kind = MonitorAttrib @@ -164,26 +164,26 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] = # If movedFrom events have not been matched with a moveTo. File has # been moved to an unwatched location, emit a MonitorDelete. for cookie, t in pairs(movedFrom): - var mev: TMonitorEvent + var mev: MonitorEvent mev.kind = MonitorDelete mev.wd = t.wd mev.name = t.old result.add(mev) -proc FSMonitorRead(h: PObject) = - var events = PFSMonitor(h).getEvent(PFSMonitor(h).fd) - #var newEv: TMonitorEvent +proc FSMonitorRead(h: RootRef) = + var events = FSMonitor(h).getEvent(FSMonitor(h).fd) + #var newEv: MonitorEvent for ev in events: - var target = PFSMonitor(h).targets[ev.wd] + var target = FSMonitor(h).targets[ev.wd] var newEv = ev if newEv.kind == MonitorMoved: newEv.oldPath = target / newEv.oldPath newEv.newPath = target / newEv.name else: newEv.fullName = target / newEv.name - PFSMonitor(h).handleEvent(PFSMonitor(h), newEv) + FSMonitor(h).handleEvent(FSMonitor(h), newEv) -proc toDelegate(m: PFSMonitor): PDelegate = +proc toDelegate(m: FSMonitor): Delegate = result = newDelegate() result.deleVal = m result.fd = (type(result.fd))(m.fd) @@ -191,8 +191,8 @@ proc toDelegate(m: PFSMonitor): PDelegate = result.handleRead = FSMonitorRead result.open = true -proc register*(d: PDispatcher, monitor: PFSMonitor, - handleEvent: proc (m: PFSMonitor, ev: TMonitorEvent) {.closure.}) = +proc register*(d: Dispatcher, monitor: FSMonitor, + handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.}) = ## Registers ``monitor`` with dispatcher ``d``. monitor.handleEvent = handleEvent var deleg = toDelegate(monitor) @@ -204,7 +204,7 @@ when isMainModule: var monitor = newMonitor() echo monitor.add("/home/dom/inotifytests/") disp.register(monitor, - proc (m: PFSMonitor, ev: TMonitorEvent) = + proc (m: FSMonitor, ev: MonitorEvent) = echo("Got event: ", ev.kind) if ev.kind == MonitorMoved: echo("From ", ev.oldPath, " to ", ev.newPath) diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index 40ee5951b..46af1d528 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -107,7 +107,7 @@ type EInvalidReply: ReplyError, EFTP: FTPError ].} -proc ftpClient*(address: string, port = TPort(21), +proc ftpClient*(address: string, port = Port(21), user, pass = ""): FtpClient = ## Create a ``FtpClient`` object. new(result) @@ -120,10 +120,10 @@ proc ftpClient*(address: string, port = TPort(21), result.csock = socket() if result.csock == invalidSocket: raiseOSError(osLastError()) -template blockingOperation(sock: TSocket, body: stmt) {.immediate.} = +template blockingOperation(sock: Socket, body: stmt) {.immediate.} = body -template blockingOperation(sock: asyncio.PAsyncSocket, body: stmt) {.immediate.} = +template blockingOperation(sock: asyncio.AsyncSocket, body: stmt) {.immediate.} = sock.setBlocking(true) body sock.setBlocking(false) @@ -145,14 +145,14 @@ proc send*[T](ftp: FtpBase[T], m: string): TaintedString = proc assertReply(received: TaintedString, expected: string) = if not received.string.startsWith(expected): - raise newException(EInvalidReply, + raise newException(ReplyError, "Expected reply '$1' got: $2" % [ expected, received.string]) proc assertReply(received: TaintedString, expected: varargs[string]) = for i in items(expected): if received.string.startsWith(i): return - raise newException(EInvalidReply, + raise newException(ReplyError, "Expected reply '$1' got: $2" % [expected.join("' or '"), received.string]) @@ -161,7 +161,7 @@ proc createJob[T](ftp: FtpBase[T], nimcall,gcsafe.}, cmd: FTPJobType) = if ftp.jobInProgress: - raise newException(EFTP, "Unable to do two jobs at once.") + raise newException(FTPError, "Unable to do two jobs at once.") ftp.jobInProgress = true new(ftp.job) ftp.job.prc = prc @@ -182,11 +182,11 @@ proc deleteJob[T](ftp: FtpBase[T]) = ftp.job.file.close() ftp.dsock.close() -proc handleTask(s: PAsyncSocket, ftp: PAsyncFTPClient) = +proc handleTask(s: AsyncSocket, ftp: AsyncFTPClient) = if ftp.jobInProgress: if ftp.job.typ in {JRetr, JStore}: if epochTime() - ftp.job.lastProgressReport >= 1.0: - var r: TFTPEvent + var r: FTPEvent ftp.job.lastProgressReport = epochTime() r.typ = EvTransferProgress r.bytesTotal = ftp.job.total @@ -195,22 +195,22 @@ proc handleTask(s: PAsyncSocket, ftp: PAsyncFTPClient) = r.filename = ftp.job.filename r.currentJob = ftp.job.typ ftp.job.oneSecond = 0 - ftp.handleEvent(PAsyncFTPClient(ftp), r) + ftp.handleEvent(ftp, r) -proc handleWrite(s: PAsyncSocket, ftp: PAsyncFTPClient) = +proc handleWrite(s: AsyncSocket, ftp: AsyncFTPClient) = if ftp.jobInProgress: if ftp.job.typ == JStore: assert (not ftp.job.prc(ftp, true)) -proc handleConnect(s: PAsyncSocket, ftp: PAsyncFTPClient) = +proc handleConnect(s: AsyncSocket, ftp: AsyncFTPClient) = ftp.dsockConnected = true assert(ftp.jobInProgress) if ftp.job.typ == JStore: - s.setHandleWrite(proc (s: PAsyncSocket) = handleWrite(s, ftp)) + s.setHandleWrite(proc (s: AsyncSocket) = handleWrite(s, ftp)) else: s.delHandleWrite() -proc handleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) = +proc handleRead(s: AsyncSocket, ftp: AsyncFTPClient) = assert ftp.jobInProgress assert ftp.job.typ != JStore # This can never return true, because it shouldn't check for code @@ -219,19 +219,19 @@ proc handleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) = proc pasv[T](ftp: FtpBase[T]) = ## Negotiate a data connection. - when T is TSocket: + when T is Socket: ftp.dsock = socket() if ftp.dsock == invalidSocket: raiseOSError(osLastError()) - elif T is PAsyncSocket: + elif T is AsyncSocket: ftp.dsock = asyncSocket() ftp.dsock.handleRead = - proc (s: PAsyncSocket) = + proc (s: AsyncSocket) = handleRead(s, ftp) ftp.dsock.handleConnect = - proc (s: PAsyncSocket) = + proc (s: AsyncSocket) = handleConnect(s, ftp) ftp.dsock.handleTask = - proc (s: PAsyncSocket) = + proc (s: AsyncSocket) = handleTask(s, ftp) ftp.disp.register(ftp.dsock) else: @@ -244,8 +244,8 @@ proc pasv[T](ftp: FtpBase[T]) = var ip = nums[0.. -3] var port = nums[-2.. -1] var properPort = port[0].parseInt()*256+port[1].parseInt() - ftp.dsock.connect(ip.join("."), TPort(properPort.toU16)) - when T is PAsyncSocket: + ftp.dsock.connect(ip.join("."), Port(properPort.toU16)) + when T is AsyncSocket: ftp.dsockConnected = false else: ftp.dsockConnected = true @@ -255,10 +255,10 @@ proc normalizePathSep(path: string): string = proc connect*[T](ftp: FtpBase[T]) = ## Connect to the FTP server specified by ``ftp``. - when T is PAsyncSocket: + when T is AsyncSocket: blockingOperation(ftp.csock): ftp.csock.connect(ftp.address, ftp.port) - elif T is TSocket: + elif T is Socket: ftp.csock.connect(ftp.address, ftp.port) else: {.fatal: "Incorrect socket instantiation".} @@ -292,13 +292,13 @@ proc getLines[T](ftp: FtpBase[T], async: bool = false): bool = ## It doesn't if `async` is true, because it doesn't check for 226 then. if ftp.dsockConnected: var r = TaintedString"" - when T is PAsyncSocket: + when T is AsyncSocket: if ftp.asyncDSock.readLine(r): if r.string == "": ftp.dsockConnected = false else: ftp.job.lines.add(r.string & "\n") - elif T is TSocket: + elif T is Socket: assert(not async) ftp.dsock.readLine(r) if r.string == "": @@ -309,7 +309,7 @@ proc getLines[T](ftp: FtpBase[T], async: bool = false): bool = {.fatal: "Incorrect socket instantiation".} if not async: - var readSocks: seq[TSocket] = @[ftp.csock] + var readSocks: seq[Socket] = @[ftp.csock] # This is only needed here. Asyncio gets this socket... blockingOperation(ftp.csock): if readSocks.select(1) != 0 and ftp.csock in readSocks: @@ -372,7 +372,7 @@ proc createDir*[T](ftp: FtpBase[T], dir: string, recursive: bool = false) = assertReply reply, "257" proc chmod*[T](ftp: FtpBase[T], path: string, - permissions: set[TFilePermission]) = + permissions: set[FilePermission]) = ## Changes permission of ``path`` to ``permissions``. var userOctal = 0 var groupOctal = 0 @@ -431,8 +431,8 @@ proc getFile[T](ftp: FtpBase[T], async = false): bool = var bytesRead = 0 var returned = false if async: - when T is TSocket: - raise newException(EFTP, "FTPClient must be async.") + when T is Socket: + raise newException(FTPError, "FTPClient must be async.") else: bytesRead = ftp.dsock.recvAsync(r, BufferSize) returned = bytesRead != -1 @@ -447,9 +447,9 @@ proc getFile[T](ftp: FtpBase[T], async = false): bool = elif returned and r2 == "": ftp.dsockConnected = false - when T is TSocket: + when T is Socket: if not async: - var readSocks: seq[TSocket] = @[ftp.csock] + var readSocks: seq[Socket] = @[ftp.csock] blockingOperation(ftp.csock): if readSocks.select(1) != 0 and ftp.csock in readSocks: assertReply ftp.expectReply(), "226" @@ -467,10 +467,10 @@ proc retrFile*[T](ftp: FtpBase[T], file, dest: string, async = false) = var reply = ftp.send("RETR " & file.normalizePathSep) assertReply reply, ["125", "150"] if {'(', ')'} notin reply.string: - raise newException(EInvalidReply, "Reply has no file size.") + raise newException(ReplyError, "Reply has no file size.") var fileSize: BiggestInt if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0: - raise newException(EInvalidReply, "Reply has no file size.") + raise newException(ReplyError, "Reply has no file size.") ftp.job.total = fileSize ftp.job.lastProgressReport = epochTime() @@ -545,10 +545,10 @@ proc close*[T](ftp: FtpBase[T]) = ftp.csock.close() ftp.dsock.close() -proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) = +proc csockHandleRead(s: AsyncSocket, ftp: AsyncFTPClient) = if ftp.jobInProgress: assertReply ftp.expectReply(), "226" # Make sure the transfer completed. - var r: TFTPEvent + var r: FTPEvent case ftp.job.typ of JRetrText: r.typ = EvLines @@ -557,21 +557,21 @@ proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) = r.typ = EvRetr r.filename = ftp.job.filename if ftp.job.progress != ftp.job.total: - raise newException(EFTP, "Didn't download full file.") + raise newException(FTPError, "Didn't download full file.") of JStore: r.typ = EvStore r.filename = ftp.job.filename if ftp.job.progress != ftp.job.total: - raise newException(EFTP, "Didn't upload full file.") + raise newException(FTPError, "Didn't upload full file.") ftp.deleteJob() ftp.handleEvent(ftp, r) -proc asyncFTPClient*(address: string, port = TPort(21), +proc asyncFTPClient*(address: string, port = Port(21), user, pass = "", - handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure,gcsafe.} = - (proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = discard)): PAsyncFTPClient = - ## Create a ``PAsyncFTPClient`` object. + handleEvent: proc (ftp: AsyncFTPClient, ev: FTPEvent) {.closure,gcsafe.} = + (proc (ftp: AsyncFTPClient, ev: FTPEvent) = discard)): AsyncFTPClient = + ## Create a ``AsyncFTPClient`` object. ## ## Use this if you want to use asyncio's dispatcher. var dres: AsyncFtpClient @@ -588,7 +588,7 @@ proc asyncFTPClient*(address: string, port = TPort(21), csockHandleRead(s, dres) result = dres -proc register*(d: PDispatcher, ftp: PAsyncFTPClient): PDelegate {.discardable.} = +proc register*(d: Dispatcher, ftp: AsyncFTPClient): Delegate {.discardable.} = ## Registers ``ftp`` with dispatcher ``d``. ftp.disp = d return ftp.disp.register(ftp.csock) diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index e2cbb4949..5e4eba4e5 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -552,7 +552,7 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode = proc parseHtml*(s: Stream, filename: string, errors: var seq[string]): XmlNode = ## parses the XML from stream `s` and returns a ``PXmlNode``. Every - ## occured parsing error is added to the `errors` sequence. + ## occurred parsing error is added to the `errors` sequence. var x: XmlParser open(x, s, filename, {reportComments, reportWhitespace}) next(x) @@ -581,7 +581,7 @@ proc parseHtml*(s: Stream): XmlNode = proc loadHtml*(path: string, errors: var seq[string]): XmlNode = ## Loads and parses HTML from file specified by ``path``, and returns - ## a ``PXmlNode``. Every occured parsing error is added to + ## a ``PXmlNode``. Every occurred parsing error is added to ## the `errors` sequence. var s = newFileStream(path, fmRead) if s == nil: raise newException(IOError, "Unable to read file: " & path) diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 3c1401887..37af14df3 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -385,7 +385,7 @@ proc request*(url: string, httpMethod: string, extraHeaders = "", userAgent = defUserAgent, proxy: Proxy = nil): Response = ## | Requests ``url`` with the custom method string specified by the ## | ``httpMethod`` parameter. - ## | Extra headers can be specified and must be seperated by ``\c\L`` + ## | Extra headers can be specified and must be separated by ``\c\L`` ## | An optional timeout can be specified in miliseconds, if reading from the ## server takes longer than specified an ETimeout exception will be raised. var r = if proxy == nil: parseUri(url) else: proxy.url @@ -436,7 +436,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "", body = "", sslContext = defaultSSLContext, timeout = -1, userAgent = defUserAgent, proxy: Proxy = nil): Response = ## | Requests ``url`` with the specified ``httpMethod``. - ## | Extra headers can be specified and must be seperated by ``\c\L`` + ## | Extra headers can be specified and must be separated by ``\c\L`` ## | An optional timeout can be specified in miliseconds, if reading from the ## server takes longer than specified an ETimeout exception will be raised. result = request(url, $httpMethod, extraHeaders, body, sslContext, timeout, diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim index 38a068ea1..5efdbe297 100644 --- a/lib/pure/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -363,7 +363,7 @@ proc run*(handleRequest: proc (client: Socket, port = Port(80)) = ## encapsulates the server object and main loop var s: TServer - open(s, port) + open(s, port, reuseAddr = true) #echo("httpserver running on port ", s.port) while true: next(s) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 873e4b78e..2038b246d 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -30,13 +30,32 @@ ## ## 1.3000000000000000e+00 ## true +## +## This module can also be used to comfortably create JSON using the `%*` +## operator: +## +## .. code-block:: nim +## +## var hisName = "John" +## let herAge = 31 +## var j = %* +## [ +## { +## "name": hisName, +## "age": 30 +## }, +## { +## "name": "Susan", +## "age": herAge +## } +## ] import - hashes, strutils, lexbase, streams, unicode + hashes, strutils, lexbase, streams, unicode, macros type JsonEventKind* = enum ## enumeration of all events that may occur when parsing - jsonError, ## an error ocurred during parsing + jsonError, ## an error occurred during parsing jsonEof, ## end of file reached jsonString, ## a string literal jsonInt, ## an integer literal @@ -625,6 +644,29 @@ proc `%`*(elements: openArray[JsonNode]): JsonNode = newSeq(result.elems, elements.len) for i, p in pairs(elements): result.elems[i] = p +proc toJson(x: PNimrodNode): PNimrodNode {.compiletime.} = + case x.kind + of nnkBracket: + result = newNimNode(nnkBracket) + for i in 0 .. <x.len: + result.add(toJson(x[i])) + + of nnkTableConstr: + result = newNimNode(nnkTableConstr) + for i in 0 .. <x.len: + assert x[i].kind == nnkExprColonExpr + result.add(newNimNode(nnkExprColonExpr).add(x[i][0]).add(toJson(x[i][1]))) + + else: + result = x + + result = prefix(result, "%") + +macro `%*`*(x: expr): expr = + ## Convert an expression to a JsonNode directly, without having to specify + ## `%` for every element. + result = toJson(x) + proc `==`* (a,b: JsonNode): bool = ## Check two nodes for equality if a.isNil: @@ -864,7 +906,7 @@ proc pretty*(node: JsonNode, indent = 2): string = proc `$`*(node: JsonNode): string = ## Converts `node` to its JSON Representation on one line. result = "" - toPretty(result, node, 1, false) + toPretty(result, node, 0, false) iterator items*(node: JsonNode): JsonNode = ## Iterator for the items of `node`. `node` has to be a JArray. @@ -1101,6 +1143,37 @@ when isMainModule: except: assert(false, "EInvalidIndex thrown for valid index") + # Generator: + var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}] + assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + + var j2 = %* + [ + { + "name": "John", + "age": 30 + }, + { + "name": "Susan", + "age": 31 + } + ] + assert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + + var name = "John" + let herAge = 30 + const hisAge = 31 + + var j3 = %* + [ { "name": "John" + , "age": herAge + } + , { "name": "Susan" + , "age": hisAge + } + ] + assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}] + discard """ while true: var json = stdin.readLine() diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index bb1835ed7..b64437c89 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -8,7 +8,7 @@ # ## This module implements a simple logger. It has been designed to be as simple -## as possible to avoid bloat, if this library does not fullfill your needs, +## as possible to avoid bloat, if this library does not fulfill your needs, ## write your own. ## ## Format strings support the following variables which must be prefixed with @@ -186,7 +186,7 @@ proc newRollingFileLogger*(filename = defaultFilename(), ## a new log file will be started and the old will be renamed. new(result) result.levelThreshold = levelThreshold - result.fmtStr = defaultFmtStr + result.fmtStr = fmtStr result.maxLines = maxLines result.f = open(filename, mode) result.curLine = 0 diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim index 1188be4ca..d55963c15 100644 --- a/lib/pure/matchers.nim +++ b/lib/pure/matchers.nim @@ -42,7 +42,7 @@ proc validEmailAddress*(s: string): bool {.noSideEffect, case toLower(x) of "com", "org", "net", "gov", "mil", "biz", "info", "mobi", "name", "aero", "jobs", "museum": return true - return false + else: return false proc parseInt*(s: string, value: var int, validRange: Slice[int]) {. noSideEffect, rtl, extern: "nmatchParseInt".} = diff --git a/lib/pure/math.nim b/lib/pure/math.nim index b9e057e78..c902af381 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -93,9 +93,9 @@ proc nextPowerOfTwo*(x: int): int {.noSideEffect.} = result = x - 1 when defined(cpu64): result = result or (result shr 32) - when sizeof(int) > 16: + when sizeof(int) > 2: result = result or (result shr 16) - when sizeof(int) > 8: + when sizeof(int) > 1: result = result or (result shr 8) result = result or (result shr 4) result = result or (result shr 2) @@ -129,25 +129,25 @@ proc variance*(x: openArray[float]): float {.noSideEffect.} = result = result + diff*diff result = result / toFloat(len(x)) -proc random*(max: int): int {.gcsafe.} +proc random*(max: int): int {.benign.} ## returns a random number in the range 0..max-1. The sequence of ## random number is always the same, unless `randomize` is called ## which initializes the random number generator with a "random" ## number, i.e. a tickcount. -proc random*(max: float): float {.gcsafe.} +proc random*(max: float): float {.benign.} ## returns a random number in the range 0..<max. The sequence of ## random number is always the same, unless `randomize` is called ## which initializes the random number generator with a "random" ## number, i.e. a tickcount. This has a 16-bit resolution on windows ## and a 48-bit resolution on other platforms. -proc randomize*() {.gcsafe.} +proc randomize*() {.benign.} ## initializes the random number generator with a "random" ## number, i.e. a tickcount. Note: Does nothing for the JavaScript target, ## as JavaScript does not support this. -proc randomize*(seed: int) {.gcsafe.} +proc randomize*(seed: int) {.benign.} ## initializes the random number generator with a specific seed. ## Note: Does nothing for the JavaScript target, ## as JavaScript does not support this. @@ -280,7 +280,7 @@ proc random*[T](x: Slice[T]): T = ## For a slice `a .. b` returns a value in the range `a .. b-1`. result = random(x.b - x.a) + x.a -proc random[T](a: openArray[T]): T = +proc random*[T](a: openArray[T]): T = ## returns a random element from the openarray `a`. result = a[random(a.low..a.len)] @@ -329,6 +329,31 @@ proc standardDeviation*(s: RunningStat): float = {.pop.} {.pop.} +proc `^`*[T](x, y: T): T = + ## Computes ``x`` to the power ``y`. ``x`` must be non-negative, use + ## `pow <#pow,float,float>` for negative exponents. + assert y >= 0 + var (x, y) = (x, y) + result = 1 + + while y != 0: + if (y and 1) != 0: + result *= x + y = y shr 1 + x *= x + +proc gcd*[T](x, y: T): T = + ## Computes the greatest common divisor of ``x`` and ``y``. + var (x,y) = (x,y) + while y != 0: + x = x mod y + swap x, y + abs x + +proc lcm*[T](x, y: T): T = + ## Computes the least common multiple of ``x`` and ``y``. + x div gcd(x, y) * y + when isMainModule and not defined(JS): proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".} diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 4eacfea78..bed751542 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -60,7 +60,8 @@ type sslHasPeekChar: bool sslPeekChar: char of false: nil - + lastError: OSErrorCode ## stores the last error on this socket + Socket* = ref SocketImpl SOBool* = enum ## Boolean socket options. @@ -231,6 +232,15 @@ when defined(ssl): if SSLSetFd(socket.sslHandle, socket.fd) != 1: raiseSSLError() +proc getSocketError*(socket: Socket): OSErrorCode = + ## Checks ``osLastError`` for a valid error. If it has been reset it uses + ## the last error stored in the socket object. + result = osLastError() + if result == 0.OSErrorCode: + result = socket.lastError + if result == 0.OSErrorCode: + raise newException(OSError, "No valid socket error code available") + proc socketError*(socket: Socket, err: int = -1, async = false, lastError = (-1).OSErrorCode) = ## Raises an OSError based on the error code returned by ``SSLGetError`` @@ -258,7 +268,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false, of SSL_ERROR_WANT_X509_LOOKUP: raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL: - var errStr = "IO error has occured " + var errStr = "IO error has occurred " let sslErr = ErrPeekLastError() if sslErr == 0 and err == 0: errStr.add "because an EOF was observed that violates the protocol" @@ -276,7 +286,7 @@ proc socketError*(socket: Socket, err: int = -1, async = false, else: raiseSSLError("Unknown Error") if err == -1 and not (when defined(ssl): socket.isSSL else: false): - let lastE = if lastError.int == -1: osLastError() else: lastError + var lastE = if lastError.int == -1: getSocketError(socket) else: lastError if async: when useWinVersion: if lastE.int32 == WSAEWOULDBLOCK: @@ -294,7 +304,8 @@ proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} = ## queue of pending connections. ## ## Raises an EOS error upon failure. - if listen(socket.fd, backlog) < 0'i32: raiseOSError(osLastError()) + if rawsockets.listen(socket.fd, backlog) < 0'i32: + raiseOSError(osLastError()) proc bindAddr*(socket: Socket, port = Port(0), address = "") {. tags: [ReadIOEffect].} = @@ -321,7 +332,8 @@ proc bindAddr*(socket: Socket, port = Port(0), address = "") {. dealloc(aiList) proc acceptAddr*(server: Socket, client: var Socket, address: var string, - flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} = + flags = {SocketFlag.SafeDisconn}) {. + tags: [ReadIOEffect], gcsafe, locks: 0.} = ## Blocks until a connection is being made from a client. When a connection ## is made sets ``client`` to the client socket and ``address`` to the address ## of the connecting client. @@ -442,6 +454,8 @@ proc close*(socket: Socket) = # shutdown i.e not wait for the peers "close notify" alert with a second # call to SSLShutdown let res = SSLShutdown(socket.sslHandle) + SSLFree(socket.sslHandle) + socket.sslHandle = nil if res == 0: discard elif res != 1: @@ -568,6 +582,10 @@ proc readIntoBuf(socket: Socket, flags: int32): int = result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags) else: result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags) + if result < 0: + # Save it in case it gets reset (the Nim codegen occassionally may call + # Win API functions which reset it). + socket.lastError = osLastError() if result <= 0: socket.bufLen = 0 socket.currPos = 0 @@ -623,6 +641,9 @@ proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect] result = recv(socket.fd, data, size.cint, 0'i32) else: result = recv(socket.fd, data, size.cint, 0'i32) + if result < 0: + # Save the error in case it gets reset. + socket.lastError = osLastError() proc waitFor(socket: Socket, waited: var float, timeout, size: int, funcName: string): int {.tags: [TimeEffect].} = @@ -695,7 +716,7 @@ proc recv*(socket: Socket, data: var string, size: int, timeout = -1, result = recv(socket, cstring(data), size, timeout) if result < 0: data.setLen(0) - let lastError = osLastError() + let lastError = getSocketError(socket) if flags.isDisconnectionError(lastError): return socket.socketError(result, lastError = lastError) data.setLen(result) @@ -743,7 +764,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1, line.add("\c\L") template raiseSockError(): stmt {.dirty, immediate.} = - let lastError = osLastError() + let lastError = getSocketError(socket) if flags.isDisconnectionError(lastError): setLen(line.string, 0); return socket.socketError(n, lastError = lastError) @@ -886,7 +907,7 @@ proc connectAsync(socket: Socket, name: string, port = Port(0), af: Domain = AF_INET) {.tags: [ReadIOEffect].} = ## A variant of ``connect`` for non-blocking sockets. ## - ## This procedure will immediatelly return, it will not block until a connection + ## This procedure will immediately return, it will not block until a connection ## is made. It is up to the caller to make sure the connection has been established ## by checking (using ``select``) whether the socket is writeable. ## @@ -938,8 +959,12 @@ proc connect*(socket: Socket, address: string, port = Port(0), timeout: int, doAssert socket.handshake() socket.fd.setBlocking(true) -proc isSsl*(socket: Socket): bool = return socket.isSSL +proc isSsl*(socket: Socket): bool = ## Determines whether ``socket`` is a SSL socket. + when defined(ssl): + result = socket.isSSL + else: + result = false proc getFd*(socket: Socket): SocketHandle = return socket.fd ## Returns the socket's file descriptor diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 3598cdd3a..cce2a20ae 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -132,7 +132,7 @@ else: proc hook(st: TStackTrace) {.nimcall.} = if interval == 0: hookAux(st, 1) - elif getTicks() - t0 > interval: + elif int64(t0) == 0 or getTicks() - t0 > interval: hookAux(st, 1) t0 = getTicks() diff --git a/lib/pure/nimprof.nimrod.cfg b/lib/pure/nimprof.nim.cfg index 1589e7394..1589e7394 100644 --- a/lib/pure/nimprof.nimrod.cfg +++ b/lib/pure/nimprof.nim.cfg diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 147614d3d..bf581667b 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -185,7 +185,7 @@ const proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} = ## Retrieves the operating system's error flag, ``errno``. ## On Windows ``GetLastError`` is checked before ``errno``. - ## Returns "" if no error occured. + ## Returns "" if no error occurred. ## ## **Deprecated since version 0.9.4**: use the other ``osErrorMsg`` proc. @@ -1010,8 +1010,16 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", tags: [ReadIOEffect, WriteIOEffect].} = ## Moves a file from `source` to `dest`. If this fails, `OSError` is raised. - if c_rename(source, dest) != 0'i32: - raise newException(OSError, $strerror(errno)) + when defined(Windows): + when useWinUnicode: + let s = newWideCString(source) + let d = newWideCString(dest) + if moveFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError()) + else: + if moveFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError()) + else: + if c_rename(source, dest) != 0'i32: + raise newException(OSError, $strerror(errno)) when not declared(ENOENT) and not defined(Windows): when NoFakeVars: @@ -1074,8 +1082,12 @@ when defined(windows): # because we support Windows GUI applications, things get really # messy here... when useWinUnicode: - proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. - importc: "wcschr", header: "<string.h>".} + when defined(cpp): + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. + importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "<string.h>".} + else: + proc strEnd(cstr: WideCString, c = 0'i32): WideCString {. + importc: "wcschr", header: "<string.h>".} else: proc strEnd(cstr: cstring, c = 0'i32): cstring {. importc: "strchr", header: "<string.h>".} @@ -1087,7 +1099,7 @@ when defined(windows): var env = getEnvironmentStringsW() e = env - if e == nil: return # an error occured + if e == nil: return # an error occurred while true: var eend = strEnd(e) add(environment, $e) @@ -1098,7 +1110,7 @@ when defined(windows): var env = getEnvironmentStringsA() e = env - if e == nil: return # an error occured + if e == nil: return # an error occurred while true: var eend = strEnd(e) add(environment, $e) @@ -1170,7 +1182,7 @@ proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = ## If an error occurs, `EInvalidEnvVar` is raised. # Note: by storing the string in the environment sequence, - # we gurantee that we don't free the memory before the program + # we guarantee that we don't free the memory before the program # ends (this is needed for POSIX compliance). It is also needed so that # the process itself may access its modified environment variables! var indx = findEnvVar(key) @@ -1287,8 +1299,16 @@ iterator walkDir*(dir: string): tuple[kind: PathComponent, path: string] {. if y != "." and y != "..": var s: TStat y = dir / y - if lstat(y, s) < 0'i32: break var k = pcFile + + when defined(linux) or defined(macosx) or defined(bsd): + if x.d_type != DT_UNKNOWN: + if x.d_type == DT_DIR: k = pcDir + if x.d_type == DT_LNK: k = succ(k) + yield (k, y) + continue + + if lstat(y, s) < 0'i32: break if S_ISDIR(s.st_mode): k = pcDir if S_ISLNK(s.st_mode): k = succ(k) yield (k, y) @@ -1335,7 +1355,7 @@ proc rawRemoveDir(dir: string) = if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError()) proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ - WriteDirEffect, ReadDirEffect].} = + WriteDirEffect, ReadDirEffect], benign.} = ## Removes the directory `dir` including all subdirectories and files ## in `dir` (recursively). ## @@ -1381,7 +1401,7 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} = rawCreateDir(dir) proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", - tags: [WriteIOEffect, ReadIOEffect].} = + tags: [WriteIOEffect, ReadIOEffect], benign.} = ## Copies a directory from `source` to `dest`. ## ## If this fails, `OSError` is raised. On the Windows platform this proc will @@ -1442,7 +1462,7 @@ proc createHardlink*(src, dest: string) = proc parseCmdLine*(c: string): seq[string] {. noSideEffect, rtl, extern: "nos$1".} = ## Splits a command line into several components; - ## This proc is only occassionally useful, better use the `parseopt` module. + ## This proc is only occasionally useful, better use the `parseopt` module. ## ## On Windows, it uses the following parsing rules ## (see http://msdn.microsoft.com/en-us/library/17w5ykft.aspx ): @@ -1554,7 +1574,7 @@ proc copyFileWithPermissions*(source, dest: string, proc copyDirWithPermissions*(source, dest: string, ignorePermissionErrors = true) {.rtl, extern: "nos$1", - tags: [WriteIOEffect, ReadIOEffect].} = + tags: [WriteIOEffect, ReadIOEffect], benign.} = ## Copies a directory from `source` to `dest` preserving file permissions. ## ## If this fails, `OSError` is raised. This is a wrapper proc around `copyDir() diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 6361dfb09..cd3700019 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -146,7 +146,7 @@ proc startProcess*(command: string, ## of `args` to `command` carefully escaping/quoting any special characters, ## since it will be passed *as is* to the system shell. Each system/shell may ## feature different escaping rules, so try to avoid this kind of shell - ## invokation if possible as it leads to non portable software. + ## invocation if possible as it leads to non portable software. ## ## Return value: The newly created process object. Nil is never returned, ## but ``EOS`` is raised in case of an error. @@ -260,7 +260,7 @@ proc execProcesses*(cmds: openArray[string], for i in 0..m-1: if beforeRunEvent != nil: beforeRunEvent(i) - q[i] = startCmd(cmds[i], options=options) + q[i] = startProcess(cmds[i], options=options + {poEvalCommand}) when defined(noBusyWaiting): var r = 0 for i in m..high(cmds): @@ -275,7 +275,7 @@ proc execProcesses*(cmds: openArray[string], if q[r] != nil: close(q[r]) if beforeRunEvent != nil: beforeRunEvent(i) - q[r] = startCmd(cmds[i], options=options) + q[r] = startProcess(cmds[i], options=options + {poEvalCommand}) r = (r + 1) mod n else: var i = m @@ -288,7 +288,7 @@ proc execProcesses*(cmds: openArray[string], if q[r] != nil: close(q[r]) if beforeRunEvent != nil: beforeRunEvent(i) - q[r] = startCmd(cmds[i], options=options) + q[r] = startProcess(cmds[i], options=options + {poEvalCommand}) inc(i) if i > high(cmds): break for j in 0..m-1: @@ -298,7 +298,7 @@ proc execProcesses*(cmds: openArray[string], for i in 0..high(cmds): if beforeRunEvent != nil: beforeRunEvent(i) - var p = startCmd(cmds[i], options=options) + var p = startProcess(cmds[i], options=options + {poEvalCommand}) result = max(waitForExit(p), result) close(p) @@ -644,14 +644,14 @@ elif not defined(useNimRtl): var pid: TPid var sysArgs = allocCStringArray(sysArgsRaw) - finally: deallocCStringArray(sysArgs) + defer: deallocCStringArray(sysArgs) var sysEnv = if env == nil: envToCStringArray() else: envToCStringArray(env) - finally: deallocCStringArray(sysEnv) + defer: deallocCStringArray(sysEnv) var data: TStartProcessData data.sysCommand = sysCommand @@ -748,7 +748,7 @@ elif not defined(useNimRtl): if pipe(data.pErrorPipe) != 0: raiseOSError(osLastError()) - finally: + defer: discard close(data.pErrorPipe[readIdx]) var pid: TPid @@ -956,7 +956,7 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = { exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect], gcsafe.} = ## a convenience proc that runs the `command`, grabs all its output and ## exit code and returns both. - var p = startCmd(command, options) + var p = startProcess(command, options=options + {poEvalCommand}) var outp = outputStream(p) result = (TaintedString"", -1) var line = newStringOfCap(120).TaintedString diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index bb9d2aed2..bb64c8134 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -35,7 +35,7 @@ type cfgSectionStart, ## a ``[section]`` has been parsed cfgKeyValuePair, ## a ``key=value`` pair has been detected cfgOption, ## a ``--key=value`` command line option - cfgError ## an error ocurred during parsing + cfgError ## an error occurred during parsing CfgEvent* = object of RootObj ## describes a parsing event case kind*: CfgEventKind ## the kind of the event diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index b1e2444c3..4c92a7cdf 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -11,9 +11,12 @@ ## It supports one convenience iterator over all command line options and some ## lower-level features. ## -## **Deprecated since version 0.9.3:** Use the `parseopt2 <parseopt2.html>`_ -## module instead as this version has issues with spaces in arguments. -{.deprecated.} +## Supported syntax: +## +## 1. short options - ``-abcd``, where a, b, c, d are names +## 2. long option - ``--foo:bar``, ``--foo=bar`` or ``--foo`` +## 3. argument - everything else + {.push debugger: off.} include "system/inclrtl" diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim index 8ed519fa4..73b498fe0 100644 --- a/lib/pure/parseopt2.nim +++ b/lib/pure/parseopt2.nim @@ -60,7 +60,7 @@ proc initOptParser*(cmdline: string): OptParser {.rtl, deprecated.} = ## Initalizes option parses with cmdline. Splits cmdline in on spaces ## and calls initOptParser(openarray[string]) ## Do not use. - if cmdline == "": # backward compatibilty + if cmdline == "": # backward compatibility return initOptParser(seq[string](nil)) else: return initOptParser(cmdline.split) diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 2c677fdc2..eb649a878 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -181,7 +181,7 @@ proc parseWhile*(s: string, token: var string, validChars: set[char], token = substr(s, start, i-1) proc captureBetween*(s: string, first: char, second = '\0', start = 0): string = - ## Finds the first occurence of ``first``, then returns everything from there + ## Finds the first occurrence of ``first``, then returns everything from there ## up to ``second``(if ``second`` is '\0', then ``first`` is used). var i = skipUntil(s, first, start)+1+start result = "" @@ -240,7 +240,7 @@ proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {. proc parseFloat*(s: string, number: var float, start = 0): int {. rtl, extern: "npuParseFloat", noSideEffect.} = ## parses a float starting at `start` and stores the value into `number`. - ## Result is the number of processed chars or 0 if there occured a parsing + ## Result is the number of processed chars or 0 if there occurred a parsing ## error. var bf: BiggestFloat result = parseBiggestFloat(s, bf, start) diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 39dead3c0..b957c0cf7 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -57,7 +57,7 @@ import type XmlEventKind* = enum ## enumation of all events that may occur when parsing - xmlError, ## an error ocurred during parsing + xmlError, ## an error occurred during parsing xmlEof, ## end of file reached xmlCharData, ## character data xmlWhitespace, ## whitespace has been parsed diff --git a/lib/pure/rationals.nim b/lib/pure/rationals.nim new file mode 100644 index 000000000..04aa8316a --- /dev/null +++ b/lib/pure/rationals.nim @@ -0,0 +1,275 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Dennis Felsing +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + + +## This module implements rational numbers, consisting of a numerator `num` and +## a denominator `den`, both of type int. The denominator can not be 0. + +import math + +type Rational*[T] = object + ## a rational number, consisting of a numerator and denominator + num*, den*: T + +proc initRational*[T](num, den: T): Rational[T] = + ## Create a new rational number. + result.num = num + result.den = den + +proc `//`*[T](num, den: T): Rational[T] = initRational[T](num, den) + ## A friendlier version of `initRational`. Example usage: + ## + ## .. code-block:: nim + ## var x = 1//3 + 1//5 + +proc `$`*[T](x: Rational[T]): string = + ## Turn a rational number into a string. + result = $x.num & "/" & $x.den + +proc toRational*[T](x: SomeInteger): Rational[T] = + ## Convert some integer `x` to a rational number. + result.num = x + result.den = 1 + +proc toFloat*[T](x: Rational[T]): float = + ## Convert a rational number `x` to a float. + x.num / x.den + +proc toInt*[T](x: Rational[T]): int = + ## Convert a rational number `x` to an int. Conversion rounds towards 0 if + ## `x` does not contain an integer value. + x.num div x.den + +proc reduce*[T](x: var Rational[T]) = + ## Reduce rational `x`. + let common = gcd(x.num, x.den) + if x.den > 0: + x.num = x.num div common + x.den = x.den div common + elif x.den < 0: + x.num = -x.num div common + x.den = -x.den div common + else: + raise newException(DivByZeroError, "division by zero") + +proc `+` *[T](x, y: Rational[T]): Rational[T] = + ## Add two rational numbers. + let common = lcm(x.den, y.den) + result.num = common div x.den * x.num + common div y.den * y.num + result.den = common + reduce(result) + +proc `+` *[T](x: Rational[T], y: T): Rational[T] = + ## Add rational `x` to int `y`. + result.num = x.num + y * x.den + result.den = x.den + +proc `+` *[T](x: T, y: Rational[T]): Rational[T] = + ## Add int `x` to rational `y`. + result.num = x * y.den + y.num + result.den = y.den + +proc `+=` *[T](x: var Rational[T], y: Rational[T]) = + ## Add rational `y` to rational `x`. + let common = lcm(x.den, y.den) + x.num = common div x.den * x.num + common div y.den * y.num + x.den = common + reduce(x) + +proc `+=` *[T](x: var Rational[T], y: T) = + ## Add int `y` to rational `x`. + x.num += y * x.den + +proc `-` *[T](x: Rational[T]): Rational[T] = + ## Unary minus for rational numbers. + result.num = -x.num + result.den = x.den + +proc `-` *[T](x, y: Rational[T]): Rational[T] = + ## Subtract two rational numbers. + let common = lcm(x.den, y.den) + result.num = common div x.den * x.num - common div y.den * y.num + result.den = common + reduce(result) + +proc `-` *[T](x: Rational[T], y: T): Rational[T] = + ## Subtract int `y` from rational `x`. + result.num = x.num - y * x.den + result.den = x.den + +proc `-` *[T](x: T, y: Rational[T]): Rational[T] = + ## Subtract rational `y` from int `x`. + result.num = - x * y.den + y.num + result.den = y.den + +proc `-=` *[T](x: var Rational[T], y: Rational[T]) = + ## Subtract rational `y` from rational `x`. + let common = lcm(x.den, y.den) + x.num = common div x.den * x.num - common div y.den * y.num + x.den = common + reduce(x) + +proc `-=` *[T](x: var Rational[T], y: T) = + ## Subtract int `y` from rational `x`. + x.num -= y * x.den + +proc `*` *[T](x, y: Rational[T]): Rational[T] = + ## Multiply two rational numbers. + result.num = x.num * y.num + result.den = x.den * y.den + reduce(result) + +proc `*` *[T](x: Rational[T], y: T): Rational[T] = + ## Multiply rational `x` with int `y`. + result.num = x.num * y + result.den = x.den + reduce(result) + +proc `*` *[T](x: T, y: Rational[T]): Rational[T] = + ## Multiply int `x` with rational `y`. + result.num = x * y.num + result.den = y.den + reduce(result) + +proc `*=` *[T](x: var Rational[T], y: Rational[T]) = + ## Multiply rationals `y` to `x`. + x.num *= y.num + x.den *= y.den + reduce(x) + +proc `*=` *[T](x: var Rational[T], y: T) = + ## Multiply int `y` to rational `x`. + x.num *= y + reduce(x) + +proc reciprocal*[T](x: Rational[T]): Rational[T] = + ## Calculate the reciprocal of `x`. (1/x) + if x.num > 0: + result.num = x.den + result.den = x.num + elif x.num < 0: + result.num = -x.den + result.den = -x.num + else: + raise newException(DivByZeroError, "division by zero") + +proc `/`*[T](x, y: Rational[T]): Rational[T] = + ## Divide rationals `x` by `y`. + result.num = x.num * y.den + result.den = x.den * y.num + reduce(result) + +proc `/`*[T](x: Rational[T], y: T): Rational[T] = + ## Divide rational `x` by int `y`. + result.num = x.num + result.den = x.den * y + reduce(result) + +proc `/`*[T](x: T, y: Rational[T]): Rational[T] = + ## Divide int `x` by Rational `y`. + result.num = x * y.den + result.den = y.num + reduce(result) + +proc `/=`*[T](x: var Rational[T], y: Rational[T]) = + ## Divide rationals `x` by `y` in place. + x.num *= y.den + x.den *= y.num + reduce(x) + +proc `/=`*[T](x: var Rational[T], y: T) = + ## Divide rational `x` by int `y` in place. + x.den *= y + reduce(x) + +proc cmp*(x, y: Rational): int = + ## Compares two rationals. + (x - y).num + +proc `<` *(x, y: Rational): bool = + (x - y).num < 0 + +proc `<=` *(x, y: Rational): bool = + (x - y).num <= 0 + +proc `==` *(x, y: Rational): bool = + (x - y).num == 0 + +proc abs*[T](x: Rational[T]): Rational[T] = + result.num = abs x.num + result.den = abs x.den + +when isMainModule: + var + z = Rational[int](num: 0, den: 1) + o = initRational(num=1, den=1) + a = initRational(1, 2) + b = -1 // -2 + m1 = -1 // 1 + tt = 10 // 2 + + assert( a == a ) + assert( (a-a) == z ) + assert( (a+b) == o ) + assert( (a/b) == o ) + assert( (a*b) == 1 // 4 ) + assert( (3/a) == 6 // 1 ) + assert( (a/3) == 1 // 6 ) + assert( a*b == 1 // 4 ) + assert( tt*z == z ) + assert( 10*a == tt ) + assert( a*10 == tt ) + assert( tt/10 == a ) + assert( a-m1 == 3 // 2 ) + assert( a+m1 == -1 // 2 ) + assert( m1+tt == 16 // 4 ) + assert( m1-tt == 6 // -1 ) + + assert( z < o ) + assert( z <= o ) + assert( z == z ) + assert( cmp(z, o) < 0 ) + assert( cmp(o, z) > 0 ) + + assert( o == o ) + assert( o >= o ) + assert( not(o > o) ) + assert( cmp(o, o) == 0 ) + assert( cmp(z, z) == 0 ) + + assert( a == b ) + assert( a >= b ) + assert( not(b > a) ) + assert( cmp(a, b) == 0 ) + + var x = 1//3 + + x *= 5//1 + assert( x == 5//3 ) + x += 2 // 9 + assert( x == 17//9 ) + x -= 9//18 + assert( x == 25//18 ) + x /= 1//2 + assert( x == 50//18 ) + + var y = 1//3 + + y *= 4 + assert( y == 4//3 ) + y += 5 + assert( y == 19//3 ) + y -= 2 + assert( y == 13//3 ) + y /= 9 + assert( y == 13//27 ) + + assert toRational[int, int](5) == 5//1 + assert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7 + assert toInt(z) == 0 diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index 995dff2aa..4cc64a154 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -43,7 +43,7 @@ proc isConc(r: Rope): bool {.inline.} = return isNil(r.data) # Note that the left and right pointers are not needed for leafs. # Leaves have relatively high memory overhead (~30 bytes on a 32 # bit machine) and we produce many of them. This is why we cache and -# share leafs accross different rope trees. +# share leafs across different rope trees. # To cache them they are inserted in another tree, a splay tree for best # performance. But for the caching tree we use the leaf's left and right # pointers. diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index bd2564937..b6bc9dd3a 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -35,7 +35,7 @@ type when defined(nimdoc): type Selector* = ref object - ## An object which holds file descripters to be checked for read/write + ## An object which holds file descriptors to be checked for read/write ## status. fds: Table[SocketHandle, SelectorKey] @@ -48,12 +48,21 @@ when defined(nimdoc): events: set[Event]): SelectorKey {.discardable.} = ## Updates the events which ``fd`` wants notifications for. + proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} = + ## Unregisters file descriptor ``fd`` from selector ``s``. + + proc close*(s: Selector) = + ## Closes the selector + proc select*(s: Selector, timeout: int): seq[ReadyInfo] = ## The ``events`` field of the returned ``key`` contains the original events ## for which the ``fd`` was bound. This is contrary to the ``events`` field ## of the ``TReadyInfo`` tuple which determines which events are ready ## on the ``fd``. + proc newSelector*(): Selector = + ## Creates a new selector + proc contains*(s: Selector, fd: SocketHandle): bool = ## Determines whether selector contains a file descriptor. @@ -78,8 +87,6 @@ elif defined(linux): proc register*(s: Selector, fd: SocketHandle, events: set[Event], data: RootRef): SelectorKey {.discardable.} = - ## Registers file descriptor ``fd`` to selector ``s`` with a set of TEvent - ## ``events``. var event = createEventStruct(events, fd) if events != {}: if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0: @@ -92,7 +99,6 @@ elif defined(linux): proc update*(s: Selector, fd: SocketHandle, events: set[Event]): SelectorKey {.discardable.} = - ## Updates the events which ``fd`` wants notifications for. if s.fds[fd].events != events: if events == {}: # This fd is idle -- it should not be registered to epoll. @@ -204,7 +210,6 @@ elif not defined(nimdoc): proc update*(s: Selector, fd: SocketHandle, events: set[Event]): SelectorKey {.discardable.} = - ## Updates the events which ``fd`` wants notifications for. if not s.fds.hasKey(fd): raise newException(ValueError, "File descriptor not found.") @@ -299,7 +304,7 @@ when isMainModule and not defined(nimdoc): sock: Socket var sock = socket() - if sock == sockets.InvalidSocket: raiseOSError(osLastError()) + if sock == sockets.invalidSocket: raiseOSError(osLastError()) #sock.setBlocking(false) sock.connect("irc.freenode.net", Port(6667)) diff --git a/lib/pure/smtp.nimrod.cfg b/lib/pure/smtp.nim.cfg index 521e21de4..521e21de4 100644 --- a/lib/pure/smtp.nimrod.cfg +++ b/lib/pure/smtp.nim.cfg diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index 11eeefcb9..3afb545c8 100644 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -657,6 +657,8 @@ proc close*(socket: Socket) = when defined(ssl): if socket.isSSL: discard SSLShutdown(socket.sslHandle) + SSLFree(socket.sslHandle) + socket.sslHandle = nil proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = ## Searches the database from the beginning and finds the first entry for @@ -851,7 +853,7 @@ proc connectAsync*(socket: Socket, name: string, port = Port(0), af: Domain = AF_INET) {.tags: [ReadIOEffect].} = ## A variant of ``connect`` for non-blocking sockets. ## - ## This procedure will immediatelly return, it will not block until a connection + ## This procedure will immediately return, it will not block until a connection ## is made. It is up to the caller to make sure the connection has been established ## by checking (using ``select``) whether the socket is writeable. ## @@ -1467,7 +1469,7 @@ proc recvAsync*(socket: Socket, s: var TaintedString): bool {. of SSL_ERROR_ZERO_RETURN: raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: - raiseSslError("Unexpected error occured.") # This should just not happen. + raiseSslError("Unexpected error occurred.") # This should just not happen. of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ: return false of SSL_ERROR_WANT_X509_LOOKUP: @@ -1610,7 +1612,7 @@ proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} = of SSL_ERROR_ZERO_RETURN: raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: - raiseSslError("Unexpected error occured.") # This should just not happen. + raiseSslError("Unexpected error occurred.") # This should just not happen. of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ: return 0 of SSL_ERROR_WANT_X509_LOOKUP: diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 55351ffd4..67c80e592 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -122,41 +122,41 @@ proc read[T](s: Stream, result: var T) = raise newEIO("cannot read from stream") proc readChar*(s: Stream): char = - ## reads a char from the stream `s`. Raises `EIO` if an error occured. + ## reads a char from the stream `s`. Raises `EIO` if an error occurred. ## Returns '\0' as an EOF marker. if readData(s, addr(result), sizeof(result)) != 1: result = '\0' proc readBool*(s: Stream): bool = - ## reads a bool from the stream `s`. Raises `EIO` if an error occured. + ## reads a bool from the stream `s`. Raises `EIO` if an error occurred. read(s, result) proc readInt8*(s: Stream): int8 = - ## reads an int8 from the stream `s`. Raises `EIO` if an error occured. + ## reads an int8 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) proc readInt16*(s: Stream): int16 = - ## reads an int16 from the stream `s`. Raises `EIO` if an error occured. + ## reads an int16 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) proc readInt32*(s: Stream): int32 = - ## reads an int32 from the stream `s`. Raises `EIO` if an error occured. + ## reads an int32 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) proc readInt64*(s: Stream): int64 = - ## reads an int64 from the stream `s`. Raises `EIO` if an error occured. + ## reads an int64 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) proc readFloat32*(s: Stream): float32 = - ## reads a float32 from the stream `s`. Raises `EIO` if an error occured. + ## reads a float32 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) proc readFloat64*(s: Stream): float64 = - ## reads a float64 from the stream `s`. Raises `EIO` if an error occured. + ## reads a float64 from the stream `s`. Raises `EIO` if an error occurred. read(s, result) proc readStr*(s: Stream, length: int): TaintedString = ## reads a string of length `length` from the stream `s`. Raises `EIO` if - ## an error occured. + ## an error occurred. result = newString(length).TaintedString var L = readData(s, addr(string(result)[0]), length) if L != length: setLen(result.string, L) @@ -183,7 +183,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool = proc readLine*(s: Stream): TaintedString = ## Reads a line from a stream `s`. Note: This is not very efficient. Raises - ## `EIO` if an error occured. + ## `EIO` if an error occurred. result = TaintedString"" while true: var c = readChar(s) diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 5b7149d8e..727d5a386 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -112,7 +112,7 @@ proc `[]`*(t: StringTableRef, key: string): string {.rtl, extern: "nstGet".} = proc mget*(t: StringTableRef, key: string): var string {. rtl, extern: "nstTake".} = ## retrieves the location at ``t[key]``. If `key` is not in `t`, the - ## ``EInvalidKey`` exception is raised. + ## ``KeyError`` exception is raised. var index = rawGet(t, key) if index >= 0: result = t.data[index].val else: raise newException(KeyError, "key does not exist: " & key) @@ -158,7 +158,7 @@ proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = else: result = "" if result.len == 0: if useKey in flags: result = '$' & key - elif not (useEmpty in flags): raiseFormatException(key) + elif useEmpty notin flags: raiseFormatException(key) proc newStringTable*(mode: StringTableMode): StringTableRef {. rtl, extern: "nst$1".} = diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index e17d99dc2..655203cda 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -395,11 +395,13 @@ proc toHex*(x: BiggestInt, len: int): string {.noSideEffect, const HexChars = "0123456789ABCDEF" var - shift: BiggestInt + n = x result = newString(len) for j in countdown(len-1, 0): - result[j] = HexChars[toU32(x shr shift) and 0xF'i32] - shift = shift + 4 + result[j] = HexChars[n and 0xF] + n = n shr 4 + # handle negative overflow + if n == 0 and x < 0: n = -1 proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect, rtl, extern: "nsuIntToStr".} = @@ -497,26 +499,47 @@ proc parseEnum*[T: enum](s: string, default: T): T = return e result = default -proc repeatChar*(count: int, c: char = ' '): string {.noSideEffect, +proc repeat*(c: char, count: int): string {.noSideEffect, rtl, extern: "nsuRepeatChar".} = ## Returns a string of length `count` consisting only of ## the character `c`. You can use this proc to left align strings. Example: ## ## .. code-block:: nim + ## proc tabexpand(indent: int, text: string, tabsize: int = 4) = + ## echo '\t'.repeat(indent div tabsize), ' '.repeat(indent mod tabsize), text + ## + ## tabexpand(4, "At four") + ## tabexpand(5, "At five") + ## tabexpand(6, "At six") + result = newString(count) + for i in 0..count-1: result[i] = c + +proc repeat*(s: string, n: int): string {.noSideEffect, + rtl, extern: "nsuRepeatStr".} = + ## Returns String `s` concatenated `n` times. Example: + ## + ## .. code-block:: nim + ## echo "+++ STOP ".repeat(4), "+++" + result = newStringOfCap(n * s.len) + for i in 1..n: result.add(s) + +template spaces*(n: int): string = repeat(' ',n) + ## Returns a String with `n` space characters. You can use this proc + ## to left align strings. Example: + ## + ## .. code-block:: nim ## let ## width = 15 ## text1 = "Hello user!" ## text2 = "This is a very long string" - ## echo text1 & repeatChar(max(0, width - text1.len)) & "|" - ## echo text2 & repeatChar(max(0, width - text2.len)) & "|" - result = newString(count) - for i in 0..count-1: result[i] = c + ## echo text1 & spaces(max(0, width - text1.len)) & "|" + ## echo text2 & spaces(max(0, width - text2.len)) & "|" -proc repeatStr*(count: int, s: string): string {.noSideEffect, - rtl, extern: "nsuRepeatStr".} = - ## Returns `s` concatenated `count` times. - result = newStringOfCap(count*s.len) - for i in 0..count-1: result.add(s) +proc repeatChar*(count: int, c: char = ' '): string {.deprecated.} = repeat(c, count) + ## deprecated: use repeat() or spaces() + +proc repeatStr*(count: int, s: string): string {.deprecated.} = repeat(s, count) + ## deprecated: use repeat(string, count) or string.repeat(count) proc align*(s: string, count: int, padding = ' '): string {. noSideEffect, rtl, extern: "nsuAlignString".} = @@ -815,8 +838,8 @@ proc rfind*(s: string, sub: char, start: int = -1): int {.noSideEffect, proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffect, rtl, extern: "nsuCountString".} = - ## Count the occurences of a substring `sub` in the string `s`. - ## Overlapping occurences of `sub` only count when `overlapping` + ## Count the occurrences of a substring `sub` in the string `s`. + ## Overlapping occurrences of `sub` only count when `overlapping` ## is set to true. var i = 0 while true: @@ -831,14 +854,14 @@ proc count*(s: string, sub: string, overlapping: bool = false): int {.noSideEffe proc count*(s: string, sub: char): int {.noSideEffect, rtl, extern: "nsuCountChar".} = - ## Count the occurences of the character `sub` in the string `s`. + ## Count the occurrences of the character `sub` in the string `s`. for c in s: if c == sub: inc result proc count*(s: string, subs: set[char]): int {.noSideEffect, rtl, extern: "nsuCountCharSet".} = - ## Count the occurences of the group of character `subs` in the string `s`. + ## Count the occurrences of the group of character `subs` in the string `s`. for c in s: if c in subs: inc result @@ -898,7 +921,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, rtl, extern: "nsuReplaceWord".} = ## Replaces `sub` in `s` by the string `by`. ## - ## Each occurance of `sub` has to be surrounded by word boundaries + ## Each occurrence of `sub` has to be surrounded by word boundaries ## (comparable to ``\\w`` in regular expressions), otherwise it is not ## replaced. const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim index adcfdd288..d701b85b1 100644 --- a/lib/pure/subexes.nim +++ b/lib/pure/subexes.nim @@ -353,11 +353,11 @@ when isMainModule: proc `%`(formatstr: string, a: openarray[string]): string = result = newStringOfCap(formatstr.len + a.len shl 4) - addf(result, formatstr.TSubex, a) + addf(result, formatstr.Subex, a) proc `%`(formatstr: string, a: string): string = result = newStringOfCap(formatstr.len + a.len) - addf(result, formatstr.TSubex, [a]) + addf(result, formatstr.Subex, [a]) doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c" diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 8607066f3..e0e2aa247 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -45,6 +45,21 @@ when defined(windows): var oldAttr = getAttributes() + proc winGetch(): cint {.header: "<conio.h>", importc: "_getch".} +else: + import termios, unsigned + + proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) = + var mode: Termios + discard fd.tcgetattr(addr mode) + mode.iflag = mode.iflag and not Tcflag(BRKINT or ICRNL or INPCK or ISTRIP or IXON) + mode.oflag = mode.oflag and not Tcflag(OPOST) + mode.cflag = (mode.cflag and not Tcflag(CSIZE or PARENB)) or CS8 + mode.lflag = mode.lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG) + mode.cc[VMIN] = 1.cuchar + mode.cc[VTIME] = 0.cuchar + discard fd.tcsetattr(time, addr mode) + proc setCursorPos*(x, y: int) = ## sets the terminal's cursor to the (x,y) position. (0,0) is the ## upper left of the screen. @@ -349,6 +364,19 @@ macro styledEcho*(m: varargs[expr]): stmt = result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n"))) result.add(newCall(bindSym"resetAttributes")) +proc getch*(): char = + ## Read a single character from the terminal, blocking until it is entered. + ## The character is not printed to the terminal. + when defined(windows): + result = winGetch().char + else: + let fd = getFileHandle(stdin) + var oldMode: Termios + discard fd.tcgetattr(addr oldMode) + fd.setRaw() + result = stdin.readChar() + discard fd.tcsetattr(TCSADRAIN, addr oldMode) + when isMainModule: system.addQuitProc(resetAttributes) write(stdout, "never mind") diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 1cabd381b..e32ea786a 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -16,7 +16,7 @@ # of the standard library! import - strutils + strutils, parseutils include "system/inclrtl" @@ -63,44 +63,44 @@ elif defined(windows): elif defined(JS): type Time* {.importc.} = object - getDay: proc (): int {.tags: [], raises: [], gcsafe.} - getFullYear: proc (): int {.tags: [], raises: [], gcsafe.} - getHours: proc (): int {.tags: [], raises: [], gcsafe.} - getMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.} - getMinutes: proc (): int {.tags: [], raises: [], gcsafe.} - getMonth: proc (): int {.tags: [], raises: [], gcsafe.} - getSeconds: proc (): int {.tags: [], raises: [], gcsafe.} - getTime: proc (): int {.tags: [], raises: [], gcsafe.} - getTimezoneOffset: proc (): int {.tags: [], raises: [], gcsafe.} - getDate: proc (): int {.tags: [], raises: [], gcsafe.} - getUTCDate: proc (): int {.tags: [], raises: [], gcsafe.} - getUTCFullYear: proc (): int {.tags: [], raises: [], gcsafe.} - getUTCHours: proc (): int {.tags: [], raises: [], gcsafe.} - getUTCMilliseconds: proc (): int {.tags: [], raises: [], gcsafe.} - getUTCMinutes: proc (): int {.tags: [], raises: [], gcsafe.} - getUTCMonth: proc (): int {.tags: [], raises: [], gcsafe.} - getUTCSeconds: proc (): int {.tags: [], raises: [], gcsafe.} - getUTCDay: proc (): int {.tags: [], raises: [], gcsafe.} - getYear: proc (): int {.tags: [], raises: [], gcsafe.} - parse: proc (s: cstring): Time {.tags: [], raises: [], gcsafe.} - setDate: proc (x: int) {.tags: [], raises: [], gcsafe.} - setFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.} - setHours: proc (x: int) {.tags: [], raises: [], gcsafe.} - setMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.} - setMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.} - setMonth: proc (x: int) {.tags: [], raises: [], gcsafe.} - setSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.} - setTime: proc (x: int) {.tags: [], raises: [], gcsafe.} - setUTCDate: proc (x: int) {.tags: [], raises: [], gcsafe.} - setUTCFullYear: proc (x: int) {.tags: [], raises: [], gcsafe.} - setUTCHours: proc (x: int) {.tags: [], raises: [], gcsafe.} - setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], gcsafe.} - setUTCMinutes: proc (x: int) {.tags: [], raises: [], gcsafe.} - setUTCMonth: proc (x: int) {.tags: [], raises: [], gcsafe.} - setUTCSeconds: proc (x: int) {.tags: [], raises: [], gcsafe.} - setYear: proc (x: int) {.tags: [], raises: [], gcsafe.} - toGMTString: proc (): cstring {.tags: [], raises: [], gcsafe.} - toLocaleString: proc (): cstring {.tags: [], raises: [], gcsafe.} + getDay: proc (): int {.tags: [], raises: [], benign.} + getFullYear: proc (): int {.tags: [], raises: [], benign.} + getHours: proc (): int {.tags: [], raises: [], benign.} + getMilliseconds: proc (): int {.tags: [], raises: [], benign.} + getMinutes: proc (): int {.tags: [], raises: [], benign.} + getMonth: proc (): int {.tags: [], raises: [], benign.} + getSeconds: proc (): int {.tags: [], raises: [], benign.} + getTime: proc (): int {.tags: [], raises: [], benign.} + getTimezoneOffset: proc (): int {.tags: [], raises: [], benign.} + getDate: proc (): int {.tags: [], raises: [], benign.} + getUTCDate: proc (): int {.tags: [], raises: [], benign.} + getUTCFullYear: proc (): int {.tags: [], raises: [], benign.} + getUTCHours: proc (): int {.tags: [], raises: [], benign.} + getUTCMilliseconds: proc (): int {.tags: [], raises: [], benign.} + getUTCMinutes: proc (): int {.tags: [], raises: [], benign.} + getUTCMonth: proc (): int {.tags: [], raises: [], benign.} + getUTCSeconds: proc (): int {.tags: [], raises: [], benign.} + getUTCDay: proc (): int {.tags: [], raises: [], benign.} + getYear: proc (): int {.tags: [], raises: [], benign.} + parse: proc (s: cstring): Time {.tags: [], raises: [], benign.} + setDate: proc (x: int) {.tags: [], raises: [], benign.} + setFullYear: proc (x: int) {.tags: [], raises: [], benign.} + setHours: proc (x: int) {.tags: [], raises: [], benign.} + setMilliseconds: proc (x: int) {.tags: [], raises: [], benign.} + setMinutes: proc (x: int) {.tags: [], raises: [], benign.} + setMonth: proc (x: int) {.tags: [], raises: [], benign.} + setSeconds: proc (x: int) {.tags: [], raises: [], benign.} + setTime: proc (x: int) {.tags: [], raises: [], benign.} + setUTCDate: proc (x: int) {.tags: [], raises: [], benign.} + setUTCFullYear: proc (x: int) {.tags: [], raises: [], benign.} + setUTCHours: proc (x: int) {.tags: [], raises: [], benign.} + setUTCMilliseconds: proc (x: int) {.tags: [], raises: [], benign.} + setUTCMinutes: proc (x: int) {.tags: [], raises: [], benign.} + setUTCMonth: proc (x: int) {.tags: [], raises: [], benign.} + setUTCSeconds: proc (x: int) {.tags: [], raises: [], benign.} + setYear: proc (x: int) {.tags: [], raises: [], benign.} + toGMTString: proc (): cstring {.tags: [], raises: [], benign.} + toLocaleString: proc (): cstring {.tags: [], raises: [], benign.} type TimeInfo* = object of RootObj ## represents a time in different parts @@ -139,42 +139,42 @@ type {.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time, TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].} -proc getTime*(): Time {.tags: [TimeEffect], gcsafe.} +proc getTime*(): Time {.tags: [TimeEffect], benign.} ## gets the current calendar time as a UNIX epoch value (number of seconds ## elapsed since 1970) with integer precission. Use epochTime for higher ## resolution. -proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.} +proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.} ## converts the calendar time `t` to broken-time representation, ## expressed relative to the user's specified time zone. -proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.} +proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], benign.} ## converts the calendar time `t` to broken-down time representation, ## expressed in Coordinated Universal Time (UTC). -proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], gcsafe.} +proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], benign.} ## converts a broken-down time structure to ## calendar time representation. The function ignores the specified ## contents of the structure members `weekday` and `yearday` and recomputes ## them from the other information in the broken-down time structure. -proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], gcsafe.} +proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], benign.} ## Takes a float which contains the number of seconds since the unix epoch and ## returns a time object. -proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], gcsafe.} = +proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], benign.} = ## Takes an int which contains the number of seconds since the unix epoch and ## returns a time object. fromSeconds(float(since1970)) -proc toSeconds*(time: Time): float {.tags: [], raises: [], gcsafe.} +proc toSeconds*(time: Time): float {.tags: [], raises: [], benign.} ## Returns the time in seconds since the unix epoch. -proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], gcsafe.} +proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], benign.} ## converts a `TimeInfo` object to a string representation. -proc `$` *(time: Time): string {.tags: [], raises: [], gcsafe.} +proc `$` *(time: Time): string {.tags: [], raises: [], benign.} ## converts a calendar time to a string representation. proc `-`*(a, b: Time): int64 {. - rtl, extern: "ntDiffTime", tags: [], raises: [].} + rtl, extern: "ntDiffTime", tags: [], raises: [], benign.} ## computes the difference of two calendar times. Result is in seconds. proc `<`*(a, b: Time): bool {. @@ -194,14 +194,14 @@ proc `==`*(a, b: Time): bool {. when not defined(JS): proc getTzname*(): tuple[nonDST, DST: string] {.tags: [TimeEffect], raises: [], - gcsafe.} + benign.} ## returns the local timezone; ``nonDST`` is the name of the local non-DST ## timezone, ``DST`` is the name of the local DST timezone. -proc getTimezone*(): int {.tags: [TimeEffect], raises: [], gcsafe.} +proc getTimezone*(): int {.tags: [TimeEffect], raises: [], benign.} ## returns the offset of the local (non-DST) timezone in seconds west of UTC. -proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], gcsafe.} +proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], benign.} ## get the miliseconds from the start of the program. **Deprecated since ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead. @@ -744,6 +744,285 @@ proc format*(info: TimeInfo, f: string): string = {.pop.} +proc parseToken(info: var TimeInfo; token, value: string; j: var int) = + ## Helper of the parse proc to parse individual tokens. + var sv: int + case token + of "d": + var pd = parseInt(value[j..j+1], sv) + info.monthday = sv + j += pd + of "dd": + info.monthday = value[j..j+1].parseInt() + j += 2 + of "ddd": + case value[j..j+2].toLower(): + of "sun": + info.weekday = dSun + of "mon": + info.weekday = dMon + of "tue": + info.weekday = dTue + of "wed": + info.weekday = dWed + of "thu": + info.weekday = dThu + of "fri": + info.weekday = dFri + of "sat": + info.weekday = dSat + else: + raise newException(ValueError, "invalid day of week ") + j += 3 + of "dddd": + if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0: + info.weekday = dSun + j += 6 + elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("monday") == 0: + info.weekday = dMon + j += 6 + elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("tuesday") == 0: + info.weekday = dTue + j += 7 + elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("wednesday") == 0: + info.weekday = dWed + j += 9 + elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("thursday") == 0: + info.weekday = dThu + j += 8 + elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("friday") == 0: + info.weekday = dFri + j += 6 + elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("saturday") == 0: + info.weekday = dSat + j += 8 + else: + raise newException(ValueError, "invalid day of week ") + of "h", "H": + var pd = parseInt(value[j..j+1], sv) + info.hour = sv + j += pd + of "hh", "HH": + info.hour = value[j..j+1].parseInt() + j += 2 + of "m": + var pd = parseInt(value[j..j+1], sv) + info.minute = sv + j += pd + of "mm": + info.minute = value[j..j+1].parseInt() + j += 2 + of "M": + var pd = parseInt(value[j..j+1], sv) + info.month = Month(sv-1) + info.monthday = sv + j += pd + of "MM": + var month = value[j..j+1].parseInt() + j += 2 + info.month = Month(month-1) + of "MMM": + case value[j..j+2].toLower(): + of "jan": + info.month = mJan + of "feb": + info.month = mFeb + of "mar": + info.month = mMar + of "apr": + info.month = mApr + of "may": + info.month = mMay + of "jun": + info.month = mJun + of "jul": + info.month = mJul + of "aug": + info.month = mAug + of "sep": + info.month = mSep + of "oct": + info.month = mOct + of "nov": + info.month = mNov + of "dec": + info.month = mDec + else: + raise newException(ValueError, "invalid month") + j += 3 + of "MMMM": + if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0: + info.month = mJan + j += 7 + elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("february") == 0: + info.month = mFeb + j += 8 + elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("march") == 0: + info.month = mMar + j += 5 + elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("april") == 0: + info.month = mApr + j += 5 + elif value.len >= j+3 and value[j..j+2].cmpIgnoreCase("may") == 0: + info.month = mMay + j += 3 + elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("june") == 0: + info.month = mJun + j += 4 + elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("july") == 0: + info.month = mJul + j += 4 + elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("august") == 0: + info.month = mAug + j += 6 + elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("september") == 0: + info.month = mSep + j += 9 + elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("october") == 0: + info.month = mOct + j += 7 + elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("november") == 0: + info.month = mNov + j += 8 + elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("december") == 0: + info.month = mDec + j += 8 + else: + raise newException(ValueError, "invalid month") + of "s": + var pd = parseInt(value[j..j+1], sv) + info.second = sv + j += pd + of "ss": + info.second = value[j..j+1].parseInt() + j += 2 + of "t": + if value[j] == 'P' and info.hour > 0 and info.hour < 12: + info.hour += 12 + j += 1 + of "tt": + if value[j..j+1] == "PM" and info.hour > 0 and info.hour < 12: + info.hour += 12 + j += 2 + of "yy": + # Assumes current century + var year = value[j..j+1].parseInt() + var thisCen = getLocalTime(getTime()).year div 100 + info.year = thisCen*100 + year + j += 2 + of "yyyy": + info.year = value[j..j+3].parseInt() + j += 4 + of "z": + if value[j] == '+': + info.timezone = parseInt($value[j+1]) + elif value[j] == '-': + info.timezone = 0-parseInt($value[j+1]) + else: + raise newException(ValueError, "Sign for timezone " & value[j]) + j += 2 + of "zz": + if value[j] == '+': + info.timezone = value[j+1..j+2].parseInt() + elif value[j] == '-': + info.timezone = 0-value[j+1..j+2].parseInt() + else: + raise newException(ValueError, "Sign for timezone " & value[j]) + j += 3 + of "zzz": + if value[j] == '+': + info.timezone = value[j+1..j+2].parseInt() + elif value[j] == '-': + info.timezone = 0-value[j+1..j+2].parseInt() + else: + raise newException(ValueError, "Sign for timezone " & value[j]) + j += 6 + of "ZZZ": + info.tzname = value[j..j+2].toUpper() + j += 3 + else: + # Ignore the token and move forward in the value string by the same length + j += token.len + +proc parse*(value, layout: string): TimeInfo = + ## This function parses a date/time string using the standard format identifiers (below) + ## The function defaults information not provided in the format string from the running program (timezone, month, year, etc) + ## + ## ========== ================================================================================= ================================================ + ## Specifier Description Example + ## ========== ================================================================================= ================================================ + ## d Numeric value of the day of the month, it will be one or two digits long. ``1/04/2012 -> 1``, ``21/04/2012 -> 21`` + ## dd Same as above, but always two digits. ``1/04/2012 -> 01``, ``21/04/2012 -> 21`` + ## ddd Three letter string which indicates the day of the week. ``Saturday -> Sat``, ``Monday -> Mon`` + ## dddd Full string for the day of the week. ``Saturday -> Saturday``, ``Monday -> Monday`` + ## h The hours in one digit if possible. Ranging from 0-12. ``5pm -> 5``, ``2am -> 2`` + ## hh The hours in two digits always. If the hour is one digit 0 is prepended. ``5pm -> 05``, ``11am -> 11`` + ## H The hours in one digit if possible, randing from 0-24. ``5pm -> 17``, ``2am -> 2`` + ## HH The hours in two digits always. 0 is prepended if the hour is one digit. ``5pm -> 17``, ``2am -> 02`` + ## m The minutes in 1 digit if possible. ``5:30 -> 30``, ``2:01 -> 1`` + ## mm Same as above but always 2 digits, 0 is prepended if the minute is one digit. ``5:30 -> 30``, ``2:01 -> 01`` + ## M The month in one digit if possible. ``September -> 9``, ``December -> 12`` + ## MM The month in two digits always. 0 is prepended. ``September -> 09``, ``December -> 12`` + ## MMM Abbreviated three-letter form of the month. ``September -> Sep``, ``December -> Dec`` + ## MMMM Full month string, properly capitalized. ``September -> September`` + ## s Seconds as one digit if possible. ``00:00:06 -> 6`` + ## ss Same as above but always two digits. 0 is prepended. ``00:00:06 -> 06`` + ## t ``A`` when time is in the AM. ``P`` when time is in the PM. + ## tt Same as above, but ``AM`` and ``PM`` instead of ``A`` and ``P`` respectively. + ## yy Displays the year to two digits. ``2012 -> 12`` + ## yyyy Displays the year to four digits. ``2012 -> 2012`` + ## z Displays the timezone offset from UTC. ``GMT+7 -> +7``, ``GMT-5 -> -5`` + ## zz Same as above but with leading 0. ``GMT+7 -> +07``, ``GMT-5 -> -05`` + ## zzz Same as above but with ``:00``. ``GMT+7 -> +07:00``, ``GMT-5 -> -05:00`` + ## ZZZ Displays the name of the timezone. ``GMT -> GMT``, ``EST -> EST`` + ## ========== ================================================================================= ================================================ + ## + ## Other strings can be inserted by putting them in ``''``. For example + ## ``hh'->'mm`` will give ``01->56``. The following characters can be + ## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]`` + ## ``,``. However you don't need to necessarily separate format specifiers, a + ## unambiguous format string like ``yyyyMMddhhmmss`` is valid too. + var i = 0 # pointer for format string + var j = 0 # pointer for value string + var token = "" + # Assumes current day of month, month and year, but time is reset to 00:00:00. Weekday will be reset after parsing. + var info = getLocalTime(getTime()) + info.hour = 0 + info.minute = 0 + info.second = 0 + while true: + case layout[i] + of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',': + if token.len > 0: + parseToken(info, token, value, j) + # Reset token + token = "" + # Break if at end of line + if layout[i] == '\0': break + # Skip separator and everything between single quotes + # These are literals in both the layout and the value string + if layout[i] == '\'': + inc(i) + inc(j) + while layout[i] != '\'' and layout.len-1 > i: + inc(i) + inc(j) + else: + inc(i) + inc(j) + else: + # Check if the letter being added matches previous accumulated buffer. + if token.len < 1 or token[high(token)] == layout[i]: + token.add(layout[i]) + inc(i) + else: + parseToken(info, token, value, j) + token = "" + # Reset weekday as it might not have been provided and the default may be wrong + info.weekday = getLocalTime(timeInfoToTime(info)).weekday + return info + + when isMainModule: # $ date --date='@2147483647' # Tue 19 Jan 03:14:07 GMT 2038 @@ -778,3 +1057,51 @@ when isMainModule: # Interval tests assert((t4 - initInterval(years = 2)).format("yyyy") == "1995") assert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10") + + var s = "Tuesday at 09:04am on Dec 15, 2015" + var f = "dddd at hh:mmtt on MMM d, yyyy" + assert($s.parse(f) == "Tue Dec 15 09:04:00 2015") + # ANSIC = "Mon Jan _2 15:04:05 2006" + s = "Mon Jan 2 15:04:05 2006" + f = "ddd MMM d HH:mm:ss yyyy" + assert($s.parse(f) == "Mon Jan 2 15:04:05 2006") + # UnixDate = "Mon Jan _2 15:04:05 MST 2006" + s = "Mon Jan 2 15:04:05 MST 2006" + f = "ddd MMM d HH:mm:ss ZZZ yyyy" + assert($s.parse(f) == "Mon Jan 2 15:04:05 2006") + # RubyDate = "Mon Jan 02 15:04:05 -0700 2006" + s = "Mon Jan 02 15:04:05 -07:00 2006" + f = "ddd MMM dd HH:mm:ss zzz yyyy" + assert($s.parse(f) == "Mon Jan 2 15:04:05 2006") + # RFC822 = "02 Jan 06 15:04 MST" + s = "02 Jan 06 15:04 MST" + f = "dd MMM yy HH:mm ZZZ" + assert($s.parse(f) == "Mon Jan 2 15:04:00 2006") + # RFC822Z = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone + s = "02 Jan 06 15:04 -07:00" + f = "dd MMM yy HH:mm zzz" + assert($s.parse(f) == "Mon Jan 2 15:04:00 2006") + # RFC850 = "Monday, 02-Jan-06 15:04:05 MST" + s = "Monday, 02-Jan-06 15:04:05 MST" + f = "dddd, dd-MMM-yy HH:mm:ss ZZZ" + assert($s.parse(f) == "Mon Jan 2 15:04:05 2006") + # RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" + s = "Mon, 02 Jan 2006 15:04:05 MST" + f = "ddd, dd MMM yyyy HH:mm:ss ZZZ" + assert($s.parse(f) == "Mon Jan 2 15:04:05 2006") + # RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone + s = "Mon, 02 Jan 2006 15:04:05 -07:00" + f = "ddd, dd MMM yyyy HH:mm:ss zzz" + assert($s.parse(f) == "Mon Jan 2 15:04:05 2006") + # RFC3339 = "2006-01-02T15:04:05Z07:00" + s = "2006-01-02T15:04:05Z-07:00" + f = "yyyy-MM-ddTHH:mm:ssZzzz" + assert($s.parse(f) == "Mon Jan 2 15:04:05 2006") + # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" + s = "2006-01-02T15:04:05.999999999Z-07:00" + f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz" + assert($s.parse(f) == "Mon Jan 2 15:04:05 2006") + # Kitchen = "3:04PM" + s = "3:04PM" + f = "h:mmtt" + echo "Kitchen: " & $s.parse(f) \ No newline at end of file diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index b892ec8b4..42e6a3195 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -1235,11 +1235,12 @@ proc reversed*(s: string): string = ## returns the reverse of `s`, interpreting it as unicode characters. Unicode ## combining characters are correctly interpreted as well: ## - ## .. code-block: + ## .. code-block:: nim + ## ## assert reversed("Reverse this!") == "!siht esreveR" ## assert reversed("先秦兩漢") == "漢兩秦先" ## assert reversed("as⃝df̅") == "f̅ds⃝a" - ## assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" + ## assert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞" var i = 0 lastI = 0 diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 8dc9fe0d4..f4e42ee63 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -39,6 +39,7 @@ when declared(stdout): when not defined(ECMAScript): import terminal + system.addQuitProc(resetAttributes) type TestStatus* = enum OK, FAILED @@ -234,5 +235,3 @@ if envOutLvl.len > 0: if $opt == envOutLvl: outputLevel = opt break - -system.addQuitProc(resetAttributes) diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 1627b6ca3..9a6e273a8 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -20,6 +20,7 @@ type {.deprecated: [TUrl: Url, TUri: Uri].} +{.push warning[deprecated]: off.} proc `$`*(url: Url): string {.deprecated.} = ## **Deprecated since 0.9.6**: Use ``Uri`` instead. return string(url) @@ -44,6 +45,7 @@ proc add*(url: var Url, a: Url) {.deprecated.} = ## ## **Deprecated since 0.9.6**: Use ``Uri`` instead. url = url / a +{.pop.} proc parseAuthority(authority: string, result: var Uri) = var i = 0 @@ -182,10 +184,10 @@ proc combine*(base: Uri, reference: Uri): Uri = ## assert foo.path == "/baz" ## ## let bar = combine(parseUri("http://example.com/foo/bar"), parseUri("baz")) - ## assert foo.path == "/foo/baz" + ## assert bar.path == "/foo/baz" ## ## let bar = combine(parseUri("http://example.com/foo/bar/"), parseUri("baz")) - ## assert foo.path == "/foo/bar/baz" + ## assert bar.path == "/foo/bar/baz" template setAuthority(dest, src: expr): stmt = dest.hostname = src.hostname @@ -239,10 +241,10 @@ proc `/`*(x: Uri, path: string): Uri = ## assert foo.path == "/foo/bar/baz" ## ## let bar = parseUri("http://example.com/foo/bar") / parseUri("baz") - ## assert foo.path == "/foo/bar/baz" + ## assert bar.path == "/foo/bar/baz" ## ## let bar = parseUri("http://example.com/foo/bar/") / parseUri("baz") - ## assert foo.path == "/foo/bar/baz" + ## assert bar.path == "/foo/bar/baz" result = x if result.path[result.path.len-1] == '/': if path[0] == '/': diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index 660932d92..2e55ff182 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -642,7 +642,7 @@ proc isEmpty(s: string): bool = return true proc normalize*(n: PNode) = - ## Merges all seperated TextNodes together, and removes any empty TextNodes + ## Merges all separated TextNodes together, and removes any empty TextNodes var curTextNode: PNode = nil var i: int = 0 diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim index 8591e894c..755bfcdbc 100644 --- a/lib/pure/xmlparser.nim +++ b/lib/pure/xmlparser.nim @@ -103,7 +103,7 @@ proc parse(x: var XmlParser, errors: var seq[string]): XmlNode = proc parseXml*(s: Stream, filename: string, errors: var seq[string]): XmlNode = ## parses the XML from stream `s` and returns a ``PXmlNode``. Every - ## occured parsing error is added to the `errors` sequence. + ## occurred parsing error is added to the `errors` sequence. var x: XmlParser open(x, s, filename, {reportComments}) while true: @@ -129,7 +129,7 @@ proc parseXml*(s: Stream): XmlNode = proc loadXml*(path: string, errors: var seq[string]): XmlNode = ## Loads and parses XML from file specified by ``path``, and returns - ## a ``PXmlNode``. Every occured parsing error is added to the `errors` + ## a ``PXmlNode``. Every occurred parsing error is added to the `errors` ## sequence. var s = newFileStream(path, fmRead) if s == nil: raise newException(IOError, "Unable to read file: " & path) diff --git a/lib/system.nim b/lib/system.nim index 12c5c6303..abf31c821 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -73,7 +73,7 @@ type expr* {.magic: Expr.} ## meta type to denote an expression (for templates) stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates) typedesc* {.magic: TypeDesc.} ## meta type to denote a type description - void* {.magic: "VoidType".} ## meta type to denote the absense of any type + void* {.magic: "VoidType".} ## meta type to denote the absence of any type auto* = expr any* = distinct auto @@ -124,7 +124,7 @@ proc declared*(x: expr): bool {.magic: "Defined", noSideEffect.} ## feature or not: ## ## .. code-block:: Nim - ## when not defined(strutils.toUpper): + ## when not declared(strutils.toUpper): ## # provide our own toUpper proc here, because strutils is ## # missing it. @@ -343,10 +343,10 @@ type ## ## Each exception has to inherit from `Exception`. See the full `exception ## hierarchy`_. - parent: ref Exception ## parent exception (can be used as a stack) - name: cstring ## The exception's name is its Nim identifier. - ## This field is filled automatically in the - ## ``raise`` statement. + parent*: ref Exception ## parent exception (can be used as a stack) + name: cstring ## The exception's name is its Nim identifier. + ## This field is filled automatically in the + ## ``raise`` statement. msg* {.exportc: "message".}: string ## the exception's message. Not ## providing an exception message ## is bad style. @@ -357,7 +357,7 @@ type ## ## See the full `exception hierarchy`_. IOError* = object of SystemError ## \ - ## Raised if an IO error occured. + ## Raised if an IO error occurred. ## ## See the full `exception hierarchy`_. OSError* = object of SystemError ## \ @@ -370,11 +370,11 @@ type ## ## See the full `exception hierarchy`_. ResourceExhaustedError* = object of SystemError ## \ - ## Raised if a resource request could not be fullfilled. + ## Raised if a resource request could not be fulfilled. ## ## See the full `exception hierarchy`_. ArithmeticError* = object of Exception ## \ - ## Raised if any kind of arithmetic error occured. + ## Raised if any kind of arithmetic error occurred. ## ## See the full `exception hierarchy`_. DivByZeroError* = object of ArithmeticError ## \ @@ -578,7 +578,7 @@ proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.} proc len*[I, T](x: array[I, T]): int {.magic: "LengthArray", noSideEffect.} proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.} ## returns the length of an array, an openarray, a sequence or a string. - ## This is rougly the same as ``high(T)-low(T)+1``, but its resulting type is + ## This is roughly the same as ``high(T)-low(T)+1``, but its resulting type is ## always an int. # set routines: @@ -865,7 +865,7 @@ proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} ## passes its arguments in reverse order. proc contains*[T](s: Slice[T], value: T): bool {.noSideEffect, inline.} = - ## Checks if `value` is withing the range of `s`; returns true iff + ## Checks if `value` is within the range of `s`; returns true iff ## `value >= s.a and value <= s.b` ## ## .. code-block:: Nim @@ -1455,7 +1455,8 @@ template `>%` *(x, y: expr): expr {.immediate.} = y <% x proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.} ## The stringify operator for an integer argument. Returns `x` - ## converted to a decimal string. + ## converted to a decimal string. ``$`` is Nim's general way of + ## spelling `toString`:idx:. proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} ## The stringify operator for an integer argument. Returns `x` @@ -2098,17 +2099,16 @@ when not defined(nimrodVM) and hostOS != "standalone": ## returns an informative string about the GC's activity. This may be useful ## for tweaking. - # XXX mark these as 'locks: 0' once 0.10.0 has been released - proc GC_ref*[T](x: ref T) {.magic: "GCref", gcsafe.} - proc GC_ref*[T](x: seq[T]) {.magic: "GCref", gcsafe.} - proc GC_ref*(x: string) {.magic: "GCref", gcsafe.} + proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.} + proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.} + proc GC_ref*(x: string) {.magic: "GCref", benign.} ## marks the object `x` as referenced, so that it will not be freed until ## it is unmarked via `GC_unref`. If called n-times for the same object `x`, ## n calls to `GC_unref` are needed to unmark `x`. - proc GC_unref*[T](x: ref T) {.magic: "GCunref", gcsafe.} - proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", gcsafe.} - proc GC_unref*(x: string) {.magic: "GCunref", gcsafe.} + proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.} + proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.} + proc GC_unref*(x: string) {.magic: "GCunref", benign.} ## see the documentation of `GC_ref`. template accumulateResult*(iter: expr) = @@ -2194,7 +2194,8 @@ elif hostOS != "standalone": inc(i) {.pop.} -proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], benign.} +proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], + benign, sideEffect.} ## Writes and flushes the parameters to the standard output. ## ## Special built-in that takes a variable number of arguments. Each argument @@ -2247,14 +2248,9 @@ when not declared(sysFatal): e.msg = message & arg raise e -when defined(nimlocks): - proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe, locks: 0.} - ## get type information for `x`. Ordinary code should not use this, but - ## the `typeinfo` module instead. -else: - proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", gcsafe.} - ## get type information for `x`. Ordinary code should not use this, but - ## the `typeinfo` module instead. +proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.} + ## get type information for `x`. Ordinary code should not use this, but + ## the `typeinfo` module instead. {.push stackTrace: off.} proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} = @@ -2454,19 +2450,15 @@ when not defined(JS): #and not defined(NimrodVM): ## Returns ``false`` if the end of the file has been reached, ``true`` ## otherwise. If ``false`` is returned `line` contains no new data. - when not defined(booting): - proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, - tags: [WriteIOEffect], gcsafe, locks: 0.} - ## writes the values `x` to `f` and then writes "\n". - ## May throw an IO exception. - else: - proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, - tags: [WriteIOEffect].} + proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, + tags: [WriteIOEffect], benign.} + ## writes the values `x` to `f` and then writes "\n". + ## May throw an IO exception. proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.} ## retrieves the file size (in bytes) of `f`. - proc readBytes*(f: File, a: var openArray[int8], start, len: int): int {. + proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: int): int {. tags: [ReadIOEffect], benign.} ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns ## the actual number of bytes that have been read which may be less than @@ -2484,7 +2476,7 @@ when not defined(JS): #and not defined(NimrodVM): ## the actual number of bytes that have been read which may be less than ## `len` (if not as many bytes are remaining), but not greater. - proc writeBytes*(f: File, a: openArray[int8], start, len: int): int {. + proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: int): int {. tags: [WriteIOEffect], benign.} ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns ## the number of actual written bytes, which may be less than `len` in case @@ -2575,7 +2567,7 @@ when not defined(JS): #and not defined(NimrodVM): initAllocator() when hasThreadSupport: include "system/syslocks" - include "system/threads" + when hostOS != "standalone": include "system/threads" elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone": when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom() initGC() @@ -3134,9 +3126,17 @@ proc shallow*(s: var string) {.noSideEffect, inline.} = s.reserved = s.reserved or seqShallowFlag type - TNimrodNode {.final.} = object - PNimrodNode* {.magic: "PNimrodNode".} = ref TNimrodNode - ## represents a Nim AST node. Macros operate on this type. + NimNodeObj = object + +when defined(nimnode): + type + NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj + ## represents a Nim AST node. Macros operate on this type. + {.deprecated: [PNimrodNode: NimNode].} +else: + type + PNimrodNode* {.magic: "PNimrodNode".} = ref NimNodeObj + ## represents a Nim AST node. Macros operate on this type. when false: template eval*(blk: stmt): stmt = @@ -3160,7 +3160,7 @@ when hostOS != "standalone": x[j+i] = item[j] inc(j) -proc compiles*(x): bool {.magic: "Compiles", noSideEffect.} = +proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} = ## Special compile-time procedure that checks whether `x` can be compiled ## without any semantic error. ## This can be used to check whether a type supports some operation: diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim index c4df287cf..f68e2dcd9 100644 --- a/lib/system/arithm.nim +++ b/lib/system/arithm.nim @@ -15,7 +15,7 @@ proc raiseOverflow {.compilerproc, noinline, noreturn.} = sysFatal(OverflowError, "over- or underflow") proc raiseDivByZero {.compilerproc, noinline, noreturn.} = - sysFatal(DivByZeroError, "divison by zero") + sysFatal(DivByZeroError, "division by zero") proc addInt64(a, b: int64): int64 {.compilerProc, inline.} = result = a +% b diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 429a92d34..78995954f 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -27,7 +27,7 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode, var m = selectBranch(src, n) # reset if different branches are in use; note different branches also # imply that's not self-assignment (``x = x``)! - if m != dd and dd != nil: + if m != dd and dd != nil: genericResetAux(dest, dd) copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset), n.typ.size) @@ -205,9 +205,13 @@ proc genericReset(dest: pointer, mt: PNimType) = case mt.kind of tyString, tyRef, tySequence: unsureAsgnRef(cast[PPointer](dest), nil) - of tyObject, tyTuple: - # we don't need to reset m_type field for tyObject + of tyTuple: + genericResetAux(dest, mt.node) + of tyObject: genericResetAux(dest, mt.node) + # also reset the type field for tyObject, for correct branch switching! + var pint = cast[ptr PNimType](dest) + pint[] = nil of tyArray, tyArrayConstr: for i in 0..(mt.size div mt.base.size)-1: genericReset(cast[pointer](d +% i*% mt.base.size), mt.base) diff --git a/lib/system/cgprocs.nim b/lib/system/cgprocs.nim index 089846578..f3acc81f2 100644 --- a/lib/system/cgprocs.nim +++ b/lib/system/cgprocs.nim @@ -13,7 +13,7 @@ proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.} type TLibHandle = pointer # private type - TProcAddr = pointer # libary loading and loading of procs: + TProcAddr = pointer # library loading and loading of procs: proc nimLoadLibrary(path: string): TLibHandle {.compilerproc.} proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.} diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index e0d99cf88..44f7b67c3 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -8,7 +8,7 @@ # # This file implements the ability to call native procs from libraries. -# It is not possible to do this in a platform independant way, unfortunately. +# It is not possible to do this in a platform independent way, unfortunately. # However, the interface has been designed to take platform differences into # account and been ported to all major platforms. @@ -80,15 +80,22 @@ elif defined(windows) or defined(dos): # Native Windows Implementation # ======================================================================= # - type - THINSTANCE {.importc: "HINSTANCE".} = pointer + when defined(cpp): + type + THINSTANCE {.importc: "HINSTANCE".} = object + x: pointer + proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {. + importcpp: "(void*)GetProcAddress(@)", header: "<windows.h>", stdcall.} + else: + type + THINSTANCE {.importc: "HINSTANCE".} = pointer + proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {. + importc: "GetProcAddress", header: "<windows.h>", stdcall.} proc freeLibrary(lib: THINSTANCE) {. importc: "FreeLibrary", header: "<windows.h>", stdcall.} proc winLoadLibrary(path: cstring): THINSTANCE {. importc: "LoadLibraryA", header: "<windows.h>", stdcall.} - proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {. - importc: "GetProcAddress", header: "<windows.h>", stdcall.} proc nimUnloadLibrary(lib: TLibHandle) = freeLibrary(cast[THINSTANCE](lib)) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 417a8634f..1b3471978 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -175,6 +175,8 @@ proc auxWriteStackTrace(f: PFrame, s: var string) = add(s, tempFrames[j].procname) add(s, "\n") +proc stackTraceAvailable*(): bool + when hasSomeStackTrace: proc rawWriteStackTrace(s: var string) = when NimStackTrace: @@ -188,6 +190,18 @@ when hasSomeStackTrace: auxWriteStackTraceWithBacktrace(s) else: add(s, "No stack traceback available\n") + proc stackTraceAvailable(): bool = + when NimStackTrace: + if framePtr == nil: + result = false + else: + result = true + elif defined(nativeStackTrace) and nativeStackTraceSupported: + result = true + else: + result = false +else: + proc stackTraceAvailable*(): bool = result = false proc quitOrDebug() {.inline.} = when not defined(endb): diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 844f28690..1f4279c8f 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -528,20 +528,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)), newsize-oldsize) sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") - sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4") - #if res.refcount <% rcIncrement: - # add(gch.zct, res) - #else: # XXX: what to do here? - # decRef(ol) - if (ol.refcount and ZctFlag) != 0: - var j = gch.zct.len-1 - var d = gch.zct.d - while j >= 0: - if d[j] == ol: - d[j] = res - break - dec(j) - if canbeCycleRoot(ol): excl(gch.cycleRoots, ol) + # This can be wrong for intermediate temps that are nevertheless on the + # heap because of lambda lifting: + #gcAssert(res.refcount shr rcShift <=% 1, "growObj: 4") when logGC: writeCell("growObj old cell", ol) writeCell("growObj new cell", res) @@ -549,7 +538,26 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = gcTrace(res, csAllocated) when reallyDealloc: sysAssert(allocInv(gch.region), "growObj before dealloc") - rawDealloc(gch.region, ol) + if ol.refcount shr rcShift <=% 1: + # free immediately to save space: + if (ol.refcount and ZctFlag) != 0: + var j = gch.zct.len-1 + var d = gch.zct.d + while j >= 0: + if d[j] == ol: + d[j] = res + break + dec(j) + if canbeCycleRoot(ol): excl(gch.cycleRoots, ol) + rawDealloc(gch.region, ol) + else: + # we split the old refcount in 2 parts. XXX This is still not entirely + # correct if the pointer that receives growObj's result is on the stack. + # A better fix would be to emit the location specific write barrier for + # 'growObj', but this is lost of more work and who knows what new problems + # this would create. + res.refcount = rcIncrement + decRef(ol) else: sysAssert(ol.typ != nil, "growObj: 5") zeroMem(ol, sizeof(TCell)) @@ -876,7 +884,7 @@ elif stackIncreases: var jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int # a little hack to get the size of a TJmpBuf in the generated C code - # in a platform independant way + # in a platform independent way template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} = var registers: C_JmpBuf diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index b0173b78f..ae2d2c85d 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -128,7 +128,7 @@ type # cycle roots table that uses a cheap linear scan # to find only possitively dead objects. # One strategy is to perform it only for new objects - # allocated between the invocations of CollectZCT. + # allocated between the invocations of collectZCT. # This index indicates the start of the range of # such new objects within the table. when withRealTime: @@ -140,7 +140,7 @@ var gch* {.rtlThreadVar.}: TGcHeap when not defined(useNimRtl): - InstantiateForRegion(gch.region) + instantiateForRegion(gch.region) template acquire(gch: TGcHeap) = when hasThreadSupport and hasSharedHeap: @@ -233,11 +233,11 @@ template addCycleRoot(cycleRoots: var TCellSeq, c: PCell) = proc cellToUsr(cell: PCell): pointer {.inline.} = # convert object (=pointer to refcount) to pointer to userdata - result = cast[pointer](cast[TAddress](cell)+%TAddress(sizeof(TCell))) + result = cast[pointer](cast[ByteAddress](cell)+%ByteAddress(sizeof(TCell))) proc usrToCell*(usr: pointer): PCell {.inline.} = # convert pointer to userdata to object (=pointer to refcount) - result = cast[PCell](cast[TAddress](usr)-%TAddress(sizeof(TCell))) + result = cast[PCell](cast[ByteAddress](usr)-%ByteAddress(sizeof(TCell))) proc canbeCycleRoot(c: PCell): bool {.inline.} = result = ntfAcyclic notin c.typ.flags @@ -255,10 +255,10 @@ when BitsPerPage mod (sizeof(int)*8) != 0: # forward declarations: proc collectCT(gch: var TGcHeap) -proc IsOnStack*(p: pointer): bool {.noinline.} +proc isOnStack*(p: pointer): bool {.noinline.} proc forAllChildren(cell: PCell, op: TWalkOp) proc doOperation(p: pointer, op: TWalkOp) -proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) +proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) # we need the prototype here for debugging purposes proc prepareDealloc(cell: PCell) = @@ -432,7 +432,7 @@ proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} = sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 2") sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5") -template doAsgnRef(dest: ppointer, src: pointer, +template doAsgnRef(dest: PPointer, src: pointer, heapType = LocalHeap, cycleFlag = MaybeCyclic): stmt = sysAssert(not isOnStack(dest), "asgnRef") # BUGFIX: first incRef then decRef! @@ -440,20 +440,20 @@ template doAsgnRef(dest: ppointer, src: pointer, if dest[] != nil: doDecRef(usrToCell(dest[]), heapType, cycleFlag) dest[] = src -proc asgnRef(dest: ppointer, src: pointer) {.compilerProc, inline.} = +proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} = # the code generator calls this proc! doAsgnRef(dest, src, LocalHeap, MaybeCyclic) -proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} = +proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} = # the code generator calls this proc if it is known at compile time that no # cycle is possible. doAsgnRef(dest, src, LocalHeap, Acyclic) -proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} = +proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} = # unsureAsgnRef updates the reference counters only if dest is not on the # stack. It is used by the code generator if it cannot decide wether a # reference is in the stack or not (this can happen for var parameters). - if not IsOnStack(dest): + if not isOnStack(dest): if src != nil: doIncRef(usrToCell(src)) # XXX we must detect a shared heap here # better idea may be to just eliminate the need for unsureAsgnRef @@ -470,16 +470,16 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} = when hasThreadSupport and hasSharedHeap: # shared heap version of the above procs - proc asgnRefSh(dest: ppointer, src: pointer) {.compilerProc, inline.} = + proc asgnRefSh(dest: PPointer, src: pointer) {.compilerProc, inline.} = doAsgnRef(dest, src, SharedHeap, MaybeCyclic) - proc asgnRefNoCycleSh(dest: ppointer, src: pointer) {.compilerProc, inline.} = + proc asgnRefNoCycleSh(dest: PPointer, src: pointer) {.compilerProc, inline.} = doAsgnRef(dest, src, SharedHeap, Acyclic) proc initGC() = when not defined(useNimRtl): when traceGC: - for i in low(TCellState)..high(TCellState): Init(states[i]) + for i in low(TCellState)..high(TCellState): init(states[i]) gch.cycleThreshold = InitialCycleThreshold gch.stat.stackScans = 0 gch.stat.cycleCollections = 0 @@ -491,11 +491,11 @@ proc initGC() = init(gch.zct) init(gch.tempStack) init(gch.freeStack) - Init(gch.cycleRoots) - Init(gch.decStack) + init(gch.cycleRoots) + init(gch.decStack) proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = - var d = cast[TAddress](dest) + var d = cast[ByteAddress](dest) case n.kind of nkSlot: forAllChildrenAux(cast[pointer](d +% n.offset), n.typ, op) of nkList: @@ -503,7 +503,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = # inlined for speed if n.sons[i].kind == nkSlot: if n.sons[i].typ.kind in {tyRef, tyString, tySequence}: - doOperation(cast[ppointer](d +% n.sons[i].offset)[], op) + doOperation(cast[PPointer](d +% n.sons[i].offset)[], op) else: forAllChildrenAux(cast[pointer](d +% n.sons[i].offset), n.sons[i].typ, op) @@ -514,19 +514,19 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) = if m != nil: forAllSlotsAux(dest, m, op) of nkNone: sysAssert(false, "forAllSlotsAux") -proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) = - var d = cast[TAddress](dest) +proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) = + var d = cast[ByteAddress](dest) if dest == nil: return # nothing to do if ntfNoRefs notin mt.flags: - case mt.Kind + case mt.kind of tyRef, tyString, tySequence: # leaf: - doOperation(cast[ppointer](d)[], op) + doOperation(cast[PPointer](d)[], op) of tyObject, tyTuple: forAllSlotsAux(dest, mt.node, op) of tyArray, tyArrayConstr, tyOpenArray: for i in 0..(mt.size div mt.base.size)-1: forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op) - else: nil + else: discard proc forAllChildren(cell: PCell, op: TWalkOp) = sysAssert(cell != nil, "forAllChildren: 1") @@ -536,18 +536,18 @@ proc forAllChildren(cell: PCell, op: TWalkOp) = if marker != nil: marker(cellToUsr(cell), op.int) else: - case cell.typ.Kind + case cell.typ.kind of tyRef: # common case forAllChildrenAux(cellToUsr(cell), cell.typ.base, op) of tySequence: - var d = cast[TAddress](cellToUsr(cell)) + var d = cast[ByteAddress](cellToUsr(cell)) var s = cast[PGenericSeq](d) if s != nil: let baseAddr = d +% GenericSeqSize for i in 0..s.len-1: forAllChildrenAux(cast[pointer](baseAddr +% i *% cell.typ.base.size), cell.typ.base, op) - else: nil + else: discard proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} = # we check the last 8 entries (cache line) for a slot that could be reused. @@ -605,7 +605,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap, rc1: bool): pointer = var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell))) sysAssert(allocInv(gch.region), "rawNewObj after rawAlloc") - sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2") + sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") res.typ = typ @@ -708,10 +708,10 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = # call user-defined move code # call user-defined default constructor copyMem(res, ol, oldsize + sizeof(TCell)) - zeroMem(cast[pointer](cast[TAddress](res)+% oldsize +% sizeof(TCell)), + zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)), newsize-oldsize) - sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "growObj: 3") + sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") sysAssert(res.refcount shr rcShift <=% 1, "growObj: 4") when false: @@ -786,10 +786,10 @@ type FromChildren, FromRoot -proc CollectZCT(gch: var TGcHeap): bool +proc collectZCT(gch: var TGcHeap): bool template pseudoRecursion(typ: TRecursionType, body: stmt): stmt = - # + discard proc trimCycleRoots(gch: var TGcHeap, startIdx = gch.cycleRootsTrimIdx) = var i = startIdx @@ -967,17 +967,17 @@ proc collectCycles(gch: var TGcHeap) = maybedeads, collected - Deinit(gch.cycleRoots) - Init(gch.cycleRoots) + deinit(gch.cycleRoots) + init(gch.cycleRoots) - Deinit(gch.freeStack) - Init(gch.freeStack) + deinit(gch.freeStack) + init(gch.freeStack) when MarkingSkipsAcyclicObjects: # Collect the acyclic objects that became unreachable due to collected # cyclic objects. - discard CollectZCT(gch) - # CollectZCT may add new cycle candidates and we may decide to loop here + discard collectZCT(gch) + # collectZCT may add new cycle candidates and we may decide to loop here # if gch.cycleRoots.len > 0: repeat var gcDebugging* = false @@ -988,7 +988,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: sysAssert(allocInv(gch.region), "gcMark begin") var cell = usrToCell(p) - var c = cast[TAddress](cell) + var c = cast[ByteAddress](cell) if c >% PageSize: # fast check: does it look like a cell? var objStart = cast[PCell](interiorAllocatedPtr(gch.region, cell)) @@ -997,6 +997,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} = if objStart.color != rcReallyDead: if gcDebugging: # writeCell("marking ", objStart) + discard else: inc objStart.refcount, rcIncrement gch.decStack.add objStart @@ -1009,6 +1010,7 @@ proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} = # coincidence due to the conservative stack marking. when debugGC: # writeCell("marking dead object", objStart) + discard when false: if isAllocatedPtr(gch.region, cell): sysAssert false, "allocated pointer but not interior?" @@ -1024,12 +1026,12 @@ proc markThreadStacks(gch: var TGcHeap) = while it != nil: # mark registers: for i in 0 .. high(it.registers): gcMark(gch, it.registers[i]) - var sp = cast[TAddress](it.stackBottom) - var max = cast[TAddress](it.stackTop) + var sp = cast[ByteAddress](it.stackBottom) + var max = cast[ByteAddress](it.stackTop) # XXX stack direction? # XXX unroll this loop: while sp <=% max: - gcMark(gch, cast[ppointer](sp)[]) + gcMark(gch, cast[PPointer](sp)[]) sp = sp +% sizeof(pointer) it = it.next @@ -1051,8 +1053,8 @@ when not defined(useNimRtl): # the first init must be the one that defines the stack bottom: if gch.stackBottom == nil: gch.stackBottom = theStackBottom else: - var a = cast[TAddress](theStackBottom) # and not PageMask - PageSize*2 - var b = cast[TAddress](gch.stackBottom) + var a = cast[ByteAddress](theStackBottom) # and not PageMask - PageSize*2 + var b = cast[ByteAddress](gch.stackBottom) #c_fprintf(c_stdout, "old: %p new: %p;\n",gch.stackBottom,theStackBottom) when stackIncreases: gch.stackBottom = cast[pointer](min(a, b)) @@ -1067,15 +1069,15 @@ proc stackSize(): int {.noinline.} = var jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int # a little hack to get the size of a TJmpBuf in the generated C code - # in a platform independant way + # in a platform independent way when defined(sparc): # For SPARC architecture. proc isOnStack(p: pointer): bool = var stackTop {.volatile.}: pointer stackTop = addr(stackTop) - var b = cast[TAddress](gch.stackBottom) - var a = cast[TAddress](stackTop) - var x = cast[TAddress](p) + var b = cast[ByteAddress](gch.stackBottom) + var a = cast[ByteAddress](stackTop) + var x = cast[ByteAddress](p) result = a <=% x and x <=% b proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = @@ -1092,7 +1094,7 @@ when defined(sparc): # For SPARC architecture. # Addresses decrease as the stack grows. while sp <= max: gcMark(gch, sp[]) - sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer)) + sp = cast[PPointer](cast[ByteAddress](sp) +% sizeof(pointer)) elif defined(ELATE): {.error: "stack marking code is to be written for this architecture".} @@ -1104,20 +1106,20 @@ elif stackIncreases: proc isOnStack(p: pointer): bool = var stackTop {.volatile.}: pointer stackTop = addr(stackTop) - var a = cast[TAddress](gch.stackBottom) - var b = cast[TAddress](stackTop) - var x = cast[TAddress](p) + var a = cast[ByteAddress](gch.stackBottom) + var b = cast[ByteAddress](stackTop) + var x = cast[ByteAddress](p) result = a <=% x and x <=% b proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = var registers: C_JmpBuf if c_setjmp(registers) == 0'i32: # To fill the C stack with registers. - var max = cast[TAddress](gch.stackBottom) - var sp = cast[TAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer) + var max = cast[ByteAddress](gch.stackBottom) + var sp = cast[ByteAddress](addr(registers)) +% jmpbufSize -% sizeof(pointer) # sp will traverse the JMP_BUF as well (jmp_buf size is added, # otherwise sp would be below the registers structure). while sp >=% max: - gcMark(gch, cast[ppointer](sp)[]) + gcMark(gch, cast[PPointer](sp)[]) sp = sp -% sizeof(pointer) else: @@ -1127,9 +1129,9 @@ else: proc isOnStack(p: pointer): bool = var stackTop {.volatile.}: pointer stackTop = addr(stackTop) - var b = cast[TAddress](gch.stackBottom) - var a = cast[TAddress](stackTop) - var x = cast[TAddress](p) + var b = cast[ByteAddress](gch.stackBottom) + var a = cast[ByteAddress](stackTop) + var x = cast[ByteAddress](p) result = a <=% x and x <=% b proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = @@ -1141,18 +1143,18 @@ else: if c_setjmp(registers) == 0'i32: # To fill the C stack with registers. when MinimumStackMarking: # mark the registers - var jmpbufPtr = cast[TAddress](addr(registers)) + var jmpbufPtr = cast[ByteAddress](addr(registers)) var jmpbufEnd = jmpbufPtr +% jmpbufSize while jmpbufPtr <=% jmpbufEnd: - gcMark(gch, cast[ppointer](jmpbufPtr)[]) + gcMark(gch, cast[PPointer](jmpbufPtr)[]) jmpbufPtr = jmpbufPtr +% sizeof(pointer) - var sp = cast[TAddress](gch.stackTop) + var sp = cast[ByteAddress](gch.stackTop) else: - var sp = cast[TAddress](addr(registers)) + var sp = cast[ByteAddress](addr(registers)) # mark the user stack - var max = cast[TAddress](gch.stackBottom) + var max = cast[ByteAddress](gch.stackBottom) # loop unrolled: while sp <% max - 8*sizeof(pointer): gcMark(gch, cast[PStackSlice](sp)[0]) @@ -1166,7 +1168,7 @@ else: sp = sp +% sizeof(pointer)*8 # last few entries: while sp <=% max: - gcMark(gch, cast[ppointer](sp)[]) + gcMark(gch, cast[PPointer](sp)[]) sp = sp +% sizeof(pointer) # ---------------------------------------------------------------------------- @@ -1202,7 +1204,7 @@ proc releaseCell(gch: var TGcHeap, cell: PCell) = # recursion). # We can ignore it now as the ZCT cleaner will reach it soon. -proc CollectZCT(gch: var TGcHeap): bool = +proc collectZCT(gch: var TGcHeap): bool = const workPackage = 100 var L = addr(gch.zct.len) @@ -1213,8 +1215,8 @@ proc CollectZCT(gch: var TGcHeap): bool = while L[] > 0: var c = gch.zct.d[0] - sysAssert c.isBitUp(rcZct), "CollectZCT: rcZct missing!" - sysAssert(isAllocatedPtr(gch.region, c), "CollectZCT: isAllocatedPtr") + sysAssert c.isBitUp(rcZct), "collectZCT: rcZct missing!" + sysAssert(isAllocatedPtr(gch.region, c), "collectZCT: isAllocatedPtr") # remove from ZCT: c.clearBit(rcZct) @@ -1263,7 +1265,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) = # XXX no need for an atomic dec here: if c.refcount--(LocalHeap): # the object survived only because of a stack reference - # it still doesn't have heap refernces + # it still doesn't have heap references addZCT(gch.zct, c) if canbeCycleRoot(c): @@ -1295,7 +1297,7 @@ proc collectCTBody(gch: var TGcHeap) = sysAssert gch.zct.len == 0, "zct is not null after collect cycles" inc(gch.stat.cycleCollections) gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() * - cycleIncrease) + CycleIncrease) gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold) unmarkStackAndRegisters(gch) sysAssert(allocInv(gch.region), "collectCT: end") @@ -1346,10 +1348,10 @@ when not defined(useNimRtl): proc GC_setStrategy(strategy: GC_Strategy) = case strategy - of gcThroughput: nil - of gcResponsiveness: nil - of gcOptimizeSpace: nil - of gcOptimizeTime: nil + of gcThroughput: discard + of gcResponsiveness: discard + of gcOptimizeSpace: discard + of gcOptimizeTime: discard proc GC_enableMarkAndSweep() = gch.cycleThreshold = InitialCycleThreshold diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 9c3ee8ce2..6fbe94239 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -297,10 +297,12 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = zeroMem(cast[pointer](cast[ByteAddress](res)+% oldsize +% sizeof(TCell)), newsize-oldsize) sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "growObj: 3") - when withBitvectors: excl(gch.allocated, ol) - when reallyDealloc: rawDealloc(gch.region, ol) - else: - zeroMem(ol, sizeof(TCell)) + when false: + # this is wrong since seqs can be shared via 'shallow': + when withBitvectors: excl(gch.allocated, ol) + when reallyDealloc: rawDealloc(gch.region, ol) + else: + zeroMem(ol, sizeof(TCell)) when withBitvectors: incl(gch.allocated, res) when useCellIds: inc gch.idGenerator @@ -474,7 +476,7 @@ elif stackIncreases: var jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int # a little hack to get the size of a TJmpBuf in the generated C code - # in a platform independant way + # in a platform independent way proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} = var registers: C_JmpBuf diff --git a/lib/system/hti.nim b/lib/system/hti.nim index e599668a7..aff0c0e6f 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -11,7 +11,7 @@ when declared(NimString): # we are in system module: {.pragma: codegenType, compilerproc.} else: - {.pragma: codegenType.} + {.pragma: codegenType, importc.} type # This should be he same as ast.TTypeKind @@ -26,7 +26,7 @@ type tyExpr, tyStmt, tyTypeDesc, - tyGenericInvokation, # ``T[a, b]`` for types to invoke + tyGenericInvocation, # ``T[a, b]`` for types to invoke tyGenericBody, # ``T[a, b, body]`` last parameter is the body tyGenericInst, # ``T[a, b, realInstance]`` instantiated generic type tyGenericParam, # ``a`` in the example @@ -65,7 +65,7 @@ type tyBigNum, TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase - TNimNode {.codegenType, final.} = object + TNimNode {.codegenType.} = object kind: TNimNodeKind offset: int typ: ptr TNimType @@ -78,7 +78,7 @@ type ntfAcyclic = 1, # type cannot form a cycle ntfEnumHole = 2 # enum has holes and thus `$` for them needs the slow # version - TNimType {.codegenType, final.} = object + TNimType {.codegenType.} = object size: int kind: TNimKind flags: set[TNimTypeFlag] diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 9b4a7d556..15b00f8f1 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -128,7 +128,7 @@ proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} = raise newException(OverflowError, "over- or underflow") proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn.} = - raise newException(DivByZeroError, "divison by zero") + raise newException(DivByZeroError, "division by zero") proc raiseRangeError() {.compilerproc, noreturn.} = raise newException(RangeError, "value out of range") diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 2de603cea..f1029ff6a 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -30,14 +30,16 @@ proc reprStrAux(result: var string, s: string) = add result, "nil" return add result, reprPointer(cast[pointer](s)) & "\"" - for c in items(s): + for i in 0.. <s.len: + let c = s[i] case c of '"': add result, "\\\"" of '\\': add result, "\\\\" # BUGFIX: forgotten of '\10': add result, "\\10\"\n\"" # " \n " # better readability of '\128' .. '\255', '\0'..'\9', '\11'..'\31': add result, "\\" & reprInt(ord(c)) - else: result.add(c) + else: + result.add(c) add result, "\"" proc reprStr(s: string): string {.compilerRtl.} = @@ -78,7 +80,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} = type PByteArray = ptr array[0.. 0xffff, int8] -proc addSetElem(result: var string, elem: int, typ: PNimType) {.gcsafe.} = +proc addSetElem(result: var string, elem: int, typ: PNimType) {.benign.} = case typ.kind of tyEnum: add result, reprEnum(elem, typ) of tyBool: add result, reprBool(bool(elem)) @@ -147,7 +149,7 @@ when not defined(useNimRtl): for i in 0..cl.indent-1: add result, ' ' proc reprAux(result: var string, p: pointer, typ: PNimType, - cl: var TReprClosure) {.gcsafe.} + cl: var TReprClosure) {.benign.} proc reprArray(result: var string, p: pointer, typ: PNimType, cl: var TReprClosure) = @@ -172,7 +174,7 @@ when not defined(useNimRtl): add result, "]" proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode, - cl: var TReprClosure) {.gcsafe.} = + cl: var TReprClosure) {.benign.} = case n.kind of nkNone: sysAssert(false, "reprRecordAux") of nkSlot: diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 7908fbe4d..48adb895d 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -132,7 +132,7 @@ proc rawFileSize(file: File): int = discard fseek(file, clong(oldPos), 0) proc readAllFile(file: File, len: int): string = - # We aquire the filesize beforehand and hope it doesn't change. + # We acquire the filesize beforehand and hope it doesn't change. # Speeds things up. result = newString(int(len)) if readBuffer(file, addr(result[0]), int(len)) != len: @@ -145,8 +145,8 @@ proc readAllFile(file: File): string = proc readAll(file: File): TaintedString = # Separate handling needed because we need to buffer when we # don't know the overall length of the File. - var len = rawFileSize(file) - if len >= 0: + let len = if file != stdin: rawFileSize(file) else: -1 + if len > 0: result = readAllFile(file, len).TaintedString else: result = readAllBuffer(file).TaintedString @@ -183,11 +183,17 @@ proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n") when (defined(windows) and not defined(useWinAnsi)) or defined(nimdoc): include "system/widestrs" -when defined(windows) and not defined(useWinAnsi): - proc wfopen(filename, mode: WideCString): pointer {. - importc: "_wfopen", nodecl.} - proc wfreopen(filename, mode: WideCString, stream: File): File {. - importc: "_wfreopen", nodecl.} +when defined(windows) and not defined(useWinAnsi): + when defined(cpp): + proc wfopen(filename, mode: WideCString): pointer {. + importcpp: "_wfopen((const wchar_t*)#, (const wchar_t*)#)", nodecl.} + proc wfreopen(filename, mode: WideCString, stream: File): File {. + importcpp: "_wfreopen((const wchar_t*)#, (const wchar_t*)#, #)", nodecl.} + else: + proc wfopen(filename, mode: WideCString): pointer {. + importc: "_wfopen", nodecl.} + proc wfreopen(filename, mode: WideCString, stream: File): File {. + importc: "_wfreopen", nodecl.} proc fopen(filename, mode: cstring): pointer = var f = newWideCString(filename) @@ -240,14 +246,14 @@ proc fwrite(buf: pointer, size, n: int, f: File): int {. proc readBuffer(f: File, buffer: pointer, len: int): int = result = fread(buffer, 1, len, f) -proc readBytes(f: File, a: var openArray[int8], start, len: int): int = +proc readBytes(f: File, a: var openArray[int8|uint8], start, len: int): int = result = readBuffer(f, addr(a[start]), len) proc readChars(f: File, a: var openArray[char], start, len: int): int = result = readBuffer(f, addr(a[start]), len) {.push stackTrace:off, profiler:off.} -proc writeBytes(f: File, a: openArray[int8], start, len: int): int = +proc writeBytes(f: File, a: openArray[int8|uint8], start, len: int): int = var x = cast[ptr array[0..1000_000_000, int8]](a) result = writeBuffer(f, addr(x[start]), len) proc writeChars(f: File, a: openArray[char], start, len: int): int = diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index 440d040a5..cfbc24f0c 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -208,7 +208,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. when compileOption("gc", "v2"): for i in newLen..result.len-1: let len0 = gch.tempStack.len - forAllChildrenAux(cast[pointer](cast[TAddress](result) +% + forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% (i*%elemSize)), extGetCellType(result).base, waPush) let len1 = gch.tempStack.len @@ -222,9 +222,9 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. extGetCellType(result).base, waZctDecRef) # XXX: zeroing out the memory can still result in crashes if a wiped-out - # cell is aliased by another pointer (ie proc paramter or a let variable). + # cell is aliased by another pointer (ie proc parameter or a let variable). # This is a tought problem, because even if we don't zeroMem here, in the - # presense of user defined destructors, the user will expect the cell to be + # presence of user defined destructors, the user will expect the cell to be # "destroyed" thus creating the same problem. We can destoy the cell in the # finalizer of the sequence, but this makes destruction non-deterministic. zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% @@ -264,7 +264,17 @@ proc nimFloatToStr(f: float): string {.compilerproc.} = buf[n] = '.' buf[n+1] = '0' buf[n+2] = '\0' - result = $buf + # On Windows nice numbers like '1.#INF', '-1.#INF' or '1.#NAN' are produced. + # We want to get rid of these here: + if buf[n-1] == 'N': + result = "nan" + elif buf[n-1] == 'F': + if buf[0] == '-': + result = "-inf" + else: + result = "inf" + else: + result = $buf proc strtod(buf: cstring, endptr: ptr cstring): float64 {.importc, header: "<stdlib.h>", noSideEffect.} diff --git a/lib/system/threads.nim b/lib/system/threads.nim index 496c31af1..81d9e5d73 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -84,8 +84,18 @@ when defined(windows): importc: "TlsAlloc", stdcall, header: "<windows.h>".} proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {. importc: "TlsSetValue", stdcall, header: "<windows.h>".} - proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {. + proc tlsGetValue(dwTlsIndex: TThreadVarSlot): pointer {. importc: "TlsGetValue", stdcall, header: "<windows.h>".} + + proc getLastError(): uint32 {. + importc: "GetLastError", stdcall, header: "<windows.h>".} + proc setLastError(x: uint32) {. + importc: "SetLastError", stdcall, header: "<windows.h>".} + + proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer = + let realLastError = getLastError() + result = tlsGetValue(dwTlsIndex) + setLastError(realLastError) else: proc threadVarAlloc(): TThreadVarSlot {. importc: "TlsAlloc", stdcall, dynlib: "kernel32".} @@ -95,7 +105,9 @@ when defined(windows): importc: "TlsGetValue", stdcall, dynlib: "kernel32".} else: - {.passL: "-pthread".} + when not defined(macosx): + {.passL: "-pthread".} + {.passC: "-pthread".} type diff --git a/lib/system/timers.nim b/lib/system/timers.nim index e58ff7adc..e5de791ac 100644 --- a/lib/system/timers.nim +++ b/lib/system/timers.nim @@ -27,9 +27,9 @@ when defined(windows): proc `-`(a, b: TTicks): TNanos = var frequency: int64 QueryPerformanceFrequency(frequency) - var performanceCounterRate = 1000000000.0 / toFloat(frequency.int) + var performanceCounterRate = 1e+9'f64 / float64(frequency) - result = ((a.int64 - b.int64).int.toFloat * performanceCounterRate).TNanos + result = TNanos(float64(a.int64 - b.int64) * performanceCounterRate) elif defined(macosx): type diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim index f0895217b..43c595a64 100644 --- a/lib/windows/windows.nim +++ b/lib/windows/windows.nim @@ -11616,7 +11616,7 @@ type dwPageSize*: DWORD lpMinimumApplicationAddress*: LPVOID lpMaximumApplicationAddress*: LPVOID - dwActiveProcessorMask*: DWORD + dwActiveProcessorMask*: DWORD_PTR dwNumberOfProcessors*: DWORD dwProcessorType*: DWORD dwAllocationGranularity*: DWORD diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 51a12141b..584f7cf48 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -284,6 +284,10 @@ when useWinUnicode: bFailIfExists: cint): cint {. importc: "CopyFileW", stdcall, dynlib: "kernel32".} + proc moveFileW*(lpExistingFileName, lpNewFileName: WideCString, + bFailIfExists: cint): cint {. + importc: "MoveFileW", stdcall, dynlib: "kernel32".} + proc getEnvironmentStringsW*(): WideCString {. stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".} proc freeEnvironmentStringsW*(para1: WideCString): int32 {. @@ -308,6 +312,10 @@ else: bFailIfExists: cint): cint {. importc: "CopyFileA", stdcall, dynlib: "kernel32".} + proc moveFileA*(lpExistingFileName, lpNewFileName: cstring, + bFailIfExists: cint): cint {. + importc: "MoveFileA", stdcall, dynlib: "kernel32".} + proc getEnvironmentStringsA*(): cstring {. stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".} proc freeEnvironmentStringsA*(para1: cstring): int32 {. diff --git a/lib/wrappers/claro.nim b/lib/wrappers/claro.nim index fb06da818..d36b9f178 100644 --- a/lib/wrappers/claro.nim +++ b/lib/wrappers/claro.nim @@ -64,7 +64,7 @@ proc node_move*(n: ptr TNode, oldlist: ptr TList, newlist: ptr TList){. cdecl, importc: "node_move", dynlib: clarodll.} type - TClaroObj*{.pure.} = object + TClaroObj*{.pure, inheritable.} = object typ*: array[0..64 - 1, char] destroy_pending*: cint event_handlers*: TList @@ -86,7 +86,7 @@ type TEventHandler*{.pure.} = object typ*: array[0..32 - 1, char] data*: pointer - func*: TEventFunc # the function that handles this event + fun*: TEventFunc # the function that handles this event # #define event_handler(n) void n ( TClaroObj *object, event_t *event ) @@ -121,10 +121,10 @@ proc object_set_parent*(obj: ptr TClaroObj, parent: ptr TClaroObj){.cdecl, # event functions proc object_addhandler*(obj: ptr TClaroObj, event: cstring, - func: TEventFunc){.cdecl, + fun: TEventFunc){.cdecl, importc: "object_addhandler", dynlib: clarodll.} proc object_addhandler_interface*(obj: ptr TClaroObj, event: cstring, - func: TEventFunc, data: pointer){.cdecl, + fun: TEventFunc, data: pointer){.cdecl, importc: "object_addhandler_interface", dynlib: clarodll.} proc event_send*(obj: ptr TClaroObj, event: cstring, fmt: cstring): cint{. varargs, cdecl, importc: "event_send", dynlib: clarodll.} @@ -258,7 +258,7 @@ proc image_load_inline_png*(parent: ptr TClaroObj, data: cstring, ## len size of data when true: - nil + discard else: # status icons are not supported on all platforms yet: type @@ -682,7 +682,7 @@ const type TCanvas*{.pure.} = object of TWidget surface*: cairo.PSurface - cr*: Cairo.PContext + cr*: cairo.PContext surfdata*: pointer fontdata*: pointer font_height*: cint @@ -854,7 +854,7 @@ proc canvas_cairo_buffered_text_display_count*(widget: ptr TCanvas, text: cstring, width: cint): cint{.cdecl, importc: "canvas_cairo_buffered_text_display_count", dynlib: clarodll.} -proc canvas_get_cairo_context*(widget: ptr TCanvas): Cairo.PContext {.cdecl, +proc canvas_get_cairo_context*(widget: ptr TCanvas): cairo.PContext {.cdecl, importc: "canvas_get_cairo_context", dynlib: clarodll.} type diff --git a/lib/wrappers/libffi/msvc/win32.c b/lib/wrappers/libffi/msvc/win32.c index d1149a85e..2754fd35d 100644 --- a/lib/wrappers/libffi/msvc/win32.c +++ b/lib/wrappers/libffi/msvc/win32.c @@ -90,7 +90,7 @@ noclean: // If the return value pointer is NULL, assume no return value. /* - Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction, + Intel asm is weird. We have to explicitly specify 'DWORD PTR' in the nexr instruction, otherwise only one BYTE will be compared (instead of a DWORD)! */ cmp DWORD PTR [ebp + 24], 0 diff --git a/lib/wrappers/libuv.nim b/lib/wrappers/libuv.nim index 3189ec408..a52ae0f63 100644 --- a/lib/wrappers/libuv.nim +++ b/lib/wrappers/libuv.nim @@ -30,9 +30,9 @@ type CheckProc* = proc (handle: PCheck, status: cint) {.cdecl.} IdleProc* = proc (handle: PIdle, status: cint) {.cdecl.} - PSockAddr* = ptr TSockAddr + PSockAddr* = ptr SockAddr - GetAddrInfoProc* = proc (handle: PGetAddrInfo, status: cint, res: ptr TAddrInfo) + GetAddrInfoProc* = proc (handle: PGetAddrInfo, status: cint, res: ptr AddrInfo) ExitProc* = proc (a2: PProcess, exit_status: cint, term_signal: cint) FsProc* = proc (req: PFS) @@ -210,7 +210,7 @@ type cunsigned = int UdpSendProc* = proc (req: PUdpSend, status: cint) - UdpRecvProc* = proc (handle: PUdp, nread: cssize, buf: TBuf, adr: ptr TSockAddr, flags: cunsigned) + UdpRecvProc* = proc (handle: PUdp, nread: cssize, buf: TBuf, adr: ptr SockAddr, flags: cunsigned) TUdp* {.pure, final, importc: "uv_udp_t", header: "uv.h".} = object loop* {.importc: "loop".}: PLoop @@ -366,7 +366,7 @@ type tcp_port* {.importc: "tcp_port".}: TPort socket_send_buffer_size* {.importc: "socket_send_buffer_size".}: int socket_recv_buffer_size* {.importc: "socket_receive_buffer_size".}: int - servers* {.importc: "servers".}: ptr TInAddr + servers* {.importc: "servers".}: ptr InAddr nservers* {.importc: "nservers".}: int domains* {.importc: "domains".}: ptr cstring ndomains* {.importc: "ndomains".}: int @@ -450,19 +450,19 @@ proc write*(req: PWrite, handle: PStream, bufs: ptr TBuf, bufcnt: cint, send_han proc tcp_init*(a2: PLoop, handle: PTcp): cint{. importc: "uv_tcp_init", header: "uv.h".} -proc tcp_bind*(handle: PTcp, a3: TSockAddrIn): cint{. +proc tcp_bind*(handle: PTcp, a3: SockAddrIn): cint{. importc: "uv_tcp_bind", header: "uv.h".} proc tcp_bind6*(handle: PTcp, a3: TSockAddrIn6): cint{. importc: "uv_tcp_bind6", header: "uv.h".} -proc tcp_getsockname*(handle: PTcp, name: ptr TSockAddr, namelen: var cint): cint{. +proc tcp_getsockname*(handle: PTcp, name: ptr SockAddr, namelen: var cint): cint{. importc: "uv_tcp_getsockname", header: "uv.h".} -proc tcp_getpeername*(handle: PTcp, name: ptr TSockAddr, namelen: var cint): cint{. +proc tcp_getpeername*(handle: PTcp, name: ptr SockAddr, namelen: var cint): cint{. importc: "uv_tcp_getpeername", header: "uv.h".} -proc tcp_connect*(req: PConnect, handle: PTcp, address: TSockAddrIn, cb: ConnectProc): cint{. +proc tcp_connect*(req: PConnect, handle: PTcp, address: SockAddrIn, cb: ConnectProc): cint{. importc: "uv_tcp_connect", header: "uv.h".} proc tcp_connect6*(req: PConnect, handle: PTcp, address: TSockAddrIn6, cb: ConnectProc): cint{. @@ -471,16 +471,16 @@ proc tcp_connect6*(req: PConnect, handle: PTcp, address: TSockAddrIn6, cb: Conne proc udp_init*(a2: PLoop, handle: PUdp): cint{. importc: "uv_udp_init", header: "uv.h".} -proc udp_bind*(handle: PUdp, adr: TSockAddrIn, flags: cunsigned): cint{. +proc udp_bind*(handle: PUdp, adr: SockAddrIn, flags: cunsigned): cint{. importc: "uv_udp_bind", header: "uv.h".} proc udp_bind6*(handle: PUdp, adr: TSockAddrIn6, flags: cunsigned): cint{. importc: "uv_udp_bind6", header: "uv.h".} -proc udp_getsockname*(handle: PUdp, name: ptr TSockAddr, namelen: var cint): cint{. +proc udp_getsockname*(handle: PUdp, name: ptr SockAddr, namelen: var cint): cint{. importc: "uv_udp_getsockname", header: "uv.h".} -proc udp_send*(req: PUdpSend, handle: PUdp, bufs: ptr TBuf, bufcnt: cint, adr: TSockAddrIn, send_cb: UdpSendProc): cint{. +proc udp_send*(req: PUdpSend, handle: PUdp, bufs: ptr TBuf, bufcnt: cint, adr: SockAddrIn, send_cb: UdpSendProc): cint{. importc: "uv_udp_send", header: "uv.h".} proc udp_send6*(req: PUdpSend, handle: PUdp, bufs: ptr TBuf, bufcnt: cint, adr: TSockAddrIn6, send_cb: UdpSendProc): cint{. @@ -492,7 +492,7 @@ proc udp_recv_start*(handle: PUdp, alloc_cb: AllocProc, recv_cb: UdpRecvProc): c proc udp_recv_stop*(handle: PUdp): cint{. importc: "uv_udp_recv_stop", header: "uv.h".} -proc tty_init*(a2: PLoop, a3: pTTy, fd: TFile): cint{. +proc tty_init*(a2: PLoop, a3: pTTy, fd: File): cint{. importc: "uv_tty_init", header: "uv.h".} proc tty_set_mode*(a2: pTTy, mode: cint): cint{. @@ -504,13 +504,13 @@ proc tty_get_winsize*(a2: pTTy, width: var cint, height: var cint): cint{. proc tty_reset_mode*() {. importc: "uv_tty_reset_mode", header: "uv.h".} -proc guess_handle*(file: TFile): THandleType{. +proc guess_handle*(file: File): THandleType{. importc: "uv_guess_handle", header: "uv.h".} proc pipe_init*(a2: PLoop, handle: PPipe, ipc: int): cint{. importc: "uv_pipe_init", header: "uv.h".} -proc pipe_open*(a2: PPipe, file: TFile){. +proc pipe_open*(a2: PPipe, file: File){. importc: "uv_pipe_open", header: "uv.h".} proc pipe_bind*(handle: PPipe, name: cstring): cint{. @@ -576,10 +576,10 @@ proc ares_init_options*(a2: PLoop, channel: PAresChannel, options: PAresOptions, proc ares_destroy*(a2: PLoop, channel: PAresChannel){. importc: "uv_ares_destroy", header: "uv.h".} -proc getaddrinfo*(a2: PLoop, handle: PGetAddrInfo,getaddrinfo_cb: GetAddrInfoProc, node: cstring, service: cstring, hints: ptr TAddrInfo): cint{. +proc getaddrinfo*(a2: PLoop, handle: PGetAddrInfo,getaddrinfo_cb: GetAddrInfoProc, node: cstring, service: cstring, hints: ptr AddrInfo): cint{. importc: "uv_getaddrinfo", header: "uv.h".} -proc freeaddrinfo*(ai: ptr TAddrInfo){. +proc freeaddrinfo*(ai: ptr AddrInfo){. importc: "uv_freeaddrinfo", header: "uv.h".} proc spawn*(a2: PLoop, a3: PProcess, options: TProcessOptions): cint{. @@ -594,19 +594,19 @@ proc queue_work*(loop: PLoop, req: PWork, work_cb: WorkProc, after_work_cb: Afte proc req_cleanup*(req: PFS){. importc: "uv_fs_req_cleanup", header: "uv.h".} -proc close*(loop: PLoop, req: PFS, file: TFile, cb: FsProc): cint{. +proc close*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{. importc: "uv_fs_close", header: "uv.h".} proc open*(loop: PLoop, req: PFS, path: cstring, flags: cint, mode: cint, cb: FsProc): cint{. importc: "uv_fs_open", header: "uv.h".} -proc read*(loop: PLoop, req: PFS, file: TFile, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{. +proc read*(loop: PLoop, req: PFS, file: File, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{. importc: "uv_fs_read", header: "uv.h".} proc unlink*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{. importc: "uv_fs_unlink", header: "uv.h".} -proc write*(loop: PLoop, req: PFS, file: TFile, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{. +proc write*(loop: PLoop, req: PFS, file: File, buf: pointer, length: csize, offset: coff, cb: FsProc): cint{. importc: "uv_fs_write", header: "uv.h".} proc mkdir*(loop: PLoop, req: PFS, path: cstring, mode: cint, cb: FsProc): cint{. @@ -621,22 +621,22 @@ proc readdir*(loop: PLoop, req: PFS, path: cstring, flags: cint, cb: FsProc): ci proc stat*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{. importc: "uv_fs_stat", header: "uv.h".} -proc fstat*(loop: PLoop, req: PFS, file: TFile, cb: FsProc): cint{. +proc fstat*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{. importc: "uv_fs_fstat", header: "uv.h".} proc rename*(loop: PLoop, req: PFS, path: cstring, new_path: cstring, cb: FsProc): cint{. importc: "uv_fs_rename", header: "uv.h".} -proc fsync*(loop: PLoop, req: PFS, file: TFile, cb: FsProc): cint{. +proc fsync*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{. importc: "uv_fs_fsync", header: "uv.h".} -proc fdatasync*(loop: PLoop, req: PFS, file: TFile, cb: FsProc): cint{. +proc fdatasync*(loop: PLoop, req: PFS, file: File, cb: FsProc): cint{. importc: "uv_fs_fdatasync", header: "uv.h".} -proc ftruncate*(loop: PLoop, req: PFS, file: TFile, offset: coff, cb: FsProc): cint{. +proc ftruncate*(loop: PLoop, req: PFS, file: File, offset: coff, cb: FsProc): cint{. importc: "uv_fs_ftruncate", header: "uv.h".} -proc sendfile*(loop: PLoop, req: PFS, out_fd: TFile, in_fd: TFile, in_offset: coff, length: csize, cb: FsProc): cint{. +proc sendfile*(loop: PLoop, req: PFS, out_fd: File, in_fd: File, in_offset: coff, length: csize, cb: FsProc): cint{. importc: "uv_fs_sendfile", header: "uv.h".} proc chmod*(loop: PLoop, req: PFS, path: cstring, mode: cint, cb: FsProc): cint{. @@ -645,7 +645,7 @@ proc chmod*(loop: PLoop, req: PFS, path: cstring, mode: cint, cb: FsProc): cint{ proc utime*(loop: PLoop, req: PFS, path: cstring, atime: cdouble, mtime: cdouble, cb: FsProc): cint{. importc: "uv_fs_utime", header: "uv.h".} -proc futime*(loop: PLoop, req: PFS, file: TFile, atime: cdouble, mtime: cdouble, cb: FsProc): cint{. +proc futime*(loop: PLoop, req: PFS, file: File, atime: cdouble, mtime: cdouble, cb: FsProc): cint{. importc: "uv_fs_futime", header: "uv.h".} proc lstat*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{. @@ -660,25 +660,25 @@ proc symlink*(loop: PLoop, req: PFS, path: cstring, new_path: cstring, flags: ci proc readlink*(loop: PLoop, req: PFS, path: cstring, cb: FsProc): cint{. importc: "uv_fs_readlink", header: "uv.h".} -proc fchmod*(loop: PLoop, req: PFS, file: TFile, mode: cint, cb: FsProc): cint{. +proc fchmod*(loop: PLoop, req: PFS, file: File, mode: cint, cb: FsProc): cint{. importc: "uv_fs_fchmod", header: "uv.h".} proc chown*(loop: PLoop, req: PFS, path: cstring, uid: cint, gid: cint, cb: FsProc): cint{. importc: "uv_fs_chown", header: "uv.h".} -proc fchown*(loop: PLoop, req: PFS, file: TFile, uid: cint, gid: cint, cb: FsProc): cint{. +proc fchown*(loop: PLoop, req: PFS, file: File, uid: cint, gid: cint, cb: FsProc): cint{. importc: "uv_fs_fchown", header: "uv.h".} proc event_init*(loop: PLoop, handle: PFSEvent, filename: cstring, cb: FsEventProc): cint{. importc: "uv_fs_event_init", header: "uv.h".} -proc ip4_addr*(ip: cstring, port: cint): TSockAddrIn{. +proc ip4_addr*(ip: cstring, port: cint): SockAddrIn{. importc: "uv_ip4_addr", header: "uv.h".} proc ip6_addr*(ip: cstring, port: cint): TSockAddrIn6{. importc: "uv_ip6_addr", header: "uv.h".} -proc ip4_name*(src: ptr TSockAddrIn, dst: cstring, size: csize): cint{. +proc ip4_name*(src: ptr SockAddrIn, dst: cstring, size: csize): cint{. importc: "uv_ip4_name", header: "uv.h".} proc ip6_name*(src: ptr TSockAddrIn6, dst: cstring, size: csize): cint{. diff --git a/lib/wrappers/mysql.nim b/lib/wrappers/mysql.nim index 9161f5672..937a8952a 100644 --- a/lib/wrappers/mysql.nim +++ b/lib/wrappers/mysql.nim @@ -13,7 +13,7 @@ when defined(Unix): when defined(macosx): const - lib = "libmysqlclient.(15|16|17[18).dylib" + lib = "libmysqlclient.(15|16|17|18).dylib" else: const lib = "libmysqlclient.so.(15|16|17|18)" @@ -63,9 +63,9 @@ type const SCRAMBLE_LENGTH* = 20 # Length of random string sent by server on handshake; # this is also length of obfuscated password, - # recieved from client + # received from client SCRAMBLE_LENGTH_323* = 8 # length of password stored in the db: - # new passwords are preceeded with '*' + # new passwords are preceded with '*' SCRAMBLED_PASSWORD_CHAR_LENGTH* = SCRAMBLE_LENGTH * 2 + 1 SCRAMBLED_PASSWORD_CHAR_LENGTH_323* = SCRAMBLE_LENGTH_323 * 2 NOT_NULL_FLAG* = 1 # Field can't be NULL @@ -146,7 +146,7 @@ const MAX_MEDIUMINT_WIDTH* = 8 # Max width for a INT24 w.o. sign MAX_INT_WIDTH* = 10 # Max width for a LONG w.o. sign MAX_BIGINT_WIDTH* = 20 # Max width for a LONGLONG - MAX_CHAR_WIDTH* = 255 # Max length for a CHAR colum + MAX_CHAR_WIDTH* = 255 # Max length for a CHAR column MAX_BLOB_WIDTH* = 8192 # Default width for blob type @@ -558,7 +558,7 @@ type Tstatus* = enum STATUS_READY, STATUS_GET_RESULT, STATUS_USE_RESULT Tprotocol_type* = enum # There are three types of queries - the ones that have to go to - # the master, the ones that go to a slave, and the adminstrative + # the master, the ones that go to a slave, and the administrative # type which must happen on the pivot connectioin PROTOCOL_DEFAULT, PROTOCOL_TCP, PROTOCOL_SOCKET, PROTOCOL_PIPE, PROTOCOL_MEMORY @@ -790,7 +790,7 @@ proc server_init*(argc: cint, argv: cstringArray, groups: cstringArray): cint{. proc server_end*(){.cdecl, dynlib: lib, importc: "mysql_server_end".} # mysql_server_init/end need to be called when using libmysqld or # libmysqlclient (exactly, mysql_server_init() is called by mysql_init() so - # you don't need to call it explicitely; but you need to call + # you don't need to call it explicitly; but you need to call # mysql_server_end() to free memory). The names are a bit misleading # (mysql_SERVER* to be used when using libmysqlCLIENT). So we add more general # names which suit well whether you're using libmysqld or libmysqlclient. We diff --git a/lib/wrappers/readline/history.nim b/lib/wrappers/readline/history.nim index caa857ceb..495bc15e4 100644 --- a/lib/wrappers/readline/history.nim +++ b/lib/wrappers/readline/history.nim @@ -231,7 +231,7 @@ proc history_truncate_file*(a2: cstring, a3: cint): cint{.cdecl, # -1) If there was an error in expansion. # 2) If the returned line should just be printed. # -# If an error ocurred in expansion, then OUTPUT contains a descriptive +# If an error occurred in expansion, then OUTPUT contains a descriptive # error message. proc history_expand*(a2: cstring, a3: cstringArray): cint{.cdecl, diff --git a/lib/wrappers/readline/tweaked/history.h b/lib/wrappers/readline/tweaked/history.h index 53bd642b1..b79123790 100644 --- a/lib/wrappers/readline/tweaked/history.h +++ b/lib/wrappers/readline/tweaked/history.h @@ -217,7 +217,7 @@ extern int history_truncate_file PARAMS((const char *, int)); -1) If there was an error in expansion. 2) If the returned line should just be printed. - If an error ocurred in expansion, then OUTPUT contains a descriptive + If an error occurred in expansion, then OUTPUT contains a descriptive error message. */ extern int history_expand PARAMS((char *, char **)); diff --git a/lib/wrappers/sdl/sdl.nim b/lib/wrappers/sdl/sdl.nim index 449b651f9..5bb5b7ec2 100644 --- a/lib/wrappers/sdl/sdl.nim +++ b/lib/wrappers/sdl/sdl.nim @@ -89,7 +89,7 @@ # As most games will need it. # # April 02 2001 - DL : Added SDL_getenv.h definitions and tested version -# 1.2.0 compatability. +# 1.2.0 compatibility. # # March 13 2001 - MT : Added Linux compatibility. # @@ -118,7 +118,7 @@ # # November 30 2001 - DL : SDL_NOFRAME added as pointed out by Simon Rushton. # -# December 11 2001 - DL : Added $WEAKPACKAGEUNIT ON to facilitate useage in +# December 11 2001 - DL : Added $WEAKPACKAGEUNIT ON to facilitate usage in # Components # # January 05 2002 - DL : Added SDL_Swap32 function as suggested by Matthias @@ -209,7 +209,7 @@ # forgot to apply Michalis Kamburelis' patch to the implementation section. now fixed # # Revision 1.14 2004/12/23 23:42:18 savage -# Applied Patches supplied by Michalis Kamburelis ( THANKS! ), for greater FreePascal compatability. +# Applied Patches supplied by Michalis Kamburelis ( THANKS! ), for greater FreePascal compatibility. # # Revision 1.13 2004/09/30 22:31:59 savage # Updated with slightly different header comments @@ -221,7 +221,7 @@ # Updated so that Library name defines are correctly defined for MacOS X. # # Revision 1.10 2004/07/20 23:57:33 savage -# Thanks to Paul Toth for spotting an error in the SDL Audio Convertion structures. +# Thanks to Paul Toth for spotting an error in the SDL Audio Conversion structures. # In TSDL_AudioCVT the filters variable should point to and array of pointers and not what I had there previously. # # Revision 1.9 2004/07/03 22:07:22 savage @@ -243,7 +243,7 @@ # SDL_GetEnv Fix so that it is not define twice for FPC. Thanks to Rene Hugentobler for pointing out this bug, # # Revision 1.3 2004/02/18 22:35:51 savage -# Brought sdl.pas up to 1.2.7 compatability +# Brought sdl.pas up to 1.2.7 compatibility # Thus... # Added SDL_GL_STEREO, # SDL_GL_MULTISAMPLEBUFFERS, diff --git a/lib/wrappers/sdl/sdl_mixer.nim b/lib/wrappers/sdl/sdl_mixer.nim index 33a71508a..2f8664635 100644 --- a/lib/wrappers/sdl/sdl_mixer.nim +++ b/lib/wrappers/sdl/sdl_mixer.nim @@ -136,7 +136,7 @@ # Windows unit not used in this file, so it was removed to keep the code tidy. # # Revision 1.3 2004/03/31 10:05:08 savage -# Better defines for Endianess under FreePascal and Borland compilers. +# Better defines for Endianness under FreePascal and Borland compilers. # # Revision 1.2 2004/03/30 20:23:28 savage # Tidied up use of UNIX compiler directive. diff --git a/lib/wrappers/zip/zlib.nim b/lib/wrappers/zip/zlib.nim index e3530d566..8bdb47106 100644 --- a/lib/wrappers/zip/zlib.nim +++ b/lib/wrappers/zip/zlib.nim @@ -232,7 +232,7 @@ proc uncompress*(sourceBuf: cstring, sourceLen: int): string = return # Make sure memory allocated by inflateInit2() is freed eventually. - finally: discard inflateEnd(z) + defer: discard inflateEnd(z) # Decompress all of self. while true: diff --git a/readme.md b/readme.md index d5968982b..e716c0d0d 100644 --- a/readme.md +++ b/readme.md @@ -39,8 +39,7 @@ $ bin/nim c koch $ ./koch boot -d:release ``` -``koch install [dir]`` may then be used to install Nim, or you can simply -add it to your PATH. More ``koch`` related options are documented in +``koch install [dir]`` may then be used to install Nim, but lots of things don't work then so don't do that. Add it to your PATH instead. More ``koch`` related options are documented in [doc/koch.txt](doc/koch.txt). The above steps can be performed on Windows in a similar fashion, the @@ -62,12 +61,28 @@ allowing you to create commercial applications. Read copying.txt for more details. -Copyright (c) 2006-2014 Andreas Rumpf. +Copyright (c) 2006-2015 Andreas Rumpf. All rights reserved. # Build Status -| |Linux|Windows|Mac| -|---|---|---|---| -| x86 |  |  |  -| x86_64 |  |  |  -| arm |  | +[**Build Waterfall**][waterfall] + +| | Linux | Windows | Mac | +| ------ | ----- | ------- | --- | +| x86 | ![linux-x86][linux-x86-img] | ![windows-x86][windows-x86-img] | ![mac-x86][mac-x86-img] | +| x86_64 | ![linux-x86_64][linux-x86_64-img] | ![windows-x86_64][windows-x86_64-img] | ![mac-x86_64][mac-x86_64-img] | +| arm | ![linux-armv5][linux-arm5-img]<br/> ![linux-armv6][linux-arm6-img]<br/> ![linux-armv7][linux-arm7-img] | | | + +[linux-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x32-builder +[linux-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-x64-builder +[linux-arm5-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm5-builder +[linux-arm6-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm6-builder +[linux-arm7-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=linux-arm7-builder + +[windows-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x32-builder +[windows-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=windows-x64-builder + +[mac-x86-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x32-builder +[mac-x86_64-img]: http://buildbot.nim-lang.org/buildstatusimage?builder=mac-x64-builder + +[waterfall]: http://buildbot.nim-lang.org/waterfall diff --git a/tests/actiontable/tactiontable2.nim b/tests/actiontable/tactiontable2.nim index 99bb3dca0..fbc65a67d 100644 --- a/tests/actiontable/tactiontable2.nim +++ b/tests/actiontable/tactiontable2.nim @@ -1,6 +1,5 @@ discard """ - line: 21 - errormsg: "invalid type: 'Table[string, proc (string){.gcsafe.}]'" + output: "action 3 arg" """ import tables diff --git a/tests/assert/tfailedassert.nim b/tests/assert/tfailedassert.nim index d03d3136b..16769f529 100644 --- a/tests/assert/tfailedassert.nim +++ b/tests/assert/tfailedassert.nim @@ -10,7 +10,7 @@ tfailedassert.nim:27 false assertion from foo type TLineInfo = tuple[filename: string, line: int] - TMyError = object of E_Base + TMyError = object of Exception lineinfo: TLineInfo EMyError = ref TMyError diff --git a/tests/async/tasyncexceptions.nim b/tests/async/tasyncexceptions.nim index 30ef41756..c4379f7d8 100644 --- a/tests/async/tasyncexceptions.nim +++ b/tests/async/tasyncexceptions.nim @@ -19,7 +19,6 @@ proc processClient(fd: int) {.async.} = var foo = line[0] if foo == 'g': raise newException(EBase, "foobar") - proc serve() {.async.} = diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim index 66ea40d49..99433b9d8 100644 --- a/tests/async/tasynctry.nim +++ b/tests/async/tasynctry.nim @@ -49,3 +49,44 @@ proc catch() {.async.} = assert false asyncCheck catch() + +proc test(): Future[bool] {.async.} = + result = false + try: + raise newException(OSError, "Foobar") + except: + result = true + return + +proc foo(): Future[bool] {.async.} = discard + +proc test2(): Future[bool] {.async.} = + result = false + try: + discard await foo() + raise newException(OSError, "Foobar") + except: + result = true + return + +proc test3(): Future[int] {.async.} = + result = 0 + try: + try: + discard await foo() + raise newException(OSError, "Hello") + except: + result = 1 + raise + except: + result = 2 + return + +var x = test() +assert x.read + +x = test2() +assert x.read + +var y = test3() +assert y.read == 2 diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim index e1ff090dd..bf6d92927 100644 --- a/tests/bind/tnicerrorforsymchoice.nim +++ b/tests/bind/tnicerrorforsymchoice.nim @@ -1,6 +1,6 @@ discard """ line: 18 - errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string){.gcsafe.})" + errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string)" """ #bug #442 diff --git a/tests/caas/issue_416_template_shift.txt b/tests/caas/issue_416_template_shift.txt index b1f47c1ac..e911c1360 100644 --- a/tests/caas/issue_416_template_shift.txt +++ b/tests/caas/issue_416_template_shift.txt @@ -6,7 +6,7 @@ def\tskType\tsystem.string\tstring > idetools --track:$TESTNIM,12,35 --def $SILENT def\tskLet\t$MODULE.failtest.input\tTaintedString -# The following fail because they seem shifted one colum to the right. +# The following fail because they seem shifted one column to the right. > idetools --track:$TESTNIM,12,16 --def $SILENT def\tskTemplate\tsequtils.toSeq\tproc \(expr\): expr > idetools --track:$TESTNIM,12,22 --def $SILENT diff --git a/tests/caas/its_full_of_procs.nim b/tests/caas/its_full_of_procs.nim index 45347490c..8f8b66764 100644 --- a/tests/caas/its_full_of_procs.nim +++ b/tests/caas/its_full_of_procs.nim @@ -2,7 +2,7 @@ import unicode, sequtils # This example shows that idetools returns proc as signature for everything # which can be called. While a clever person would use the second column to -# differentiate betwen procs, methods and others, why does the output contain +# differentiate between procs, methods and others, why does the output contain # incorrect information? type diff --git a/tests/casestmt/tcase_emptyset_when.nim b/tests/casestmt/tcase_emptyset_when.nim new file mode 100644 index 000000000..e9b1ec2df --- /dev/null +++ b/tests/casestmt/tcase_emptyset_when.nim @@ -0,0 +1,24 @@ +discard """ + file: "tcaseofwhen.nim" + outputsub: "compiles for 1\ni am always two\ndefault for 3\nset is 4 not 5\narray is 6 not 7\ndefault for 8" + exitcode: "0" +""" + +proc whenCase(a: int) = + case a + of (when compiles(whenCase(1)): 1 else: {}): echo "compiles for 1" + of {}: echo "me not fail" + of 2: echo "i am always two" + of []: echo "me neither" + of {4,5}: echo "set is 4 not 5" + of [6,7]: echo "array is 6 not 7" + of (when compiles(neverCompilesIBet()): 3 else: {}): echo "compiles for 3" + #of {},[]: echo "me neither" + else: echo "default for ", a + +whenCase(1) +whenCase(2) +whenCase(3) +whenCase(4) +whenCase(6) +whenCase(8) diff --git a/tests/ccgbugs/tmissingderef.nim b/tests/ccgbugs/tmissingderef.nim new file mode 100644 index 000000000..edff1dd4e --- /dev/null +++ b/tests/ccgbugs/tmissingderef.nim @@ -0,0 +1,30 @@ +discard """ + output: '''255 +1 1 +0.5''' +""" + +# bug #1181 + +type + TFoo = object + x: int32 + +proc mainowar = + var foo: TFoo + foo.x = 0xff + var arr1 = cast[ptr array[4, uint8]](addr foo)[] # Fails. + echo arr1[when cpuEndian == littleEndian: 0 else: 3] + + var i = 1i32 + let x = addr i + var arr2 = cast[ptr array[4, uint8]](x)[] # Fails. + echo arr2[when cpuEndian == littleEndian: 0 else: 3], " ", i + + # bug #1715 + var a: array[2, float32] = [0.5'f32, 0.7] + let p = addr a + var b = p[] + echo b[0] + +mainowar() diff --git a/tests/ccgbugs/trecursive_closure.nim b/tests/ccgbugs/trecursive_closure.nim new file mode 100644 index 000000000..50c363a4a --- /dev/null +++ b/tests/ccgbugs/trecursive_closure.nim @@ -0,0 +1,8 @@ +# bug #2233 +type MalType = object + fun: proc: MalType + +proc f(x: proc: MalType) = + discard x() + +f(nil) diff --git a/tests/clearmsg/ta.nim b/tests/clearmsg/ta.nim index b21522d12..38449c319 100644 --- a/tests/clearmsg/ta.nim +++ b/tests/clearmsg/ta.nim @@ -1,5 +1,5 @@ discard """ - errormsg: 'type mismatch: got (mc.typ)' + errormsg: "type mismatch: got (mc.typ)" line: 12 """ diff --git a/tests/closure/tfib50.nim b/tests/closure/tfib50.nim new file mode 100644 index 000000000..719aa3ad5 --- /dev/null +++ b/tests/closure/tfib50.nim @@ -0,0 +1,22 @@ +discard """ + output: "20365011074" +""" + +import tables + +proc memoize(f: proc (a: int64): int64): proc (a: int64): int64 = + var previous = initTable[int64, int64]() + return proc(i: int64): int64 = + if not previous.hasKey i: + previous[i] = f(i) + return previous[i] + +var fib: proc(a: int64): int64 + +fib = memoize(proc (i: int64): int64 = + if i == 0 or i == 1: + return 1 + return fib(i-1) + fib(i-2) +) + +echo fib(50) diff --git a/tests/closure/tissue1642.nim b/tests/closure/tissue1642.nim index d396630c8..e3028c88e 100644 --- a/tests/closure/tissue1642.nim +++ b/tests/closure/tissue1642.nim @@ -1,5 +1,6 @@ discard """ file: "tissue1642.nim" + disabled: true """ block: var i = 0 diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim new file mode 100644 index 000000000..3138ae72e --- /dev/null +++ b/tests/closure/ttimeinfo.nim @@ -0,0 +1,15 @@ +# bug #2073 + +import sequtils +import times + +# 1 +proc f(n: int): TimeInfo = + TimeInfo(year: n, month: mJan, monthday: 1) + +echo toSeq(2000 || 2015).map(f) + +# 2 +echo toSeq(2000 || 2015).map(proc (n: int): TimeInfo = + TimeInfo(year: n, month: mJan, monthday: 1) +) diff --git a/tests/collections/tindexby.nim b/tests/collections/tindexby.nim new file mode 100644 index 000000000..f374d5504 --- /dev/null +++ b/tests/collections/tindexby.nim @@ -0,0 +1,22 @@ +import tables + +doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table" + +var tbl1 = initTable[int, int]() +tbl1.add(1,1) +tbl1.add(2,2) +doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table" + +type + TElem = object + foo: int + bar: string + +let + elem1 = TElem(foo: 1, bar: "bar") + elem2 = TElem(foo: 2, bar: "baz") + +var tbl2 = initTable[string, TElem]() +tbl2.add("bar", elem1) +tbl2.add("baz", elem2) +doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table" diff --git a/tests/table/ttableconstr.nim b/tests/collections/ttableconstr.nim index 1a21a18d1..1a21a18d1 100644 --- a/tests/table/ttableconstr.nim +++ b/tests/collections/ttableconstr.nim diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim index f374d5504..3a923610e 100644 --- a/tests/collections/ttables.nim +++ b/tests/collections/ttables.nim @@ -1,22 +1,152 @@ -import tables - -doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table" - -var tbl1 = initTable[int, int]() -tbl1.add(1,1) -tbl1.add(2,2) -doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table" - -type - TElem = object - foo: int - bar: string - -let - elem1 = TElem(foo: 1, bar: "bar") - elem2 = TElem(foo: 2, bar: "baz") +discard """ + output: '''true''' +""" + +import hashes, tables + +const + data = { + "34": 123456, "12": 789, + "90": 343, "0": 34404, + "1": 344004, "2": 344774, + "3": 342244, "4": 3412344, + "5": 341232144, "6": 34214544, + "7": 3434544, "8": 344544, + "9": 34435644, "---00": 346677844, + "10": 34484, "11": 34474, "19": 34464, + "20": 34454, "30": 34141244, "40": 344114, + "50": 344490, "60": 344491, "70": 344492, + "80": 344497} + + sorteddata = { + "---00": 346677844, + "0": 34404, + "1": 344004, + "10": 34484, + "11": 34474, + "12": 789, + "19": 34464, + "2": 344774, "20": 34454, + "3": 342244, "30": 34141244, + "34": 123456, + "4": 3412344, "40": 344114, + "5": 341232144, "50": 344490, + "6": 34214544, "60": 344491, + "7": 3434544, "70": 344492, + "8": 344544, "80": 344497, + "9": 34435644, + "90": 343} + +block tableTest1: + var t = initTable[tuple[x, y: int], string]() + t[(0,0)] = "00" + t[(1,0)] = "10" + t[(0,1)] = "01" + t[(1,1)] = "11" + for x in 0..1: + for y in 0..1: + assert t[(x,y)] == $x & $y + assert($t == + "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") + +block tableTest2: + var t = initTable[string, float]() + t["test"] = 1.2345 + t["111"] = 1.000043 + t["123"] = 1.23 + t.del("111") -var tbl2 = initTable[string, TElem]() -tbl2.add("bar", elem1) -tbl2.add("baz", elem2) -doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table" + t["012"] = 67.9 + t["123"] = 1.5 # test overwriting + + assert t["123"] == 1.5 + assert t["111"] == 0.0 # deleted + assert(not hasKey(t, "111")) + + for key, val in items(data): t[key] = val.toFloat + for key, val in items(data): assert t[key] == val.toFloat + + assert(not t.hasKeyOrPut("456", 4.0)) # test absent key + assert t.hasKeyOrPut("012", 3.0) # test present key + var x = t.mgetOrPut("111", 1.5) # test absent key + x = x * 2 + assert x == 3.0 + x = t.mgetOrPut("test", 1.5) # test present key + x = x * 2 + assert x == 2 * 1.2345 + +block orderedTableTest1: + var t = initOrderedTable[string, int](2) + for key, val in items(data): t[key] = val + for key, val in items(data): assert t[key] == val + var i = 0 + # `pairs` needs to yield in insertion order: + for key, val in pairs(t): + assert key == data[i][0] + assert val == data[i][1] + inc(i) + + for key, val in mpairs(t): val = 99 + for val in mvalues(t): assert val == 99 + +block countTableTest1: + var s = data.toTable + var t = initCountTable[string]() + for k in s.keys: t.inc(k) + for k in t.keys: assert t[k] == 1 + t.inc("90", 3) + t.inc("12", 2) + t.inc("34", 1) + assert t.largest()[0] == "90" + + t.sort() + var i = 0 + for k, v in t.pairs: + case i + of 0: assert k == "90" and v == 4 + of 1: assert k == "12" and v == 3 + of 2: assert k == "34" and v == 2 + else: break + inc i + +block mpairsTableTest1: + var t = initTable[string, int]() + t["a"] = 1 + t["b"] = 2 + t["c"] = 3 + t["d"] = 4 + for k, v in t.mpairs: + if k == "a" or k == "c": + v = 9 + + for k, v in t.pairs: + if k == "a" or k == "c": + assert v == 9 + else: + assert v != 1 and v != 3 + +block SyntaxTest: + var x = toTable[int, string]({:}) + +proc orderedTableSortTest() = + var t = initOrderedTable[string, int](2) + for key, val in items(data): t[key] = val + for key, val in items(data): assert t[key] == val + t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key)) + var i = 0 + # `pairs` needs to yield in sorted order: + for key, val in pairs(t): + doAssert key == sorteddata[i][0] + doAssert val == sorteddata[i][1] + inc(i) + + # check that lookup still works: + for key, val in pairs(t): + doAssert val == t[key] + # check that insert still works: + t["newKeyHere"] = 80 + + +orderedTableSortTest() +echo "true" + diff --git a/tests/table/ttables2.nim b/tests/collections/ttables2.nim index 611f3f8ec..6f3fa841a 100644 --- a/tests/table/ttables2.nim +++ b/tests/collections/ttables2.nim @@ -16,5 +16,15 @@ proc run1() = # occupied Memory stays constant, but for i in 1 .. 50: # aborts at run: 44 on win32 with 3.2GB with out of memory TestHashIntInt() +# bug #2107 + +var delTab = initTable[int,int](4) + +for i in 1..4: + delTab[i] = i + delTab.del(i) +delTab[5] = 5 + + run1() echo "true" diff --git a/tests/table/ptables.nim b/tests/collections/ttablesref.nim index 79a9aab17..b57aedf4a 100644 --- a/tests/table/ptables.nim +++ b/tests/collections/ttablesref.nim @@ -47,7 +47,7 @@ block tableTest1: for y in 0..1: assert t[(x,y)] == $x & $y assert($t == - "{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") + "{(x: 0, y: 1): 01, (x: 0, y: 0): 00, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") block tableTest2: var t = newTable[string, float]() @@ -84,7 +84,7 @@ block orderedTableTest1: block countTableTest1: var s = data.toTable var t = newCountTable[string]() - for k in s.Keys: t.inc(k) + for k in s.keys: t.inc(k) for k in t.keys: assert t[k] == 1 t.inc("90", 3) t.inc("12", 2) diff --git a/tests/table/ptables2.nim b/tests/collections/ttablesref2.nim index 939de2b84..939de2b84 100644 --- a/tests/table/ptables2.nim +++ b/tests/collections/ttablesref2.nim diff --git a/tests/cpp/trawsockets.nim b/tests/cpp/trawsockets.nim new file mode 100644 index 000000000..bc129de57 --- /dev/null +++ b/tests/cpp/trawsockets.nim @@ -0,0 +1,5 @@ +discard """ + cmd: "nim cpp $file" +""" + +import rawsockets diff --git a/tests/cpp/ttypeinfo.nim b/tests/cpp/ttypeinfo.nim new file mode 100644 index 000000000..1529c86e9 --- /dev/null +++ b/tests/cpp/ttypeinfo.nim @@ -0,0 +1,5 @@ +discard """ + cmd: "nim cpp $file" +""" + +import typeinfo diff --git a/tests/deprecated/tdeprecated.nim b/tests/deprecated/tdeprecated.nim index f41f0a72f..ed3d2733a 100644 --- a/tests/deprecated/tdeprecated.nim +++ b/tests/deprecated/tdeprecated.nim @@ -1,6 +1,5 @@ discard """ - line: 9 - errormsg: "'a' is deprecated [Deprecated]" + nimout: "'a' is deprecated [Deprecated]" """ var @@ -8,4 +7,3 @@ var a[8] = 1 - diff --git a/tests/destructor/tdestructor2.nim b/tests/destructor/tdestructor2.nim index 1bdf4993b..6f966d861 100644 --- a/tests/destructor/tdestructor2.nim +++ b/tests/destructor/tdestructor2.nim @@ -1,6 +1,6 @@ discard """ - line: 20 - errormsg: " usage of a type with a destructor in a non destructible context" + line: 23 + nimout: " usage of a type with a destructor in a non destructible context" """ {.experimental.} @@ -19,5 +19,9 @@ proc open: TMyObj = proc `$`(x: TMyObj): string = $x.y -echo open() +proc foo = + discard open() + +# XXX doesn't trigger this yet: +#echo open() diff --git a/tests/dll/client.nimrod.cfg b/tests/dll/client.nim.cfg index 0e044a829..0e044a829 100644 --- a/tests/dll/client.nimrod.cfg +++ b/tests/dll/client.nim.cfg diff --git a/tests/dll/server.nimrod.cfg b/tests/dll/server.nim.cfg index 02393ba8b..02393ba8b 100644 --- a/tests/dll/server.nimrod.cfg +++ b/tests/dll/server.nim.cfg diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim index 27f89f5fa..ea1ea7b21 100644 --- a/tests/effects/teffects1.nim +++ b/tests/effects/teffects1.nim @@ -1,5 +1,4 @@ discard """ - line: 2166 file: "system.nim" errormsg: "can raise an unlisted exception: ref IOError" """ diff --git a/tests/exception/tdefer1.nim b/tests/exception/tdefer1.nim new file mode 100644 index 000000000..61439530a --- /dev/null +++ b/tests/exception/tdefer1.nim @@ -0,0 +1,18 @@ +discard """ + output: '''hi +hi''' +""" + +# bug #1742 + +template test(): expr = + let a = 0 + defer: echo "hi" + a + +let i = test() + +import strutils +let x = try: parseInt("133a") + except: -1 + finally: echo "hi" diff --git a/tests/exprs/thighCString.nim b/tests/exprs/thighCString.nim new file mode 100644 index 000000000..543966df4 --- /dev/null +++ b/tests/exprs/thighCString.nim @@ -0,0 +1,6 @@ +discard """ + output: "5" +""" +let test = cstring("foobar") + +echo high(test) diff --git a/tests/fields/tfields_in_template.nim b/tests/fields/tfields_in_template.nim new file mode 100644 index 000000000..9352a7a51 --- /dev/null +++ b/tests/fields/tfields_in_template.nim @@ -0,0 +1,15 @@ +discard """ + output: '''n +n''' +""" + +# bug #1902 +# This works. +for name, value in (n: "v").fieldPairs: + echo name + +# This doesn't compile - "expression 'name' has no type (or is ambiguous)". +template wrapper: stmt = + for name, value in (n: "v").fieldPairs: + echo name +wrapper() diff --git a/tests/fields/tfields_with_break.nim b/tests/fields/tfields_with_break.nim new file mode 100644 index 000000000..1f2632692 --- /dev/null +++ b/tests/fields/tfields_with_break.nim @@ -0,0 +1,33 @@ +discard """ + output: '''(one: 1, two: 2, three: 3) +1 +2 +3 +(one: 4, two: 5, three: 6) +4 +(one: 7, two: 8, three: 9) +7 +8 +9''' +""" + +# bug #2134 +type + TestType = object + one: int + two: int + three: int + +var + ab = TestType(one:1, two:2, three:3) + ac = TestType(one:4, two:5, three:6) + ad = TestType(one:7, two:8, three:9) + tstSeq = [ab, ac, ad] + +for tstElement in mitems(tstSeq): + echo tstElement + for tstField in fields(tstElement): + #for tstField in [1,2,4,6]: + echo tstField + if tstField == 4: + break diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim index 6f2b8a1fe..54e74ac7b 100644 --- a/tests/gc/gcleak4.nim +++ b/tests/gc/gcleak4.nim @@ -38,12 +38,14 @@ proc newPlus(a, b: ref TExpr): ref TPlusExpr = result.b = b result.op2 = $getOccupiedMem() +const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 500_000 + for i in 0..100_000: var s: array[0..11, ref TExpr] for j in 0..high(s): s[j] = newPlus(newPlus(newLit(j), newLit(2)), newLit(4)) if eval(s[j]) != j+6: quit "error: wrong result" - if getOccupiedMem() > 500_000: quit("still a leak!") + if getOccupiedMem() > Limit: quit("still a leak!") echo "no leak: ", getOccupiedMem() diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim new file mode 100644 index 000000000..a16468c7e --- /dev/null +++ b/tests/gc/growobjcrash.nim @@ -0,0 +1,29 @@ +discard """ + output: "works" +""" + +import cgi, strtabs + +proc handleRequest(query: string): StringTableRef = + iterator foo(): StringTableRef {.closure.} = + var params = {:}.newStringTable() + for key, val in cgi.decodeData(query): + params[key] = val + yield params + + let x = foo + result = x() + +const Limit = when compileOption("gc", "markAndSweep"): 5*1024*1024 else: 700_000 + +proc main = + var counter = 0 + for i in 0 .. 100_000: + for k, v in handleRequest("nick=Elina2&type=activate"): + inc counter + if counter mod 100 == 0: + if getOccupiedMem() > Limit: + quit "but now a leak" + +main() +echo "works" diff --git a/tests/generics/t1056.nim b/tests/generics/t1056.nim index 73a24a76a..b1fe25894 100644 --- a/tests/generics/t1056.nim +++ b/tests/generics/t1056.nim @@ -1,6 +1,5 @@ discard """ output: '''TMatrix[3, 3, system.int] -3 3''' """ @@ -22,5 +21,5 @@ proc echoMat2(a: TMat2) = var m = TMatrix[3,3,int](data: [1,2,3,4,5,6,7,8,9]) echoMatrix m -echoMat2 m +#echoMat2 m diff --git a/tests/generics/twrong_field_caching.nim b/tests/generics/twrong_field_caching.nim new file mode 100644 index 000000000..595c58eb7 --- /dev/null +++ b/tests/generics/twrong_field_caching.nim @@ -0,0 +1,68 @@ +discard """ + output: '''a23: 2x3 +a32: 3x2 +transpose A +t32: 3x2 +transpose B +x23: 2x3 (2x3) +x32: 3x2 (3x2)''' +""" + +# bug #2125 +# Suppose we have the following type for a rectangular array: + +type + RectArray*[R, C: static[int], T] = distinct array[R * C, T] + +var a23: RectArray[2, 3, int] +var a32: RectArray[3, 2, int] + +echo "a23: ", a23.R, "x", a23.C +echo "a32: ", a32.R, "x", a32.C + +# Output: +# a23: 2x3 +# a32: 3x2 + +# Looking good. Let's add a proc: +proc transpose*[R, C, T](m: RectArray[R, C, T]): RectArray[C, R, T] = + echo "transpose A" + +var t32 = a23.transpose + +echo "t32: ", t32.R, "x", t32.C + +# Output: +# t32: 3x2 + + +# Everything is still OK. Now let's use the rectangular array inside another +# generic type: +type + Matrix*[R, C: static[int], T] = object + theArray*: RectArray[R, C, T] + +#var m23: Matrix[2, 3, int] +#var m32: Matrix[3, 2, int] + +#echo "m23: ", m23.R, "x", m23.C, " (", m23.theArray.R, "x", m23.theArray.C, ")" +#echo "m32: ", m32.R, "x", m32.C, " (", m32.theArray.R, "x", m32.theArray.C, ")" + +# Output: +# m23: 2x3 (2x3) +# m32: 3x2 (3x2) + + +# Everything is still as expected. Now let's add the following proc: +proc transpose*[R, C, T](m: Matrix[R, C, T]): Matrix[C, R, T] = + echo "transpose B" + +var x23: Matrix[2, 3, int] +var x32 = x23.transpose + +echo "x23: ", x23.R, "x", x23.C, " (", x23.theArray.R, "x", x23.theArray.C, ")" +echo "x32: ", x32.R, "x", x32.C, " (", x32.theArray.R, "x", x32.theArray.C, ")" + +# Output: +# x23: 2x3 (2x3) +# x32: 3x2 (3x2) <--- this is incorrect. R and C do not match! diff --git a/tests/generics/twrong_floatlit_type.nim b/tests/generics/twrong_floatlit_type.nim new file mode 100644 index 000000000..2db8b4353 --- /dev/null +++ b/tests/generics/twrong_floatlit_type.nim @@ -0,0 +1,118 @@ +discard """ + errormsg: "type mismatch" + line: 116 +""" + +# bug #2169 +import strutils, math + +type + Point2D*[S] = object + x*, y*: S + Matrix2x3*[S] = distinct array[6, S] ## Row major order + + Vector2D*[S] = object + x*, y*: S + +proc `[]`*[T](m: Matrix2x3[T], i: int): T = array[6, T](m)[i] + +template M11*[T](m: Matrix2x3[T]): T = m[0] +template M12*[T](m: Matrix2x3[T]): T = m[1] +template M13*[T](m: Matrix2x3[T]): T = m[2] +template M21*[T](m: Matrix2x3[T]): T = m[3] +template M22*[T](m: Matrix2x3[T]): T = m[4] +template M23*[T](m: Matrix2x3[T]): T = m[5] + +proc identity*[T](): Matrix2x3[T] = + Matrix2x3[T]([T(1.0), 0.0, 0.0, 0.0, 1.0, 0.0]) + +proc translation*[T](p: Point2D[T]): Matrix2x3[T] = + Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y]) + +proc translation*[T](p: Vector2D[T]): Matrix2x3[T] = + Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y]) + +proc scale*[T](v: Vector2D[T]): Matrix2x3[T] = + Matrix2x3[T]([v.x, T(0.0), T(0.0), T(0.0), v.y, T(0.0)]) + +proc rotation*[T](th: T): Matrix2x3[T] = + let + c = T(cos(th.float)) + s = T(sin(th.float)) + + Matrix2x3[T]([c, -s, T(0.0), s, c, T(0.0)]) + +proc `*`*[T](a, b: Matrix2x3[T]): Matrix2x3[T] = + # Here we pretend that row 3 is [0,0,0,1] without + # actually storing it in the matrix. + Matrix2x3[T]([a.M11*b.M11 + a.M12*b.M21, + a.M11*b.M12 + a.M12*b.M22, + a.M11*b.M13 + a.M12*b.M23 + a.M13, + + a.M21*b.M11 + a.M22*b.M21, + a.M21*b.M12 + a.M22*b.M22, + a.M21*b.M13 + a.M22*b.M23 + a.M23]) + +proc `*`*[T](a: Matrix2x3[T], p: Point2D[T]): Point2D[T] = + let + x = a.M11*p.x + a.M12*p.y + a.M13 + y = a.M21*p.x + a.M22*p.y + a.M23 + + Point2D[T](x: x, y: y) + +# making these so things like "line" that need a constructor don't stick out. +# 2x2 determinant: |a b| +# |c d| = ad - bc + +# String rendering +# +template ff[S](x: S): string = + formatFloat(float(x), ffDefault, 0) + +proc `$`*[S](p: Point2D[S]): string = + "P($1, $2)" % [ff(p.x), ff(p.y)] + +proc `$`*[S](p: Vector2D[S]): string = + "V($1, $2)" % [ff(p.x), ff(p.y)] + +proc `$`*[S](m: Matrix2x3[S]): string = + "M($1 $2 $3/$4 $5 $6)" % [ff(m.M11), ff(m.M12), ff(m.M13), + ff(m.M21), ff(m.M22), ff(m.M23)] + +# +# Vector operators. +proc `-`*[S](a: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: -a.x, y: -a.y) + +proc `+`*[S](a, b: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: a.x + b.x, y: a.y + b.y) + +proc `-`*[S](a, b: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: a.x - b.x, y: a.y - b.y) + +proc `*`*[S](v: Vector2D[S], sc: S): Vector2D[S] = + Vector2D[S](x: v.x*sc, y: v.y*sc) + +proc `*`*[S](sc: S, v: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: v.x*sc, y: v.y*sc) + +proc `/`*[S](v: Vector2D[S], sc: S): Vector2D[S] = + Vector2D[S](x: v.x/sc, y: v.y/sc) + +proc `/`*[S](sc: S; v: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: sc/v.x, y: sc/v.y) + +proc `/`*[S](a, b: Vector2D[S]): Vector2D[S] = + Vector2D[S](x: a.x/b.x, y: a.y/b.y) +#proc vec[S](x, y: S): Vector2D[S] +proc vec[S](x, y: S): Vector2D[S] = + Vector2D[S](x: x, y: y) + +if isMainModule: + # Comment out this let, and the program will fail to + # compile with a type mismatch, as expected. + + let s3 = scale(vec(4.0, 4.0)) + let barf = translation(Point2D[float32](x: 1, y: 1)) * rotation(float(0.7)) + + echo "Badness ", barf diff --git a/tests/global/tglobal.nim b/tests/global/tglobal.nim index 84c4510c1..d44a62afc 100644 --- a/tests/global/tglobal.nim +++ b/tests/global/tglobal.nim @@ -1,6 +1,6 @@ discard """ - file: "toop1.nim" output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second" + disabled: "true" """ import globalaux, globalaux2 diff --git a/tests/implicit/timplictderef.nim b/tests/implicit/timplictderef.nim index 99b0b645b..fcb647217 100644 --- a/tests/implicit/timplictderef.nim +++ b/tests/implicit/timplictderef.nim @@ -1,9 +1,10 @@ discard """ - output: "2" + output: '''2 +88''' """ type - TValue* {.pure, final.} = object of TObject + TValue* {.pure, final.} = object of RootObj a: int PValue = ref TValue PPValue = ptr PValue @@ -16,3 +17,19 @@ var sp: PPValue = addr x sp.a = 2 if sp.a == 2: echo 2 # with sp[].a the error is gone +# Test the new auto-deref a little + +{.experimental.} + +proc p(x: var int; y: int) = x += y + +block: + var x: ref int + new(x) + + x.p(44) + + var indirect = p + x.indirect(44) + + echo x[] diff --git a/tests/iter/tconcat.nim b/tests/iter/tconcat.nim new file mode 100644 index 000000000..477ac5e26 --- /dev/null +++ b/tests/iter/tconcat.nim @@ -0,0 +1,24 @@ +discard """ + output: '''1 +2 +3 +4 +20 +21 +22 +23''' +""" + +proc toIter*[T](s: Slice[T]): iterator: T = + iterator it: T {.closure.} = + for x in s.a..s.b: + yield x + return it + +iterator concat*[T](its: varargs[T, toIter]): auto = + for i in its: + for x in i(): + yield x + +for i in concat(1..4, 20..23): + echo i diff --git a/tests/macros/macro_bug.nim b/tests/macros/macro_bug.nim new file mode 100644 index 000000000..0d0fa76ac --- /dev/null +++ b/tests/macros/macro_bug.nim @@ -0,0 +1,17 @@ +import macros + +macro macro_bug*(s: stmt): stmt {.immediate.} = + s.expectKind({nnkProcDef, nnkMethodDef}) + + var params = s.params + + let genericParams = s[2] + result = newNimNode(nnkProcDef).add( + s.name, s[1], genericParams, params, pragma(s), newEmptyNode()) + + var body = body(s) + + # Fails here. + var call = newCall("macro_bug", s.params[1][0]) + body.insert(0, call) + result.add(body) diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim index f19aa2ddb..991668930 100644 --- a/tests/macros/tmacrotypes.nim +++ b/tests/macros/tmacrotypes.nim @@ -1,16 +1,16 @@ discard """ - disabled: true + nimout: '''void +int''' """ -import macros, typetraits +import macros -macro checkType(ex, expected: expr): stmt {.immediate.} = - var t = ex.typ - assert t.name == expected.strVal +macro checkType(ex: stmt; expected: expr): stmt = + var t = ex.getType() + echo t proc voidProc = echo "hello" -proc intProc(a, b): int = 10 +proc intProc(a: int, b: float): int = 10 checkType(voidProc(), "void") checkType(intProc(10, 20.0), "int") -checkType(noproc(10, 20.0), "Error Type") diff --git a/tests/macros/tnimrodnode_for_runtime.nim b/tests/macros/tnimnode_for_runtime.nim index e73c8430f..69c7aedd2 100644 --- a/tests/macros/tnimrodnode_for_runtime.nim +++ b/tests/macros/tnimnode_for_runtime.nim @@ -1,6 +1,5 @@ discard """ output: "bla" - disabled: true """ import macros diff --git a/tests/macros/tsame_name_497.nim b/tests/macros/tsame_name_497.nim new file mode 100644 index 000000000..ed5d5c6d8 --- /dev/null +++ b/tests/macros/tsame_name_497.nim @@ -0,0 +1,9 @@ +discard """ + disabled: true +""" + +import macro_bug + +type TObj = object + +proc f(o: TObj) {.macro_bug.} = discard diff --git a/tests/macros/typesapi.nim b/tests/macros/typesapi.nim new file mode 100644 index 000000000..670b39c9e --- /dev/null +++ b/tests/macros/typesapi.nim @@ -0,0 +1,17 @@ +discard """ + nimout: '''proc (x: int): string => typeDesc[proc[string, int]] +proc (x: int): void => typeDesc[proc[void, int]] +proc (x: int) => typeDesc[proc[void, int]]''' +""" + +#2211 + +import macros + +macro showType(t:stmt): stmt = + let ty = t.getType + echo t.repr, " => ", ty.repr + +showType(proc(x:int): string) +showType(proc(x:int): void) +showType(proc(x:int)) diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index af671cd85..a507a08e4 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -302,7 +302,7 @@ template build_specification_lookup(): ## Returns the table used to keep pointers to all of the specifications. var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification] result = initOrderedTable[string, ptr Tparameter_specification]( - nextPowerOfTwo(expected.len)) + tables.rightSize(expected.len)) for i in 0..expected.len-1: for param_to_detect in expected[i].names: if result.hasKey(param_to_detect): diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim index d079a2e72..493a2106c 100644 --- a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim +++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim @@ -74,7 +74,7 @@ type contacts*: PContact stamp*: TTimestamp handler*: PCollisionHandler - swappedColl*: bool32 + swappedColl*: Bool32 state*: TArbiterState PCollisionHandler* = ptr TCollisionHandler TCollisionHandler*{.pf.} = object @@ -108,7 +108,7 @@ type #/ Collision begin event function callback type. #/ Returning false from a begin callback causes the collision to be ignored until #/ the the separate callback is called when the objects stop colliding. - TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): Bool{. + TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): bool{. cdecl.} #/ Collision pre-solve event function callback type. #/ Returning false from a pre-step callback causes the collision to be ignored until the next step. @@ -142,14 +142,14 @@ type PSpatialIndex = ptr TSpatialIndex TSpatialIndex{.pf.} = object klass: PSpatialIndexClass - bbfunc: TSpatialIndexBBFunc + bbfun: TSpatialIndexBBFunc staticIndex: PSpatialIndex dynamicIndex: PSpatialIndex TSpatialIndexDestroyImpl* = proc (index: PSpatialIndex){.cdecl.} TSpatialIndexCountImpl* = proc (index: PSpatialIndex): cint{.cdecl.} TSpatialIndexEachImpl* = proc (index: PSpatialIndex; - func: TSpatialIndexIteratorFunc; data: pointer){. + fun: TSpatialIndexIteratorFunc; data: pointer){. cdecl.} TSpatialIndexContainsImpl* = proc (index: PSpatialIndex; obj: pointer; hashid: THashValue): Bool32 {.cdecl.} @@ -161,15 +161,15 @@ type TSpatialIndexReindexObjectImpl* = proc (index: PSpatialIndex; obj: pointer; hashid: THashValue){.cdecl.} TSpatialIndexReindexQueryImpl* = proc (index: PSpatialIndex; - func: TSpatialIndexQueryFunc; data: pointer){.cdecl.} + fun: TSpatialIndexQueryFunc; data: pointer){.cdecl.} TSpatialIndexPointQueryImpl* = proc (index: PSpatialIndex; point: TVector; - func: TSpatialIndexQueryFunc; + fun: TSpatialIndexQueryFunc; data: pointer){.cdecl.} TSpatialIndexSegmentQueryImpl* = proc (index: PSpatialIndex; obj: pointer; - a: TVector; b: TVector; t_exit: CpFloat; func: TSpatialIndexSegmentQueryFunc; + a: TVector; b: TVector; t_exit: CpFloat; fun: TSpatialIndexSegmentQueryFunc; data: pointer){.cdecl.} TSpatialIndexQueryImpl* = proc (index: PSpatialIndex; obj: pointer; - bb: TBB; func: TSpatialIndexQueryFunc; + bb: TBB; fun: TSpatialIndexQueryFunc; data: pointer){.cdecl.} PSpatialIndexClass* = ptr TSpatialIndexClass TSpatialIndexClass*{.pf.} = object @@ -279,14 +279,14 @@ type PSegmentQueryInfo* = ptr TSegmentQueryInfo #/ Segment query info struct. TSegmentQueryInfo*{.pf.} = object - shape*: PShape #/ The shape that was hit, NULL if no collision occured. + shape*: PShape #/ The shape that was hit, NULL if no collision occurred. t*: CpFloat #/ The normalized distance along the query segment in the range [0, 1]. n*: TVector #/ The normal of the surface hit. TShapeType*{.size: sizeof(cint).} = enum CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, CP_POLY_SHAPE, CP_NUM_SHAPES TShapeCacheDataImpl* = proc (shape: PShape; p: TVector; rot: TVector): TBB{.cdecl.} TShapeDestroyImpl* = proc (shape: PShape){.cdecl.} - TShapePointQueryImpl* = proc (shape: PShape; p: TVector): bool32 {.cdecl.} + TShapePointQueryImpl* = proc (shape: PShape; p: TVector): Bool32 {.cdecl.} TShapeSegmentQueryImpl* = proc (shape: PShape; a: TVector; b: TVector; info: PSegmentQueryInfo){.cdecl.} PShapeClass* = ptr TShapeClass @@ -427,7 +427,7 @@ defGetter(PSpace, CpFloat, currDt, CurrentTimeStep) #/ returns true from inside a callback and objects cannot be added/removed. -proc isLocked*(space: PSpace): Bool{.inline.} = +proc isLocked*(space: PSpace): bool{.inline.} = result = space.locked.bool #/ Set a default collision handler for this space. @@ -478,24 +478,24 @@ proc removeBody*(space: PSpace; body: PBody){. proc RemoveConstraint*(space: PSpace; constraint: PConstraint){. cdecl, importc: "cpSpaceRemoveConstraint", dynlib: Lib.} #/ Test if a collision shape has been added to the space. -proc containsShape*(space: PSpace; shape: PShape): Bool{. +proc containsShape*(space: PSpace; shape: PShape): bool{. cdecl, importc: "cpSpaceContainsShape", dynlib: Lib.} #/ Test if a rigid body has been added to the space. -proc containsBody*(space: PSpace; body: PBody): Bool{. +proc containsBody*(space: PSpace; body: PBody): bool{. cdecl, importc: "cpSpaceContainsBody", dynlib: Lib.} #/ Test if a constraint has been added to the space. -proc containsConstraint*(space: PSpace; constraint: PConstraint): Bool{. +proc containsConstraint*(space: PSpace; constraint: PConstraint): bool{. cdecl, importc: "cpSpaceContainsConstraint", dynlib: Lib.} #/ Schedule a post-step callback to be called when cpSpaceStep() finishes. #/ @c obj is used a key, you can only register one callback per unique value for @c obj -proc addPostStepCallback*(space: PSpace; func: TPostStepFunc; +proc addPostStepCallback*(space: PSpace; fun: TPostStepFunc; obj: pointer; data: pointer){. cdecl, importc: "cpSpaceAddPostStepCallback", dynlib: Lib.} #/ Query the space at a point and call @c func for each shape found. proc pointQuery*(space: PSpace; point: TVector; layers: TLayers; - group: TGroup; func: TSpacePointQueryFunc; data: pointer){. + group: TGroup; fun: TSpacePointQueryFunc; data: pointer){. cdecl, importc: "cpSpacePointQuery", dynlib: Lib.} #/ Query the space at a point and return the first shape found. Returns NULL if no shapes were found. @@ -506,7 +506,7 @@ proc pointQueryFirst*(space: PSpace; point: TVector; layers: TLayers; #/ Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected. proc segmentQuery*(space: PSpace; start: TVector; to: TVector; layers: TLayers; group: TGroup; - func: TSpaceSegmentQueryFunc; data: pointer){. + fun: TSpaceSegmentQueryFunc; data: pointer){. cdecl, importc: "cpSpaceSegmentQuery", dynlib: Lib.} #/ Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit. proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector; @@ -517,26 +517,26 @@ proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector; #/ Perform a fast rectangle query on the space calling @c func for each shape found. #/ Only the shape's bounding boxes are checked for overlap, not their full shape. proc BBQuery*(space: PSpace; bb: TBB; layers: TLayers; group: TGroup; - func: TSpaceBBQueryFunc; data: pointer){. + fun: TSpaceBBQueryFunc; data: pointer){. cdecl, importc: "cpSpaceBBQuery", dynlib: Lib.} #/ Query a space for any shapes overlapping the given shape and call @c func for each shape found. -proc shapeQuery*(space: PSpace; shape: PShape; func: TSpaceShapeQueryFunc; data: pointer): Bool {. +proc shapeQuery*(space: PSpace; shape: PShape; fun: TSpaceShapeQueryFunc; data: pointer): bool {. cdecl, importc: "cpSpaceShapeQuery", dynlib: Lib.} #/ Call cpBodyActivate() for any shape that is overlaps the given shape. proc activateShapesTouchingShape*(space: PSpace; shape: PShape){. cdecl, importc: "cpSpaceActivateShapesTouchingShape", dynlib: Lib.} #/ Call @c func for each body in the space. -proc eachBody*(space: PSpace; func: TSpaceBodyIteratorFunc; data: pointer){. +proc eachBody*(space: PSpace; fun: TSpaceBodyIteratorFunc; data: pointer){. cdecl, importc: "cpSpaceEachBody", dynlib: Lib.} #/ Call @c func for each shape in the space. -proc eachShape*(space: PSpace; func: TSpaceShapeIteratorFunc; +proc eachShape*(space: PSpace; fun: TSpaceShapeIteratorFunc; data: pointer){. cdecl, importc: "cpSpaceEachShape", dynlib: Lib.} #/ Call @c func for each shape in the space. -proc eachConstraint*(space: PSpace; func: TSpaceConstraintIteratorFunc; +proc eachConstraint*(space: PSpace; fun: TSpaceConstraintIteratorFunc; data: pointer){. cdecl, importc: "cpSpaceEachConstraint", dynlib: Lib.} #/ Update the collision detection info for the static shapes in the space. @@ -674,7 +674,7 @@ proc dist*(v1, v2: TVector): CpFloat {.inline.} = proc distsq*(v1, v2: TVector): CpFloat {.inline.} = result = (v1 - v2).lenSq #vlengthsq(vsub(v1, v2)) #/ Returns true if the distance between v1 and v2 is less than dist. -proc near*(v1, v2: TVector; dist: CpFloat): Bool{.inline.} = +proc near*(v1, v2: TVector; dist: CpFloat): bool{.inline.} = result = v1.distSq(v2) < dist * dist @@ -706,13 +706,13 @@ proc Sleep*(body: PBody){.importc: "cpBodySleep", dynlib: Lib.} proc SleepWithGroup*(body: PBody; group: PBody){. importc: "cpBodySleepWithGroup", dynlib: Lib.} #/ Returns true if the body is sleeping. -proc isSleeping*(body: PBody): Bool {.inline.} = +proc isSleeping*(body: PBody): bool {.inline.} = return body.node.root != nil #/ Returns true if the body is static. proc isStatic*(body: PBody): bool {.inline.} = return body.node.idleTime == CpInfinity #/ Returns true if the body has not been added to a space. -proc isRogue*(body: PBody): Bool {.inline.} = +proc isRogue*(body: PBody): bool {.inline.} = return body.space == nil # #define CP_DefineBodyStructGetter(type, member, name) \ @@ -808,15 +808,15 @@ proc kineticEnergy*(body: PBOdy): CpFloat = result = (body.v.dot(body.v) * body.m) + (body.w * body.w * body.i) #/ Call @c func once for each shape attached to @c body and added to the space. -proc eachShape*(body: PBody; func: TBodyShapeIteratorFunc; +proc eachShape*(body: PBody; fun: TBodyShapeIteratorFunc; data: pointer){. cdecl, importc: "cpBodyEachShape", dynlib: Lib.} #/ Call @c func once for each constraint attached to @c body and added to the space. -proc eachConstraint*(body: PBody; func: TBodyConstraintIteratorFunc; +proc eachConstraint*(body: PBody; fun: TBodyConstraintIteratorFunc; data: pointer) {. cdecl, importc: "cpBodyEachConstraint", dynlib: Lib.} #/ Call @c func once for each arbiter that is currently active on the body. -proc eachArbiter*(body: PBody; func: TBodyArbiterIteratorFunc; +proc eachArbiter*(body: PBody; fun: TBodyArbiterIteratorFunc; data: pointer){. cdecl, importc: "cpBodyEachArbiter", dynlib: Lib.} #/ Allocate a spatial hash. @@ -824,10 +824,10 @@ proc SpaceHashAlloc*(): PSpaceHash{. cdecl, importc: "cpSpaceHashAlloc", dynlib: Lib.} #/ Initialize a spatial hash. proc SpaceHashInit*(hash: PSpaceHash; celldim: CpFloat; numcells: cint; - bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. + bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. cdecl, importc: "cpSpaceHashInit", dynlib: Lib.} #/ Allocate and initialize a spatial hash. -proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfunc: TSpatialIndexBBFunc; +proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. cdecl, importc: "cpSpaceHashNew", dynlib: Lib.} #/ Change the cell dimensions and table size of the spatial hash to tune it. @@ -842,18 +842,18 @@ proc SpaceHashResize*(hash: PSpaceHash; celldim: CpFloat; numcells: cint){. #/ Allocate a bounding box tree. proc BBTreeAlloc*(): PBBTree{.cdecl, importc: "cpBBTreeAlloc", dynlib: Lib.} #/ Initialize a bounding box tree. -proc BBTreeInit*(tree: PBBTree; bbfunc: TSpatialIndexBBFunc; +proc BBTreeInit*(tree: PBBTree; bbfun: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, importc: "cpBBTreeInit", dynlib: Lib.} #/ Allocate and initialize a bounding box tree. -proc BBTreeNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. +proc BBTreeNew*(bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{. cdecl, importc: "cpBBTreeNew", dynlib: Lib.} #/ Perform a static top down optimization of the tree. proc BBTreeOptimize*(index: PSpatialIndex){. cdecl, importc: "cpBBTreeOptimize", dynlib: Lib.} #/ Set the velocity function for the bounding box tree to enable temporal coherence. -proc BBTreeSetVelocityFunc*(index: PSpatialIndex; func: TBBTreeVelocityFunc){. +proc BBTreeSetVelocityFunc*(index: PSpatialIndex; fun: TBBTreeVelocityFunc){. cdecl, importc: "cpBBTreeSetVelocityFunc", dynlib: Lib.} #MARK: Single Axis Sweep @@ -864,12 +864,12 @@ proc Sweep1DAlloc*(): ptr TSweep1D{.cdecl, importc: "cpSweep1DAlloc", dynlib: Lib.} #/ Initialize a 1D sort and sweep broadphase. -proc Sweep1DInit*(sweep: ptr TSweep1D; bbfunc: TSpatialIndexBBFunc; +proc Sweep1DInit*(sweep: ptr TSweep1D; bbfun: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, importc: "cpSweep1DInit", dynlib: Lib.} #/ Allocate and initialize a 1D sort and sweep broadphase. -proc Sweep1DNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{. +proc Sweep1DNew*(bbfun: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{. cdecl, importc: "cpSweep1DNew", dynlib: Lib.} @@ -1359,7 +1359,7 @@ defCProp(SlideJoint, TVector, anchr2, Anchr2) defCProp(SlideJoint, CpFloat, min, Min) defCProp(SlideJoint, CpFloat, max, Max) -proc pivotJointGetClass*(): PConstraintClass {. +proc PivotJointGetClass*(): PConstraintClass {. cdecl, importc: "cpPivotJointGetClass", dynlib: Lib.} #/ Allocate a pivot joint diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim index df1b743ee..93857207a 100644 --- a/tests/manyloc/keineschweine/dependencies/enet/enet.nim +++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim @@ -20,7 +20,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. const Lib = "libenet.so.1(|.0.3)" -{.deadCodeElim: ON.} +{.deadCodeElim: on.} const ENET_VERSION_MAJOR* = 1 ENET_VERSION_MINOR* = 3 diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim index 44d00db53..4f2fb1ea3 100644 --- a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim +++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim @@ -9,15 +9,6 @@ template defPacketImports*(): stmt {.immediate, dirty.} = import macros, macro_dsl, estreams from strutils import format -proc `$`*[T](x: seq[T]): string = - result = "[seq len=" - result.add($x.len) - result.add ':' - for i in 0.. <len(x): - result.add " " - result.add($x[i]) - result.add ']' - macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = result = newNimNode(nnkStmtList) let @@ -293,4 +284,4 @@ when isMainModule: for itm in test.x: echo(itm) test.pack(s) - echo(repr(s.data)) \ No newline at end of file + echo(repr(s.data)) diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim index 0d09d40e3..1071ec767 100644 --- a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim @@ -221,10 +221,10 @@ type TTransform* {.pf.} = object matrix*: array[0..8, cfloat] TColor* {.pf.} = object - r*: Uint8 - g*: Uint8 - b*: Uint8 - a*: Uint8 + r*: uint8 + g*: uint8 + b*: uint8 + a*: uint8 PFloatRect* = ptr TFloatRect TFloatRect*{.pf.} = object left*: cfloat @@ -306,7 +306,7 @@ proc close*(window: PRenderWindow) {. proc isOpen*(window: PRenderWindow): bool {. cdecl, importc: "sfRenderWindow_isOpen", dynlib: LibG.} -#void sfRenderWindow_setIcon(sfRenderWindow* renderWindow, unsigned int width, unsigned int height, const sfUint8* pixels); +#void sfRenderWindow_setIcon(sfRenderWindow* renderWindow, unsigned int width, unsigned int height, const sfuint8* pixels); #proc setIcon*(window: PRenderWindow, width, height: cint, pixels: seq[uint8]) {. # cdecl, importc: "sfRenderWindow_setIcon", dynlib: LibG.} @@ -395,7 +395,7 @@ proc capture*(window: PRenderWindow): PImage {. cdecl, importc: "sfRenderWindow_capture", dynlib: LibG.} #Construct a new render texture -proc newRenderTexture*(width, height: cint; depthBuffer: Bool): PRenderTexture {. +proc newRenderTexture*(width, height: cint; depthBuffer: bool): PRenderTexture {. cdecl, importc: "sfRenderTexture_create", dynlib: LibG.} #Destroy an existing render texture proc destroy*(renderTexture: PRenderTexture){. @@ -522,9 +522,9 @@ proc copy*(font: PFont): PFont {. cdecl, importc: "sfFont_copy", dynlib: LibG.} proc destroy*(font: PFont) {. cdecl, importc: "sfFont_destroy", dynlib: LibG.} -proc getGlyph*(font: PFont, codePoint: Uint32, characterSize: cint, bold: bool): TGlyph{. +proc getGlyph*(font: PFont, codePoint: uint32, characterSize: cint, bold: bool): TGlyph{. cdecl, importc: "sfFont_getGlyph", dynlib: LibG.} -proc getKerning*(font: PFont, first: Uint32, second: Uint32, characterSize: cint): cint {. +proc getKerning*(font: PFont, first: uint32, second: uint32, characterSize: cint): cint {. cdecl, importc: "sfFont_getKerning", dynlib: LibG.} proc getLineSpacing*(font: PFont, characterSize: cint): cint {. cdecl, importc: "sfFont_getLineSpacing", dynlib: LibG.} @@ -882,7 +882,7 @@ proc getInverseTransform*(text: PText): TTransform {. cdecl, importc: "sfText_getInverseTransform", dynlib: LibG.} proc setString*(text: PText, string: cstring) {. cdecl, importc: "sfText_setString", dynlib: LibG.} -proc setUnicodeString*(text: PText, string: ptr Uint32) {. +proc setUnicodeString*(text: PText, string: ptr uint32) {. cdecl, importc: "sfText_setUnicodeString", dynlib: LibG.} proc setFont*(text: PText, font: PFont) {. cdecl, importc: "sfText_setFont", dynlib: LibG.} @@ -894,13 +894,13 @@ proc setColor*(text: PText, color: TColor) {. cdecl, importc: "sfText_setColor", dynlib: LibG.} proc getString*(text: PText): cstring {. cdecl, importc: "sfText_getString", dynlib: LibG.} -proc getUnicodeString*(text: PText): ptr Uint32 {.cdecl, +proc getUnicodeString*(text: PText): ptr uint32 {.cdecl, importc: "sfText_getUnicodeString", dynlib: LibG.} proc getFont*(text: PText): PFont {. cdecl, importc: "sfText_getFont", dynlib: LibG.} proc getCharacterSize*(text: PText): cint {. cdecl, importc: "sfText_getCharacterSize", dynlib: LibG.} -proc getStyle*(text: PText): Uint32 {. +proc getStyle*(text: PText): uint32 {. cdecl, importc: "sfText_getStyle", dynlib: LibG.} proc getColor*(text: PText): TColor {. cdecl, importc: "sfText_getColor", dynlib: LibG.} diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim index 3cfd33c02..5aa017ac4 100644 --- a/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim +++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim @@ -284,7 +284,7 @@ proc newSoundBuffer*(stream: PInputStream): PSoundBuffer{. #/ \brief Create a new sound buffer and load it from an array of samples in memory #/ #/ The assumed format of the audio samples is 16 bits signed integer -#/ (sfInt16). +#/ (sfint16). #/ #/ \param samples Pointer to the array of samples in memory #/ \param sampleCount Number of samples in the array @@ -334,7 +334,7 @@ proc saveToFile*(soundBuffer: PSoundBuffer; filename: cstring): bool {. #/ \brief Get the array of audio samples stored in a sound buffer #/ #/ The format of the returned samples is 16 bits signed integer -#/ (sfInt16). The total number of samples in this array +#/ (sfint16). The total number of samples in this array #/ is given by the sfSoundBuffer_getSampleCount function. #/ #/ \param soundBuffer Sound buffer object @@ -342,7 +342,7 @@ proc saveToFile*(soundBuffer: PSoundBuffer; filename: cstring): bool {. #/ \return Read-only pointer to the array of sound samples #/ #////////////////////////////////////////////////////////// -proc sfSoundBuffer_getSamples*(soundBuffer: PSoundBuffer): ptr Int16{. +proc sfSoundBuffer_getSamples*(soundBuffer: PSoundBuffer): ptr int16{. cdecl, importc: "sfSoundBuffer_getSamples", dynlib: Lib.} #////////////////////////////////////////////////////////// #/ \brief Get the number of samples stored in a sound buffer diff --git a/tests/manyloc/keineschweine/enet_server/enet_client.nim b/tests/manyloc/keineschweine/enet_server/enet_client.nim index 0c903a733..5ebbdb88b 100644 --- a/tests/manyloc/keineschweine/enet_server/enet_client.nim +++ b/tests/manyloc/keineschweine/enet_server/enet_client.nim @@ -105,6 +105,7 @@ proc tryLogin*(b: PButton) = passwd = u_passwd.getText()) dirServer.send HLogin, login proc tryTransition*(b: PButton) = + discard #zone.writePkt HZoneJoinReq, myCreds proc tryConnect*(b: PButton) = if not dirServer.connected: diff --git a/tests/manyloc/keineschweine/enet_server/nimrod.cfg b/tests/manyloc/keineschweine/enet_server/nim.cfg index 72ef47ee0..72ef47ee0 100644 --- a/tests/manyloc/keineschweine/enet_server/nimrod.cfg +++ b/tests/manyloc/keineschweine/enet_server/nim.cfg diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim index e868b96a5..0a5dc1efc 100644 --- a/tests/manyloc/keineschweine/keineschweine.nim +++ b/tests/manyloc/keineschweine/keineschweine.nim @@ -143,7 +143,7 @@ proc mouseToSpace*(): TVector = proc explode*(b: PLiveBullet) ## TCollisionBeginFunc proc collisionBulletPlayer(arb: PArbiter; space: PSpace; - data: pointer): Bool{.cdecl.} = + data: pointer): bool{.cdecl.} = var bullet = cast[PLiveBullet](arb.a.data) target = cast[PVehicle](arb.b.data) @@ -152,7 +152,7 @@ proc collisionBulletPlayer(arb: PArbiter; space: PSpace; proc angularDampingSim(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} = body.w -= (body.w * 0.98 * dt) - body.updateVelocity(gravity, damping, dt) + body.UpdateVelocity(gravity, damping, dt) proc initLevel() = loadAllAssets() @@ -227,7 +227,7 @@ proc explode*(b: PLiveBullet) = playSound(b.record.explosion.sound, b.body.getPos()) proc bulletUpdate(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} = - body.updateVelocity(gravity, damping, dt) + body.UpdateVelocity(gravity, damping, dt) template getPhysical() {.immediate.} = result.body = space.addBody(newBody( @@ -237,7 +237,7 @@ template getPhysical() {.immediate.} = chipmunk.newCircleShape( result.body, record.physics.radius, - vectorZero)) + VectorZero)) proc newBullet*(record: PBulletRecord; fromPlayer: PPlayer): PLiveBullet = new(result, free) @@ -480,7 +480,7 @@ when defined(DebugKeys): echo(repr(activeVehicle.record)) elif keyPressed(KeyH): activeVehicle.body.setPos(vector(100.0, 100.0)) - activeVehicle.body.setVel(vectorZero) + activeVehicle.body.setVel(VectorZero) elif keyPressed(KeyComma): activeVehicle.body.setPos mouseToSpace()) ingameClient.registerHandler(KeyY, down, proc() = @@ -507,7 +507,7 @@ when defined(DebugKeys): return let body = shape.getBody() mouseJoint = space.addConstraint( - newPivotJoint(mouseBody, body, vectorZero, body.world2local(point))) + newPivotJoint(mouseBody, body, VectorZero, body.world2local(point))) mouseJoint.maxForce = 50000.0 mouseJoint.errorBias = pow(1.0 - 0.15, 60)) @@ -539,15 +539,15 @@ proc mainUpdate(dt: float) = elif not activeVehicle.isNil: if keyPressed(KeyUp): activeVehicle.accel(dt) - elif keyPressed(keyDown): + elif keyPressed(KeyDown): activeVehicle.reverse(dt) if keyPressed(KeyRight): activeVehicle.turn_right(dt) elif keyPressed(KeyLeft): activeVehicle.turn_left(dt) - if keyPressed(keyz): + if keyPressed(Keyz): activeVehicle.strafe_left(dt) - elif keyPressed(keyx): + elif keyPressed(Keyx): activeVehicle.strafe_right(dt) if keyPressed(KeyLControl): localPlayer.useItem 0 @@ -557,7 +557,7 @@ proc mainUpdate(dt: float) = localPlayer.useItem 2 if keyPressed(KeyW): localPlayer.useItem 3 - if Keypressed(keyA): + if keyPressed(KeyA): localPlayer.useItem 4 if keyPressed(sfml.KeyS): localPlayer.useItem 5 @@ -666,7 +666,7 @@ when isMainModule: import parseopt localPlayer = newPlayer() - LobbyInit() + lobbyInit() videoMode = getClientSettings().resolution window = newRenderWindow(videoMode, "sup", sfDefaultStyle) @@ -683,7 +683,7 @@ when isMainModule: mouseSprite.setOutlineThickness 1.4 mouseSprite.setOrigin vec2f(14, 14) - LobbyReady() + lobbyReady() playBtn = specGui.newButton( "Unspec - F12", position = vec2f(680.0, 8.0), onClick = proc(b: PButton) = toggleSpec()) diff --git a/tests/manyloc/keineschweine/lib/game_objects.nim b/tests/manyloc/keineschweine/lib/game_objects.nim index 37019ebcb..277ffb6cb 100644 --- a/tests/manyloc/keineschweine/lib/game_objects.nim +++ b/tests/manyloc/keineschweine/lib/game_objects.nim @@ -26,7 +26,7 @@ proc newObject*(record: PObjectRecord): PGameObject = when false: result.sprite = record.anim.spriteSheet.sprite.copy() result.body = newBody(result.record.physics.mass, 10.0) - result.shape = chipmunk.newCircleShape(result.body, result.record.physics.radius, vectorZero) + result.shape = chipmunk.newCircleShape(result.body, result.record.physics.radius, VectorZero) result.body.setPos(vector(100, 100)) proc newObject*(name: string): PGameObject = result = newObject(fetchObj(name)) diff --git a/tests/manyloc/keineschweine/lib/gl.nim b/tests/manyloc/keineschweine/lib/gl.nim index 9387b5bc9..c577f3404 100644 --- a/tests/manyloc/keineschweine/lib/gl.nim +++ b/tests/manyloc/keineschweine/lib/gl.nim @@ -38,7 +38,7 @@ type PGLclampf* = ptr TGLclampf PGLdouble* = ptr TGLdouble PGLclampd* = ptr TGLclampd - PGLvoid* = Pointer + PGLvoid* = pointer PPGLvoid* = ptr PGLvoid TGLenum* = cint TGLboolean* = bool @@ -983,7 +983,7 @@ const # Version GL_TEXTURE_COMPONENTS* = GL_TEXTURE_INTERNAL_FORMAT proc glAccum*(op: TGLenum, value: TGLfloat){.dynlib: dllname, importc: "glAccum".} -proc glAlphaFunc*(func: TGLenum, theref: TGLclampf){.dynlib: dllname, +proc glAlphaFunc*(fun: TGLenum, theref: TGLclampf){.dynlib: dllname, importc: "glAlphaFunc".} proc glAreTexturesResident*(n: TGLsizei, textures: PGLuint, residences: PGLboolean): TGLboolean{. @@ -998,7 +998,7 @@ proc glBitmap*(width, height: TGLsizei, xorig, yorig: TGLfloat, proc glBlendFunc*(sfactor, dfactor: TGLenum){.dynlib: dllname, importc: "glBlendFunc".} proc glCallList*(list: TGLuint){.dynlib: dllname, importc: "glCallList".} -proc glCallLists*(n: TGLsizei, atype: TGLenum, lists: Pointer){.dynlib: dllname, +proc glCallLists*(n: TGLsizei, atype: TGLenum, lists: pointer){.dynlib: dllname, importc: "glCallLists".} proc glClear*(mask: TGLbitfield){.dynlib: dllname, importc: "glClear".} proc glClearAccum*(red, green, blue, alpha: TGLfloat){.dynlib: dllname, @@ -1062,7 +1062,7 @@ proc glColorMask*(red, green, blue, alpha: TGLboolean){.dynlib: dllname, proc glColorMaterial*(face, mode: TGLenum){.dynlib: dllname, importc: "glColorMaterial".} proc glColorPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei, - pointer: Pointer){.dynlib: dllname, + p: pointer){.dynlib: dllname, importc: "glColorPointer".} proc glCopyPixels*(x, y: TGLint, width, height: TGLsizei, atype: TGLenum){. dynlib: dllname, importc: "glCopyPixels".} @@ -1084,7 +1084,7 @@ proc glDeleteLists*(list: TGLuint, range: TGLsizei){.dynlib: dllname, importc: "glDeleteLists".} proc glDeleteTextures*(n: TGLsizei, textures: PGLuint){.dynlib: dllname, importc: "glDeleteTextures".} -proc glDepthFunc*(func: TGLenum){.dynlib: dllname, importc: "glDepthFunc".} +proc glDepthFunc*(fun: TGLenum){.dynlib: dllname, importc: "glDepthFunc".} proc glDepthMask*(flag: TGLboolean){.dynlib: dllname, importc: "glDepthMask".} proc glDepthRange*(zNear, zFar: TGLclampd){.dynlib: dllname, importc: "glDepthRange".} @@ -1095,12 +1095,12 @@ proc glDrawArrays*(mode: TGLenum, first: TGLint, count: TGLsizei){. dynlib: dllname, importc: "glDrawArrays".} proc glDrawBuffer*(mode: TGLenum){.dynlib: dllname, importc: "glDrawBuffer".} proc glDrawElements*(mode: TGLenum, count: TGLsizei, atype: TGLenum, - indices: Pointer){.dynlib: dllname, + indices: pointer){.dynlib: dllname, importc: "glDrawElements".} proc glDrawPixels*(width, height: TGLsizei, format, atype: TGLenum, - pixels: Pointer){.dynlib: dllname, importc: "glDrawPixels".} + pixels: pointer){.dynlib: dllname, importc: "glDrawPixels".} proc glEdgeFlag*(flag: TGLboolean){.dynlib: dllname, importc: "glEdgeFlag".} -proc glEdgeFlagPointer*(stride: TGLsizei, pointer: Pointer){.dynlib: dllname, +proc glEdgeFlagPointer*(stride: TGLsizei, p: pointer){.dynlib: dllname, importc: "glEdgeFlagPointer".} proc glEdgeFlagv*(flag: PGLboolean){.dynlib: dllname, importc: "glEdgeFlagv".} proc glEnable*(cap: TGLenum){.dynlib: dllname, importc: "glEnable".} @@ -1171,7 +1171,7 @@ proc glGetPixelMapuiv*(map: TGLenum, values: PGLuint){.dynlib: dllname, importc: "glGetPixelMapuiv".} proc glGetPixelMapusv*(map: TGLenum, values: PGLushort){.dynlib: dllname, importc: "glGetPixelMapusv".} -proc glGetPointerv*(pname: TGLenum, params: Pointer){.dynlib: dllname, +proc glGetPointerv*(pname: TGLenum, params: pointer){.dynlib: dllname, importc: "glGetPointerv".} proc glGetPolygonStipple*(mask: PGLubyte){.dynlib: dllname, importc: "glGetPolygonStipple".} @@ -1188,10 +1188,10 @@ proc glGetTexGenfv*(coord, pname: TGLenum, params: PGLfloat){.dynlib: dllname, proc glGetTexGeniv*(coord, pname: TGLenum, params: PGLint){.dynlib: dllname, importc: "glGetTexGeniv".} proc glGetTexImage*(target: TGLenum, level: TGLint, format: TGLenum, - atype: TGLenum, pixels: Pointer){.dynlib: dllname, + atype: TGLenum, pixels: pointer){.dynlib: dllname, importc: "glGetTexImage".} proc glGetTexLevelParameterfv*(target: TGLenum, level: TGLint, pname: TGLenum, - params: Pointer){.dynlib: dllname, + params: pointer){.dynlib: dllname, importc: "glGetTexLevelParameterfv".} proc glGetTexLevelParameteriv*(target: TGLenum, level: TGLint, pname: TGLenum, params: PGLint){.dynlib: dllname, @@ -1202,7 +1202,7 @@ proc glGetTexParameteriv*(target, pname: TGLenum, params: PGLint){. dynlib: dllname, importc: "glGetTexParameteriv".} proc glHint*(target, mode: TGLenum){.dynlib: dllname, importc: "glHint".} proc glIndexMask*(mask: TGLuint){.dynlib: dllname, importc: "glIndexMask".} -proc glIndexPointer*(atype: TGLenum, stride: TGLsizei, pointer: Pointer){. +proc glIndexPointer*(atype: TGLenum, stride: TGLsizei, p: pointer){. dynlib: dllname, importc: "glIndexPointer".} proc glIndexd*(c: TGLdouble){.dynlib: dllname, importc: "glIndexd".} proc glIndexdv*(c: PGLdouble){.dynlib: dllname, importc: "glIndexdv".} @@ -1215,7 +1215,7 @@ proc glIndexsv*(c: PGLshort){.dynlib: dllname, importc: "glIndexsv".} proc glIndexub*(c: TGLubyte){.dynlib: dllname, importc: "glIndexub".} proc glIndexubv*(c: PGLubyte){.dynlib: dllname, importc: "glIndexubv".} proc glInitNames*(){.dynlib: dllname, importc: "glInitNames".} -proc glInterleavedArrays*(format: TGLenum, stride: TGLsizei, pointer: Pointer){. +proc glInterleavedArrays*(format: TGLenum, stride: TGLsizei, p: pointer){. dynlib: dllname, importc: "glInterleavedArrays".} proc glIsEnabled*(cap: TGLenum): TGLboolean{.dynlib: dllname, importc: "glIsEnabled".} @@ -1288,7 +1288,7 @@ proc glNormal3i*(nx, ny, nz: TGLint){.dynlib: dllname, importc: "glNormal3i".} proc glNormal3iv*(v: PGLint){.dynlib: dllname, importc: "glNormal3iv".} proc glNormal3s*(nx, ny, nz: TGLshort){.dynlib: dllname, importc: "glNormal3s".} proc glNormal3sv*(v: PGLshort){.dynlib: dllname, importc: "glNormal3sv".} -proc glNormalPointer*(atype: TGLenum, stride: TGLsizei, pointer: Pointer){. +proc glNormalPointer*(atype: TGLenum, stride: TGLsizei, p: pointer){. dynlib: dllname, importc: "glNormalPointer".} proc glOrtho*(left, right, bottom, top, zNear, zFar: TGLdouble){. dynlib: dllname, importc: "glOrtho".} @@ -1360,7 +1360,7 @@ proc glRasterPos4s*(x, y, z, w: TGLshort){.dynlib: dllname, proc glRasterPos4sv*(v: PGLshort){.dynlib: dllname, importc: "glRasterPos4sv".} proc glReadBuffer*(mode: TGLenum){.dynlib: dllname, importc: "glReadBuffer".} proc glReadPixels*(x, y: TGLint, width, height: TGLsizei, - format, atype: TGLenum, pixels: Pointer){.dynlib: dllname, + format, atype: TGLenum, pixels: pointer){.dynlib: dllname, importc: "glReadPixels".} proc glRectd*(x1, y1, x2, y2: TGLdouble){.dynlib: dllname, importc: "glRectd".} proc glRectdv*(v1: PGLdouble, v2: PGLdouble){.dynlib: dllname, @@ -1383,7 +1383,7 @@ proc glScissor*(x, y: TGLint, width, height: TGLsizei){.dynlib: dllname, proc glSelectBuffer*(size: TGLsizei, buffer: PGLuint){.dynlib: dllname, importc: "glSelectBuffer".} proc glShadeModel*(mode: TGLenum){.dynlib: dllname, importc: "glShadeModel".} -proc glStencilFunc*(func: TGLenum, theref: TGLint, mask: TGLuint){. +proc glStencilFunc*(fun: TGLenum, theref: TGLint, mask: TGLuint){. dynlib: dllname, importc: "glStencilFunc".} proc glStencilMask*(mask: TGLuint){.dynlib: dllname, importc: "glStencilMask".} proc glStencilOp*(fail, zfail, zpass: TGLenum){.dynlib: dllname, @@ -1424,7 +1424,7 @@ proc glTexCoord4s*(s, t, r, q: TGLshort){.dynlib: dllname, importc: "glTexCoord4s".} proc glTexCoord4sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord4sv".} proc glTexCoordPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei, - pointer: Pointer){.dynlib: dllname, + p: pointer){.dynlib: dllname, importc: "glTexCoordPointer".} proc glTexEnvf*(target: TGLenum, pname: TGLenum, param: TGLfloat){. dynlib: dllname, importc: "glTexEnvf".} @@ -1448,10 +1448,10 @@ proc glTexGeniv*(coord: TGLenum, pname: TGLenum, params: PGLint){. dynlib: dllname, importc: "glTexGeniv".} proc glTexImage1D*(target: TGLenum, level, internalformat: TGLint, width: TGLsizei, border: TGLint, format, atype: TGLenum, - pixels: Pointer){.dynlib: dllname, importc: "glTexImage1D".} + pixels: pointer){.dynlib: dllname, importc: "glTexImage1D".} proc glTexImage2D*(target: TGLenum, level, internalformat: TGLint, width, height: TGLsizei, border: TGLint, - format, atype: TGLenum, pixels: Pointer){.dynlib: dllname, + format, atype: TGLenum, pixels: pointer){.dynlib: dllname, importc: "glTexImage2D".} proc glTexParameterf*(target: TGLenum, pname: TGLenum, param: TGLfloat){. dynlib: dllname, importc: "glTexParameterf".} @@ -1462,11 +1462,11 @@ proc glTexParameteri*(target: TGLenum, pname: TGLenum, param: TGLint){. proc glTexParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){. dynlib: dllname, importc: "glTexParameteriv".} proc glTexSubImage1D*(target: TGLenum, level, xoffset: TGLint, width: TGLsizei, - format, atype: TGLenum, pixels: Pointer){.dynlib: dllname, + format, atype: TGLenum, pixels: pointer){.dynlib: dllname, importc: "glTexSubImage1D".} proc glTexSubImage2D*(target: TGLenum, level, xoffset, yoffset: TGLint, width, height: TGLsizei, format, atype: TGLenum, - pixels: Pointer){.dynlib: dllname, + pixels: pointer){.dynlib: dllname, importc: "glTexSubImage2D".} proc glTranslated*(x, y, z: TGLdouble){.dynlib: dllname, importc: "glTranslated".} proc glTranslatef*(x, y, z: TGLfloat){.dynlib: dllname, importc: "glTranslatef".} @@ -1495,7 +1495,7 @@ proc glVertex4iv*(v: PGLint){.dynlib: dllname, importc: "glVertex4iv".} proc glVertex4s*(x, y, z, w: TGLshort){.dynlib: dllname, importc: "glVertex4s".} proc glVertex4sv*(v: PGLshort){.dynlib: dllname, importc: "glVertex4sv".} proc glVertexPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei, - pointer: Pointer){.dynlib: dllname, + p: pointer){.dynlib: dllname, importc: "glVertexPointer".} proc glViewport*(x, y: TGLint, width, height: TGLsizei){.dynlib: dllname, importc: "glViewport".} @@ -1505,28 +1505,28 @@ type count: TGLsizei) PFN_GLVERTEX_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum, stride, count: TGLsizei, - pointer: Pointer) + p: pointer) PFN_GLNORMAL_POINTER_EXTPROC* = proc (atype: TGLenum, stride, count: TGLsizei, - pointer: Pointer) + p: pointer) PFN_GLCOLOR_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum, - stride, count: TGLsizei, pointer: Pointer) + stride, count: TGLsizei, p: pointer) PFN_GLINDEX_POINTER_EXTPROC* = proc (atype: TGLenum, stride, count: TGLsizei, - pointer: Pointer) + p: pointer) PFN_GLTEXCOORD_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum, - stride, count: TGLsizei, pointer: Pointer) + stride, count: TGLsizei, p: pointer) PFN_GLEDGEFLAG_POINTER_EXTPROC* = proc (stride, count: TGLsizei, pointer: PGLboolean) - PFN_GLGET_POINTER_VEXT_PROC* = proc (pname: TGLenum, params: Pointer) + PFN_GLGET_POINTER_VEXT_PROC* = proc (pname: TGLenum, params: pointer) PFN_GLARRAY_ELEMENT_ARRAY_EXTPROC* = proc (mode: TGLenum, count: TGLsizei, - pi: Pointer) # WIN_swap_hint + pi: pointer) # WIN_swap_hint PFN_GLADDSWAPHINT_RECT_WINPROC* = proc (x, y: TGLint, width, height: TGLsizei) PFN_GLCOLOR_TABLE_EXTPROC* = proc (target, internalFormat: TGLenum, width: TGLsizei, format, atype: TGLenum, - data: Pointer) + data: pointer) PFN_GLCOLOR_SUBTABLE_EXTPROC* = proc (target: TGLenum, start, count: TGLsizei, - format, atype: TGLenum, data: Pointer) + format, atype: TGLenum, data: pointer) PFN_GLGETCOLOR_TABLE_EXTPROC* = proc (target, format, atype: TGLenum, - data: Pointer) + data: pointer) PFN_GLGETCOLOR_TABLE_PARAMETER_IVEXTPROC* = proc (target, pname: TGLenum, params: PGLint) PFN_GLGETCOLOR_TABLE_PARAMETER_FVEXTPROC* = proc (target, pname: TGLenum, diff --git a/tests/manyloc/keineschweine/lib/map_filter.nim b/tests/manyloc/keineschweine/lib/map_filter.nim index 54173fa61..966b84b6a 100644 --- a/tests/manyloc/keineschweine/lib/map_filter.nim +++ b/tests/manyloc/keineschweine/lib/map_filter.nim @@ -4,14 +4,14 @@ template filterIt2*(seq, pred: expr, body: stmt): stmt {.immediate, dirty.} = for it in items(seq): if pred: body -proc map*[A, B](x: seq[A], func: proc(y: A): B {.closure.}): seq[B] = +proc map*[A, B](x: seq[A], fun: proc(y: A): B {.closure.}): seq[B] = result = @[] for item in x.items: - result.add func(item) + result.add fun(item) -proc mapInPlace*[A](x: var seq[A], func: proc(y: A): A {.closure.}) = +proc mapInPlace*[A](x: var seq[A], fun: proc(y: A): A {.closure.}) = for i in 0..x.len-1: - x[i] = func(x[i]) + x[i] = fun(x[i]) template unless*(condition: expr; body: stmt): stmt {.dirty.} = if not(condition): @@ -38,4 +38,4 @@ when isMainModule: var someSeq = @[9,8,7,6,5,4,3,2,1] ## numbers < 6 or even filterIt2 someSeq, it < 6 or (it and 1) == 0: echo(it) - echo "-----------" \ No newline at end of file + echo "-----------" diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim index ccd1d9280..c5a39550a 100644 --- a/tests/manyloc/keineschweine/lib/sg_assets.nim +++ b/tests/manyloc/keineschweine/lib/sg_assets.nim @@ -122,9 +122,9 @@ var nameToBulletID*: TTable[string, int] activeState = Lobby -proc newSprite(filename: string; errors: var seq[string]): PSpriteSheet +proc newSprite*(filename: string; errors: var seq[string]): PSpriteSheet proc load*(ss: PSpriteSheet): bool {.discardable.} -proc newSound(filename: string; errors: var seq[string]): PSoundRecord +proc newSound*(filename: string; errors: var seq[string]): PSoundRecord proc load*(s: PSoundRecord): bool {.discardable.} proc validateSettings*(settings: PJsonNode; errors: var seq[string]): bool @@ -146,7 +146,7 @@ proc importHandling(data: PJsonNode): THandlingRecord proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord proc importSoul(data: PJsonNode): TSoulRecord proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord -proc importSound(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord +proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord ## this is the only pipe between lobby and main.nim proc getActiveState*(): TGameState = @@ -466,7 +466,7 @@ proc importPhys(data: PJsonNode): TPhysicsRecord = phys.getField("radius", result.radius) phys.getField("mass", result.mass) when not defined(NoChipmunk): - result.moment = momentForCircle(result.mass, 0.0, result.radius, vectorZero) * MomentMult + result.moment = momentForCircle(result.mass, 0.0, result.radius, VectorZero) * MomentMult proc importHandling(data: PJsonNode): THandlingRecord = result.thrust = 45.0 result.topSpeed = 100.0 #unused diff --git a/tests/manyloc/keineschweine/lib/sg_packets.nim b/tests/manyloc/keineschweine/lib/sg_packets.nim index 625436cb6..601054b47 100644 --- a/tests/manyloc/keineschweine/lib/sg_packets.nim +++ b/tests/manyloc/keineschweine/lib/sg_packets.nim @@ -9,8 +9,8 @@ template idpacket(pktName, id, s2c, c2s: expr): stmt {.immediate, dirty.} = defPacket(`Sc pktName`, s2c) defPacket(`Cs pktName`, c2s) -forwardPacketT(Uint8, int8) -forwardPacketT(Uint16, int16) +forwardPacketT(uint8, int8) +forwardPacketT(uint16, int16) forwardPacketT(TPort, int16) idPacket(Login, 'a', @@ -51,7 +51,7 @@ defPacket(ScTeamList, tuple[teams: seq[ScTeam]]) let HTeamChange* = 't' idPacket(ZoneQuery, 'Q', - tuple[playerCount: Uint16], ##i should include a time here or something + tuple[playerCount: uint16], ##i should include a time here or something tuple[pad: char = '\0']) type SpawnKind = enum diff --git a/tests/manyloc/keineschweine/lib/vehicles.nim b/tests/manyloc/keineschweine/lib/vehicles.nim index edbd84ff9..4b11856c6 100644 --- a/tests/manyloc/keineschweine/lib/vehicles.nim +++ b/tests/manyloc/keineschweine/lib/vehicles.nim @@ -9,22 +9,22 @@ proc accel*(obj: PVehicle, dt: float) = # sin(obj.angle) * obj.record.handling.thrust.float * dt) obj.body.applyImpulse( vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.thrust, - vectorZero) + VectorZero) proc reverse*(obj: PVehicle, dt: float) = #obj.velocity += vec2f( # -cos(obj.angle) * obj.record.handling.reverse.float * dt, # -sin(obj.angle) * obj.record.handling.reverse.float * dt) obj.body.applyImpulse( -vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.reverse, - vectorZero) + VectorZero) proc strafe_left*(obj: PVehicle, dt: float) = obj.body.applyImpulse( vectorForAngle(obj.body.getAngle()).perp() * obj.record.handling.strafe * dt, - vectorZero) + VectorZero) proc strafe_right*(obj: PVehicle, dt: float) = obj.body.applyImpulse( vectorForAngle(obj.body.getAngle()).rperp()* obj.record.handling.strafe * dt, - vectorZero) + VectorZero) proc turn_right*(obj: PVehicle, dt: float) = #obj.angle = (obj.angle + (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU obj.body.setTorque(obj.record.handling.rotation) diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim index ef977afb0..9a6542d75 100644 --- a/tests/manyloc/keineschweine/lib/zlib_helpers.nim +++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim @@ -8,7 +8,7 @@ proc compress*(source: string): string = result.setLen destLen var res = zlib.compress(cstring(result), addr destLen, cstring(source), sourceLen) if res != Z_OK: - echo "Error occured: ", res + echo "Error occurred: ", res elif destLen < result.len: result.setLen(destLen) @@ -17,7 +17,7 @@ proc uncompress*(source: string, destLen: var int): string = result.setLen destLen var res = zlib.uncompress(cstring(result), addr destLen, cstring(source), source.len) if res != Z_OK: - echo "Error occured: ", res + echo "Error occurred: ", res when isMainModule: diff --git a/tests/manyloc/keineschweine/server/nimrod.cfg b/tests/manyloc/keineschweine/server/nim.cfg index fdc45a8e1..fdc45a8e1 100644 --- a/tests/manyloc/keineschweine/server/nimrod.cfg +++ b/tests/manyloc/keineschweine/server/nim.cfg diff --git a/tests/metatype/tautoproc.nim b/tests/metatype/tautoproc.nim index 9e8ff0bcb..562f508fc 100644 --- a/tests/metatype/tautoproc.nim +++ b/tests/metatype/tautoproc.nim @@ -1,3 +1,7 @@ +discard """ + errormsg: "expression 'generate(builder)' has no type (or is ambiguous)" +""" + # bug #898 proc measureTime(e: auto) = diff --git a/tests/metatype/tcompositetypeclasses.nim b/tests/metatype/tcompositetypeclasses.nim index 5ae93795f..1cb86e4d7 100644 --- a/tests/metatype/tcompositetypeclasses.nim +++ b/tests/metatype/tcompositetypeclasses.nim @@ -30,7 +30,7 @@ accept bar(vbar) accept baz(vbar) accept baz(vbaz) -reject baz(vnotbaz) +#reject baz(vnotbaz) # XXX this really shouldn't compile reject bar(vfoo) # https://github.com/Araq/Nim/issues/517 diff --git a/tests/matrix/tmatrix.nim b/tests/metatype/tmatrix.nim index 90dfde959..90dfde959 100644 --- a/tests/matrix/tmatrix.nim +++ b/tests/metatype/tmatrix.nim diff --git a/tests/matrix/tmatrix1.nim b/tests/metatype/tmatrix1.nim index 0adf30b57..0adf30b57 100644 --- a/tests/matrix/tmatrix1.nim +++ b/tests/metatype/tmatrix1.nim diff --git a/tests/matrix/tmatrix2.nim b/tests/metatype/tmatrix2.nim index 82990f1a5..82990f1a5 100644 --- a/tests/matrix/tmatrix2.nim +++ b/tests/metatype/tmatrix2.nim diff --git a/tests/metatype/tmatrix3.nim b/tests/metatype/tmatrix3.nim new file mode 100644 index 000000000..a143e2bc9 --- /dev/null +++ b/tests/metatype/tmatrix3.nim @@ -0,0 +1,19 @@ +discard """ + output: "" +""" + +type Matrix[M,N: static[int]] = array[M, array[N, float]] + +let a = [[1.0, 1.0, 1.0, 1.0], + [2.0, 4.0, 8.0, 16.0], + [3.0, 9.0, 27.0, 81.0], + [4.0, 16.0, 64.0, 256.0]] + +proc `$`(m: Matrix): string = + result = "" + +proc `*`[M,N,M2,N2](a: Matrix[M,N2]; b: Matrix[M2,N]): Matrix[M,N] = + discard + +echo a * a + diff --git a/tests/static/tstaticparammacro.nim b/tests/metatype/tstaticparammacro.nim index ebd6caa47..e577efc56 100644 --- a/tests/static/tstaticparammacro.nim +++ b/tests/metatype/tstaticparammacro.nim @@ -14,6 +14,7 @@ AST b 20Test 20 ''' + disabled: true """ import macros diff --git a/tests/metatype/tstaticvector.nim b/tests/metatype/tstaticvector.nim new file mode 100644 index 000000000..c9923f469 --- /dev/null +++ b/tests/metatype/tstaticvector.nim @@ -0,0 +1,17 @@ + +type + RectArray*[R, C: static[int], T] = distinct array[R * C, T] + + StaticMatrix*[R, C: static[int], T] = object + elements*: RectArray[R, C, T] + + StaticVector*[N: static[int], T] = StaticMatrix[N, 1, T] + +proc foo*[N, T](a: StaticVector[N, T]): T = 0.T +proc foobar*[N, T](a, b: StaticVector[N, T]): T = 0.T + + +var a: StaticVector[3, int] + +echo foo(a) # OK +echo foobar(a, a) # <--- hangs compiler diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 4344855eb..4c3ad9e0b 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -1,6 +1,7 @@ discard """ msg: "int\nstring\nTBar[int]" output: "int\nstring\nTBar[int]\nint\nrange 0..2(int)\nstring" + disabled: true """ import typetraits diff --git a/tests/matrix/issue1013.nim b/tests/metatype/tymatrix.nim index 7d3d52f85..7d3d52f85 100644 --- a/tests/matrix/issue1013.nim +++ b/tests/metatype/tymatrix.nim diff --git a/tests/metatype/typeclassinference.nim b/tests/metatype/typeclassinference.nim index 2ac037ac5..fd2d307a9 100644 --- a/tests/metatype/typeclassinference.nim +++ b/tests/metatype/typeclassinference.nim @@ -1,6 +1,7 @@ discard """ errormsg: "type mismatch: got (string) but expected 'ptr'" line: 20 + disabled: true """ import typetraits diff --git a/tests/metatype/typedesc_as_value.nim b/tests/metatype/typedesc_as_value.nim new file mode 100644 index 000000000..f6e526987 --- /dev/null +++ b/tests/metatype/typedesc_as_value.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "'typedesc' metatype is not valid here; typed '=' instead of ':'?" +""" + + +var x = int + +echo x + + + diff --git a/tests/namspc/mnamspc1.nim b/tests/modules/mnamspc1.nim index da13c5f24..da13c5f24 100644 --- a/tests/namspc/mnamspc1.nim +++ b/tests/modules/mnamspc1.nim diff --git a/tests/namspc/mnamspc2.nim b/tests/modules/mnamspc2.nim index 84ef8533e..84ef8533e 100644 --- a/tests/namspc/mnamspc2.nim +++ b/tests/modules/mnamspc2.nim diff --git a/tests/module/mopaque.nim b/tests/modules/mopaque.nim index 7eee4bd96..7eee4bd96 100644 --- a/tests/module/mopaque.nim +++ b/tests/modules/mopaque.nim diff --git a/tests/module/mrecmod.nim b/tests/modules/mrecmod.nim index fab9654d5..fab9654d5 100644 --- a/tests/module/mrecmod.nim +++ b/tests/modules/mrecmod.nim diff --git a/tests/module/mrecmod2.nim b/tests/modules/mrecmod2.nim index 9557ce729..9557ce729 100644 --- a/tests/module/mrecmod2.nim +++ b/tests/modules/mrecmod2.nim diff --git a/tests/modules/tmismatchedvisibility.nim b/tests/modules/tmismatchedvisibility.nim index 6f2f79282..325c729c0 100644 --- a/tests/modules/tmismatchedvisibility.nim +++ b/tests/modules/tmismatchedvisibility.nim @@ -1,9 +1,9 @@ discard """ line: 8 - errormsg: "public implementation 'tmismatchedvisibility.foo(a: int): int' has non-public forward declaration in tmismatchedvisibility.nim(6,5)" + errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)' has non-public forward declaration in " """ proc foo(a: int): int proc foo*(a: int): int = - result = a + a \ No newline at end of file + result = a + a diff --git a/tests/namspc/tnamspc.nim b/tests/modules/tnamspc.nim index 1e2049cec..1e2049cec 100644 --- a/tests/namspc/tnamspc.nim +++ b/tests/modules/tnamspc.nim diff --git a/tests/module/topaque.nim b/tests/modules/topaque.nim index f0587c959..f0587c959 100644 --- a/tests/module/topaque.nim +++ b/tests/modules/topaque.nim diff --git a/tests/module/trecinca.nim b/tests/modules/trecinca.nim index 62d37783c..bedea8d7e 100644 --- a/tests/module/trecinca.nim +++ b/tests/modules/trecinca.nim @@ -1,7 +1,7 @@ discard """ file: "tests/reject/trecincb.nim" line: 9 - errormsg: "recursive dependency: 'tests/module/trecincb.nim'" + errormsg: "recursive dependency: 'trecincb.nim'" """ # Test recursive includes diff --git a/tests/module/trecincb.nim b/tests/modules/trecincb.nim index a2934052f..eb0f72db0 100644 --- a/tests/module/trecincb.nim +++ b/tests/modules/trecincb.nim @@ -1,7 +1,7 @@ discard """ file: "trecincb.nim" line: 9 - errormsg: "recursive dependency: 'tests/module/trecincb.nim'" + errormsg: "recursive dependency: 'trecincb.nim'" """ # Test recursive includes diff --git a/tests/module/trecmod.nim b/tests/modules/trecmod.nim index 9d39d3ff7..9d39d3ff7 100644 --- a/tests/module/trecmod.nim +++ b/tests/modules/trecmod.nim diff --git a/tests/module/trecmod2.nim b/tests/modules/trecmod2.nim index 85fe2215f..85fe2215f 100644 --- a/tests/module/trecmod2.nim +++ b/tests/modules/trecmod2.nim diff --git a/tests/notnil/tnotnil_in_generic.nim b/tests/notnil/tnotnil_in_generic.nim new file mode 100644 index 000000000..1e2d8b940 --- /dev/null +++ b/tests/notnil/tnotnil_in_generic.nim @@ -0,0 +1,27 @@ +discard """ + errormsg: "cannot prove 'x' is not nil" +""" + +# bug #2216 + +type + A[T] = ref object + x: int + ud: T + +proc good[T](p: A[T]) = + discard + +proc bad[T](p: A[T] not nil) = + discard + + +proc go() = + let s = A[int](x: 1) + + good(s) + bad(s) + var x: A[int] + bad(x) + +go() diff --git a/tests/objects/tobjpragma.nim b/tests/objects/tobjpragma.nim index f9fbd5e40..dda8057b6 100644 --- a/tests/objects/tobjpragma.nim +++ b/tests/objects/tobjpragma.nim @@ -7,8 +7,11 @@ discard """ 1 2 3''' + disabled: "true" """ +# Disabled since some versions of GCC ignore the 'packed' attribute + # Test type diff --git a/tests/objects/trefobjsyntax.nim b/tests/objects/trefobjsyntax.nim new file mode 100644 index 000000000..9b48de718 --- /dev/null +++ b/tests/objects/trefobjsyntax.nim @@ -0,0 +1,27 @@ +discard """ + output: '''wohoo +baz''' +""" + +# Test to ensure the popular 'ref T' syntax works everywhere + +type + Foo = object + a, b: int + s: string + + FooBar = object of RootObj + n, m: string + Baz = object of FooBar + +proc invoke(a: ref Baz) = + echo "baz" + +# check object construction: +let x = (ref Foo)(a: 0, b: 45, s: "wohoo") +echo x.s + +var y: ref FooBar = (ref Baz)(n: "n", m: "m") + +invoke((ref Baz)(y)) + diff --git a/tests/objvariant/treassign.nim b/tests/objvariant/treassign.nim new file mode 100644 index 000000000..2938b30a3 --- /dev/null +++ b/tests/objvariant/treassign.nim @@ -0,0 +1,27 @@ +discard """ + output: "SUCCESS" +""" + +type + BasicNumber = object of RootObj + value: float32 + RefChild* = ref object + curr*: TokenObject + Token* {.pure.} = enum + foo, + bar, + TokenObject = object + case kind*: Token + of Token.foo: + foo*: string + of Token.bar: + bar*: BasicNumber + + +var t = RefChild() + +t.curr = TokenObject(kind: Token.bar, bar: BasicNumber(value: 12.34)) + +t.curr = TokenObject(kind: Token.foo, foo: "foo") + +echo "SUCCESS" diff --git a/tests/osproc/tstdin.nim b/tests/osproc/tstdin.nim index 2ea939992..b491c2500 100644 --- a/tests/osproc/tstdin.nim +++ b/tests/osproc/tstdin.nim @@ -4,13 +4,16 @@ discard """ """ import osproc, os, streams -doAssert fileExists(getCurrentDir() / "tests" / "osproc" / "ta.exe") +const filename = when defined(Windows): "ta.exe" else: "ta" -var p = startProcess("ta.exe", getCurrentDir() / "tests" / "osproc") +doAssert fileExists(getCurrentDir() / "tests" / "osproc" / filename) + +var p = startProcess(filename, getCurrentDir() / "tests" / "osproc") p.inputStream.write("5\n") +p.inputStream.flush() while true: let line = p.outputStream.readLine() if line != "": echo line else: - break \ No newline at end of file + break diff --git a/tests/overload/tparams_after_varargs.nim b/tests/overload/tparams_after_varargs.nim new file mode 100644 index 000000000..a93e280b9 --- /dev/null +++ b/tests/overload/tparams_after_varargs.nim @@ -0,0 +1,17 @@ +discard """ + output: '''a 1 b 2 x @[3, 4, 5] y 6 z 7 +yay +12''' +""" + +proc test(a, b: int, x: varargs[int]; y, z: int) = + echo "a ", a, " b ", b, " x ", @x, " y ", y, " z ", z + +test 1, 2, 3, 4, 5, 6, 7 + +template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) = + blck + echo a, b + +takesBlock 1, 2, "some", 0.90, "random stuff": + echo "yay" diff --git a/tests/overload/tprefer_tygenericinst.nim b/tests/overload/tprefer_tygenericinst.nim new file mode 100644 index 000000000..2700bed5e --- /dev/null +++ b/tests/overload/tprefer_tygenericinst.nim @@ -0,0 +1,17 @@ +discard """ + output: "Version 2 was called." + disabled: true +""" + +# bug #2220 + +type A[T] = object +type B = A[int] + +proc p[X](x: X) = + echo "Version 1 was called." + +proc p(x: B) = + echo "Version 2 was called." + +p(B()) # This call reported as ambiguous. diff --git a/tests/parser/twhen_in_enum.nim b/tests/parser/twhen_in_enum.nim new file mode 100644 index 000000000..d4a3ea56a --- /dev/null +++ b/tests/parser/twhen_in_enum.nim @@ -0,0 +1,11 @@ +discard """ + errormsg: "identifier expected, but found 'keyword when'" +""" + +# bug #2123 +type num = enum + NUM_NONE = 0 + NUM_ALL = 1 + when defined(macosx): NUM_OSX = 10 # only this differs for real + NUM_XTRA = 20 + diff --git a/tests/rodfiles/nimrod.cfg b/tests/rodfiles/nim.cfg index 78fc8db64..78fc8db64 100644 --- a/tests/rodfiles/nimrod.cfg +++ b/tests/rodfiles/nim.cfg diff --git a/tests/stdlib/tdialogs.nim b/tests/stdlib/tdialogs.nim index d161a976d..f0203d319 100644 --- a/tests/stdlib/tdialogs.nim +++ b/tests/stdlib/tdialogs.nim @@ -4,7 +4,7 @@ import dialogs, gtk2 gtk2.nimrod_init() -var x = ChooseFilesToOpen(nil) +var x = chooseFilesToOpen(nil) for a in items(x): writeln(stdout, a) @@ -12,6 +12,6 @@ info(nil, "start with an info box") warning(nil, "now a warning ...") error(nil, "... and an error!") -writeln(stdout, ChooseFileToOpen(nil)) -writeln(stdout, ChooseFileToSave(nil)) -writeln(stdout, ChooseDir(nil)) +writeln(stdout, chooseFileToOpen(nil)) +writeln(stdout, chooseFileToSave(nil)) +writeln(stdout, chooseDir(nil)) diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim index 49a019061..c8e496cc1 100644 --- a/tests/stdlib/tgetfileinfo.nim +++ b/tests/stdlib/tgetfileinfo.nim @@ -32,7 +32,7 @@ proc caseOneAndTwo(followLink: bool) = try: discard getFileInfo(getAppFilename(), followLink) #echo("String : Existing File : Symlink $# : Success" % $followLink) - except EOS: + except OSError: echo("String : Existing File : Symlink $# : Failure" % $followLink) proc caseThreeAndFour(followLink: bool) = @@ -40,7 +40,8 @@ proc caseThreeAndFour(followLink: bool) = try: discard getFileInfo(invalidName, true) echo("String : Non-existing File : Symlink $# : Failure" % $followLink) - except EOS: + except OSError: + discard #echo("String : Non-existing File : Symlink $# : Success" % $followLink) proc testGetFileInfo = @@ -82,12 +83,14 @@ proc testGetFileInfo = discard getFileInfo(testFile) echo("Handle : Invalid File : Failure") except EIO, EOS: + discard #echo("Handle : Invalid File : Success") try: discard getFileInfo(testHandle) echo("Handle : Invalid File : Failure") except EIO, EOS: + discard #echo("Handle : Invalid File : Success") -testGetFileInfo() \ No newline at end of file +testGetFileInfo() diff --git a/tests/stdlib/tircbot.nim b/tests/stdlib/tircbot.nim deleted file mode 100644 index b91300762..000000000 --- a/tests/stdlib/tircbot.nim +++ /dev/null @@ -1,452 +0,0 @@ -import irc, sockets, asyncio, json, os, strutils, times, redis - -type - TDb* = object - r*: TRedis - lastPing: float - - TBuildResult* = enum - bUnknown, bFail, bSuccess - - TTestResult* = enum - tUnknown, tFail, tSuccess - - TEntry* = tuple[c: TCommit, p: seq[TPlatform]] - - TCommit* = object - commitMsg*, username*, hash*: string - date*: TTime - - TPlatform* = object - buildResult*: TBuildResult - testResult*: TTestResult - failReason*, platform*: string - total*, passed*, skipped*, failed*: biggestInt - csources*: bool - -const - listName = "commits" - failOnExisting = False - -proc open*(host = "localhost", port: TPort): TDb = - result.r = redis.open(host, port) - result.lastPing = epochTime() - -discard """proc customHSet(database: TDb, name, field, value: string) = - if database.r.hSet(name, field, value).int == 0: - if failOnExisting: - assert(false) - else: - echo("[Warning:REDIS] ", field, " already exists in ", name)""" - -proc updateProperty*(database: TDb, commitHash, platform, property, - value: string) = - var name = platform & ":" & commitHash - if database.r.hSet(name, property, value).int == 0: - echo("[INFO:REDIS] '$1' field updated in hash" % [property]) - else: - echo("[INFO:REDIS] '$1' new field added to hash" % [property]) - -proc globalProperty*(database: TDb, commitHash, property, value: string) = - if database.r.hSet(commitHash, property, value).int == 0: - echo("[INFO:REDIS] '$1' field updated in hash" % [property]) - else: - echo("[INFO:REDIS] '$1' new field added to hash" % [property]) - -proc addCommit*(database: TDb, commitHash, commitMsg, user: string) = - # Add the commit hash to the `commits` list. - discard database.r.lPush(listName, commitHash) - # Add the commit message, current date and username as a property - globalProperty(database, commitHash, "commitMsg", commitMsg) - globalProperty(database, commitHash, "date", $int(getTime())) - globalProperty(database, commitHash, "username", user) - -proc keepAlive*(database: var TDb) = - ## Keep the connection alive. Ping redis in this case. This functions does - ## not guarantee that redis will be pinged. - var t = epochTime() - if t - database.lastPing >= 60.0: - echo("PING -> redis") - assert(database.r.ping() == "PONG") - database.lastPing = t - -proc getCommits*(database: TDb, - plStr: var seq[string]): seq[TEntry] = - result = @[] - var commitsRaw = database.r.lrange("commits", 0, -1) - for c in items(commitsRaw): - var commit: TCommit - commit.hash = c - for key, value in database.r.hPairs(c): - case normalize(key) - of "commitmsg": commit.commitMsg = value - of "date": commit.date = TTime(parseInt(value)) - of "username": commit.username = value - else: - echo(key) - assert(false) - - var platformsRaw = database.r.lrange(c & ":platforms", 0, -1) - var platforms: seq[TPlatform] = @[] - for p in items(platformsRaw): - var platform: TPlatform - for key, value in database.r.hPairs(p & ":" & c): - case normalize(key) - of "buildresult": - platform.buildResult = parseInt(value).TBuildResult - of "testresult": - platform.testResult = parseInt(value).TTestResult - of "failreason": - platform.failReason = value - of "total": - platform.total = parseBiggestInt(value) - of "passed": - platform.passed = parseBiggestInt(value) - of "skipped": - platform.skipped = parseBiggestInt(value) - of "failed": - platform.failed = parseBiggestInt(value) - of "csources": - platform.csources = if value == "t": true else: false - else: - echo(normalize(key)) - assert(false) - - platform.platform = p - - platforms.add(platform) - if p notin plStr: - plStr.add(p) - result.add((commit, platforms)) - -proc commitExists*(database: TDb, commit: string, starts = false): bool = - # TODO: Consider making the 'commits' list a set. - for c in items(database.r.lrange("commits", 0, -1)): - if starts: - if c.startsWith(commit): return true - else: - if c == commit: return true - return false - -proc platformExists*(database: TDb, commit: string, platform: string): bool = - for p in items(database.r.lrange(commit & ":" & "platforms", 0, -1)): - if p == platform: return true - -proc expandHash*(database: TDb, commit: string): string = - for c in items(database.r.lrange("commits", 0, -1)): - if c.startsWith(commit): return c - assert false - -proc isNewest*(database: TDb, commit: string): bool = - return database.r.lIndex("commits", 0) == commit - -proc getNewest*(database: TDb): string = - return database.r.lIndex("commits", 0) - -proc addPlatform*(database: TDb, commit: string, platform: string) = - assert database.commitExists(commit) - assert (not database.platformExists(commit, platform)) - var name = platform & ":" & commit - if database.r.exists(name): - if failOnExisting: quit("[FAIL] " & name & " already exists!", 1) - else: echo("[Warning] " & name & " already exists!") - - discard database.r.lPush(commit & ":" & "platforms", platform) - -proc `[]`*(p: seq[TPlatform], name: string): TPlatform = - for platform in items(p): - if platform.platform == name: - return platform - raise newException(EInvalidValue, name & " platforms not found in commits.") - -proc contains*(p: seq[TPlatform], s: string): bool = - for i in items(p): - if i.platform == s: - return True - - -type - PState = ref TState - TState = object of TObject - dispatcher: PDispatcher - sock: PAsyncSocket - ircClient: PAsyncIRC - hubPort: TPort - database: TDb - dbConnected: bool - - TSeenType = enum - PSeenJoin, PSeenPart, PSeenMsg, PSeenNick, PSeenQuit - - TSeen = object - nick: string - channel: string - timestamp: TTime - case kind*: TSeenType - of PSeenJoin: nil - of PSeenPart, PSeenQuit, PSeenMsg: - msg: string - of PSeenNick: - newNick: string - -const - ircServer = "irc.freenode.net" - joinChans = @["#nim"] - botNickname = "NimBot" - -proc setSeen(d: TDb, s: TSeen) = - discard d.r.del("seen:" & s.nick) - - var hashToSet = @[("type", $s.kind.int), ("channel", s.channel), - ("timestamp", $s.timestamp.int)] - case s.kind - of PSeenJoin: discard - of PSeenPart, PSeenMsg, PSeenQuit: - hashToSet.add(("msg", s.msg)) - of PSeenNick: - hashToSet.add(("newnick", s.newNick)) - - d.r.hMSet("seen:" & s.nick, hashToSet) - -proc getSeen(d: TDb, nick: string, s: var TSeen): bool = - if d.r.exists("seen:" & nick): - result = true - s.nick = nick - # Get the type first - s.kind = d.r.hGet("seen:" & nick, "type").parseInt.TSeenType - - for key, value in d.r.hPairs("seen:" & nick): - case normalize(key) - of "type": - #s.kind = value.parseInt.TSeenType - of "channel": - s.channel = value - of "timestamp": - s.timestamp = TTime(value.parseInt) - of "msg": - s.msg = value - of "newnick": - s.newNick = value - -template createSeen(typ: TSeenType, n, c: string): stmt {.immediate, dirty.} = - var seenNick: TSeen - seenNick.kind = typ - seenNick.nick = n - seenNick.channel = c - seenNick.timestamp = getTime() - -proc parseReply(line: string, expect: string): Bool = - var jsonDoc = parseJson(line) - return jsonDoc["reply"].str == expect - -proc limitCommitMsg(m: string): string = - ## Limits the message to 300 chars and adds ellipsis. - var m1 = m - if NewLines in m1: - m1 = m1.splitLines()[0] - - if m1.len >= 300: - m1 = m1[0..300] - - if m1.len >= 300 or NewLines in m: m1.add("... ") - - if NewLines in m: m1.add($m.splitLines().len & " more lines") - - return m1 - -proc handleWebMessage(state: PState, line: string) = - echo("Got message from hub: " & line) - var json = parseJson(line) - if json.hasKey("payload"): - for i in 0..min(4, json["payload"]["commits"].len-1): - var commit = json["payload"]["commits"][i] - # Create the message - var message = "" - message.add(json["payload"]["repository"]["owner"]["name"].str & "/" & - json["payload"]["repository"]["name"].str & " ") - message.add(commit["id"].str[0..6] & " ") - message.add(commit["author"]["name"].str & " ") - message.add("[+" & $commit["added"].len & " ") - message.add("±" & $commit["modified"].len & " ") - message.add("-" & $commit["removed"].len & "]: ") - message.add(limitCommitMsg(commit["message"].str)) - - # Send message to #nim. - state.ircClient.privmsg(joinChans[0], message) - elif json.hasKey("redisinfo"): - assert json["redisinfo"].hasKey("port") - #let redisPort = json["redisinfo"]["port"].num - state.dbConnected = true - -proc hubConnect(state: PState) -proc handleConnect(s: PAsyncSocket, state: PState) = - try: - # Send greeting - var obj = newJObject() - obj["name"] = newJString("irc") - obj["platform"] = newJString("?") - state.sock.send($obj & "\c\L") - - # Wait for reply. - var line = "" - sleep(1500) - if state.sock.recvLine(line): - assert(line != "") - doAssert parseReply(line, "OK") - echo("The hub accepted me!") - else: - raise newException(EInvalidValue, - "Hub didn't accept me. Waited 1.5 seconds.") - - # ask for the redis info - var riobj = newJObject() - riobj["do"] = newJString("redisinfo") - state.sock.send($riobj & "\c\L") - - except EOS: - echo(getCurrentExceptionMsg()) - s.close() - echo("Waiting 5 seconds...") - sleep(5000) - state.hubConnect() - -proc handleRead(s: PAsyncSocket, state: PState) = - var line = "" - if state.sock.recvLine(line): - if line != "": - # Handle the message - state.handleWebMessage(line) - else: - echo("Disconnected from hub: ", OSErrorMsg()) - s.close() - echo("Reconnecting...") - state.hubConnect() - else: - echo(OSErrorMsg()) - -proc hubConnect(state: PState) = - state.sock = AsyncSocket() - state.sock.connect("127.0.0.1", state.hubPort) - state.sock.handleConnect = - proc (s: PAsyncSocket) = - handleConnect(s, state) - state.sock.handleRead = - proc (s: PAsyncSocket) = - handleRead(s, state) - - state.dispatcher.register(state.sock) - -proc handleIrc(irc: PAsyncIRC, event: TIRCEvent, state: PState) = - case event.typ - of EvConnected: discard - of EvDisconnected: - while not state.ircClient.isConnected: - try: - state.ircClient.connect() - except: - echo("Error reconnecting: ", getCurrentExceptionMsg()) - - echo("Waiting 5 seconds...") - sleep(5000) - echo("Reconnected successfully!") - of EvMsg: - echo("< ", event.raw) - case event.cmd - of MPrivMsg: - let msg = event.params[event.params.len-1] - let words = msg.split(' ') - template pm(msg: string): stmt = - state.ircClient.privmsg(event.origin, msg) - case words[0] - of "!ping": pm("pong") - of "!lag": - if state.ircClient.getLag != -1.0: - var lag = state.ircClient.getLag - lag = lag * 1000.0 - pm($int(lag) & "ms between me and the server.") - else: - pm("Unknown.") - of "!seen": - if words.len > 1: - let nick = words[1] - if nick == botNickname: - pm("Yes, I see myself.") - echo(nick) - var seenInfo: TSeen - if state.database.getSeen(nick, seenInfo): - #var mSend = "" - case seenInfo.kind - of PSeenMsg: - pm("$1 was last seen on $2 in $3 saying: $4" % - [seenInfo.nick, $seenInfo.timestamp, - seenInfo.channel, seenInfo.msg]) - of PSeenJoin: - pm("$1 was last seen on $2 joining $3" % - [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel]) - of PSeenPart: - pm("$1 was last seen on $2 leaving $3 with message: $4" % - [seenInfo.nick, $seenInfo.timestamp, seenInfo.channel, - seenInfo.msg]) - of PSeenQuit: - pm("$1 was last seen on $2 quitting with message: $3" % - [seenInfo.nick, $seenInfo.timestamp, seenInfo.msg]) - of PSeenNick: - pm("$1 was last seen on $2 changing nick to $3" % - [seenInfo.nick, $seenInfo.timestamp, seenInfo.newNick]) - - else: - pm("I have not seen " & nick) - else: - pm("Syntax: !seen <nick>") - - # TODO: ... commands - - # -- Seen - # Log this as activity. - createSeen(PSeenMsg, event.nick, event.origin) - seenNick.msg = msg - state.database.setSeen(seenNick) - of MJoin: - createSeen(PSeenJoin, event.nick, event.origin) - state.database.setSeen(seenNick) - of MPart: - createSeen(PSeenPart, event.nick, event.origin) - let msg = event.params[event.params.high] - seenNick.msg = msg - state.database.setSeen(seenNick) - of MQuit: - createSeen(PSeenQuit, event.nick, event.origin) - let msg = event.params[event.params.high] - seenNick.msg = msg - state.database.setSeen(seenNick) - of MNick: - createSeen(PSeenNick, event.nick, "#nim") - seenNick.newNick = event.params[0] - state.database.setSeen(seenNick) - else: - discard # TODO: ? - -proc open(port: TPort = TPort(5123)): PState = - var res: PState - new(res) - res.dispatcher = newDispatcher() - - res.hubPort = port - res.hubConnect() - let hirc = - proc (a: PAsyncIRC, ev: TIRCEvent) = - handleIrc(a, ev, res) - # Connect to the irc server. - res.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname, - joinChans = joinChans, ircEvent = hirc) - res.ircClient.connect() - res.dispatcher.register(res.ircClient) - - res.dbConnected = false - result = res - -var state = tircbot.open() # Connect to the website and the IRC server. - -while state.dispatcher.poll(): - if state.dbConnected: - state.database.keepAlive() diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim index 1b83aab53..a778d2f77 100644 --- a/tests/stdlib/tmarshal.nim +++ b/tests/stdlib/tmarshal.nim @@ -6,11 +6,11 @@ import marshal template testit(x: expr) = discard $$to[type(x)]($$x) -var x: array[0..4, array[0..4, string]] = [ - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], - ["test", "1", "2", "3", "4"]] -testit(x) +var x: array[0..4, array[0..4, string]] = [ + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"], + ["test", "1", "2", "3", "4"]] +testit(x) var test2: tuple[name: string, s: int] = ("tuple test", 56) testit(test2) @@ -24,7 +24,7 @@ type of blah: help: string else: - nil + discard PNode = ref TNode TNode = object diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim index 2297f0ee9..2c0a0392a 100644 --- a/tests/stdlib/tmitems.nim +++ b/tests/stdlib/tmitems.nim @@ -11,8 +11,8 @@ fpqeew [11, 12, 13] [11, 12, 13] [11, 12, 13] -{ "key1": 11, "key2": 12, "key3": 13} -[ 11, 12, 13] +{"key1": 11, "key2": 12, "key3": 13} +[11, 12, 13] <Students> <Student Name="Aprilfoo" /> <Student Name="bar" /> diff --git a/tests/stdlib/tpermutations.nim b/tests/stdlib/tpermutations.nim new file mode 100644 index 000000000..a6e07ded6 --- /dev/null +++ b/tests/stdlib/tpermutations.nim @@ -0,0 +1,19 @@ +discard """ + output: '''@[0, 2, 1] +@[1, 0, 2] +@[1, 2, 0] +@[2, 0, 1] +@[2, 1, 0] +@[2, 0, 1] +@[1, 2, 0] +@[1, 0, 2] +@[0, 2, 1] +@[0, 1, 2]''' +""" +import algorithm + +var v = @[0, 1, 2] +while v.nextPermutation(): + echo v +while v.prevPermutation(): + echo v diff --git a/tests/stdlib/tstrutil.nim b/tests/stdlib/tstrutil.nim index da65d1f89..3db484faa 100644 --- a/tests/stdlib/tstrutil.nim +++ b/tests/stdlib/tstrutil.nim @@ -2,18 +2,18 @@ discard """ file: "tstrutil.nim" output: "ha/home/a1xyz/usr/bin" """ -# test the new strutils module - -import - strutils - -proc testStrip() = - write(stdout, strip(" ha ")) - -proc main() = - testStrip() - for p in split("/home/a1:xyz:/usr/bin", {':'}): - write(stdout, p) +# test the new strutils module + +import + strutils + +proc testStrip() = + write(stdout, strip(" ha ")) + +proc main() = + testStrip() + for p in split("/home/a1:xyz:/usr/bin", {':'}): + write(stdout, p) proc testDelete = var s = "0123456789ABCDEFGH" @@ -25,25 +25,34 @@ proc testDelete = assert s == "1236789ABCDEFG" testDelete() - + assert(insertSep($1000_000) == "1_000_000") assert(insertSep($232) == "232") assert(insertSep($12345, ',') == "12,345") assert(insertSep($0) == "0") - -assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0) -assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1) -assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5) -assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3) -assert(editDistance("prefix__hallo_suffix", "prefix") == 14) -assert(editDistance("prefix__hallo_suffix", "suffix") == 14) -assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2) + +assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0) +assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1) +assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5) +assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3) +assert(editDistance("prefix__hallo_suffix", "prefix") == 14) +assert(editDistance("prefix__hallo_suffix", "suffix") == 14) +assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2) assert "/1/2/3".rfind('/') == 4 assert "/1/2/3".rfind('/', 1) == 0 assert "/1/2/3".rfind('0') == -1 - -main() -#OUT ha/home/a1xyz/usr/bin +assert(toHex(100i16, 32) == "00000000000000000000000000000064") +assert(toHex(-100i16, 32) == "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C") + +assert(' '.repeat(8)== " ") +assert(" ".repeat(8) == " ") +assert(spaces(8) == " ") + +assert(' '.repeat(0) == "") +assert(" ".repeat(0) == "") +assert(spaces(0) == "") +main() +#OUT ha/home/a1xyz/usr/bin diff --git a/tests/table/ttables.nim b/tests/table/ttables.nim deleted file mode 100644 index de4aaed5e..000000000 --- a/tests/table/ttables.nim +++ /dev/null @@ -1,128 +0,0 @@ -discard """ - output: '''true''' -""" - -import hashes, tables - -const - data = { - "34": 123456, "12": 789, - "90": 343, "0": 34404, - "1": 344004, "2": 344774, - "3": 342244, "4": 3412344, - "5": 341232144, "6": 34214544, - "7": 3434544, "8": 344544, - "9": 34435644, "---00": 346677844, - "10": 34484, "11": 34474, "19": 34464, - "20": 34454, "30": 34141244, "40": 344114, - "50": 344490, "60": 344491, "70": 344492, - "80": 344497} - - sorteddata = { - "---00": 346677844, - "0": 34404, - "1": 344004, - "10": 34484, - "11": 34474, - "12": 789, - "19": 34464, - "2": 344774, "20": 34454, - "3": 342244, "30": 34141244, - "34": 123456, - "4": 3412344, "40": 344114, - "5": 341232144, "50": 344490, - "6": 34214544, "60": 344491, - "7": 3434544, "70": 344492, - "8": 344544, "80": 344497, - "9": 34435644, - "90": 343} - -block tableTest1: - var t = initTable[tuple[x, y: int], string]() - t[(0,0)] = "00" - t[(1,0)] = "10" - t[(0,1)] = "01" - t[(1,1)] = "11" - for x in 0..1: - for y in 0..1: - assert t[(x,y)] == $x & $y - assert($t == - "{(x: 0, y: 0): 00, (x: 0, y: 1): 01, (x: 1, y: 0): 10, (x: 1, y: 1): 11}") - -block tableTest2: - var t = initTable[string, float]() - t["test"] = 1.2345 - t["111"] = 1.000043 - t["123"] = 1.23 - t.del("111") - - t["012"] = 67.9 - t["123"] = 1.5 # test overwriting - - assert t["123"] == 1.5 - assert t["111"] == 0.0 # deleted - assert(not hasKey(t, "111")) - - for key, val in items(data): t[key] = val.toFloat - for key, val in items(data): assert t[key] == val.toFloat - - -block orderedTableTest1: - var t = initOrderedTable[string, int](2) - for key, val in items(data): t[key] = val - for key, val in items(data): assert t[key] == val - var i = 0 - # `pairs` needs to yield in insertion order: - for key, val in pairs(t): - assert key == data[i][0] - assert val == data[i][1] - inc(i) - - for key, val in mpairs(t): val = 99 - for val in mvalues(t): assert val == 99 - -block countTableTest1: - var s = data.toTable - var t = initCountTable[string]() - for k in s.keys: t.inc(k) - for k in t.keys: assert t[k] == 1 - t.inc("90", 3) - t.inc("12", 2) - t.inc("34", 1) - assert t.largest()[0] == "90" - - t.sort() - var i = 0 - for k, v in t.pairs: - case i - of 0: assert k == "90" and v == 4 - of 1: assert k == "12" and v == 3 - of 2: assert k == "34" and v == 2 - else: break - inc i - -block SyntaxTest: - var x = toTable[int, string]({:}) - -proc orderedTableSortTest() = - var t = initOrderedTable[string, int](2) - for key, val in items(data): t[key] = val - for key, val in items(data): assert t[key] == val - t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key)) - var i = 0 - # `pairs` needs to yield in sorted order: - for key, val in pairs(t): - doAssert key == sorteddata[i][0] - doAssert val == sorteddata[i][1] - inc(i) - - # check that lookup still works: - for key, val in pairs(t): - doAssert val == t[key] - # check that insert still works: - t["newKeyHere"] = 80 - - -orderedTableSortTest() -echo "true" - diff --git a/tests/template/t2do.nim b/tests/template/t2do.nim new file mode 100644 index 000000000..b87e3328c --- /dev/null +++ b/tests/template/t2do.nim @@ -0,0 +1,22 @@ +discard """ + output: "8.0" +""" + +# bug #2057 + +proc mpf_get_d(x: int): float = float(x) +proc mpf_cmp_d(a: int; b: float): int = 0 + +template toFloatHelper(result: expr; tooSmall, tooLarge: stmt) {.immediate.} = + result = mpf_get_d(a) + if result == 0.0 and mpf_cmp_d(a,0.0) != 0: + tooSmall + if result == Inf: + tooLarge + +proc toFloat*(a: int): float = + toFloatHelper(result) + do: raise newException(ValueError, "number too small"): + raise newException(ValueError, "number too large") + +echo toFloat(8) diff --git a/tests/template/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim index 4178812af..6c4413866 100644 --- a/tests/template/tparams_gensymed.nim +++ b/tests/template/tparams_gensymed.nim @@ -12,3 +12,51 @@ template genNodeKind(kind, name: expr): stmt = result.add(c) genNodeKind(nnkNone, None) + + +# Test that generics in templates still work (regression to fix #1915) + +# bug #2004 + +type Something = object + +proc testA(x: Something) = discard + +template def(name: expr) {.immediate.} = + proc testB[T](reallyUniqueName: T) = + `test name`(reallyUniqueName) +def A + +var x: Something +testB(x) + + +# bug #2215 +# Test that templates in generics still work (regression to fix the +# regression...) + +template forStatic(index: expr, slice: Slice[int], predicate: stmt): + stmt {.immediate.} = + const a = slice.a + const b = slice.b + when a <= b: + template iteration(i: int) = + block: + const index = i + predicate + template iterateStartingFrom(i: int): stmt = + when i <= b: + iteration i + iterateStartingFrom i + 1 + iterateStartingFrom a + +proc concreteProc(x: int) = + forStatic i, 0..3: + echo i + +proc genericProc(x: any) = + forStatic i, 0..3: + echo i + +concreteProc(7) # This works +genericProc(7) # This doesn't compile diff --git a/tests/template/tscope.nim b/tests/template/tscope.nim new file mode 100644 index 000000000..2d5841af3 --- /dev/null +++ b/tests/template/tscope.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "redefinition of 'x'" +""" + +var x = 1 +template quantity(): stmt {.immediate.} = + # Causes internal error in compiler/sem.nim + proc unit*(x = 1.0): float = 12 + # Throws the correct error: redefinition of 'x' + #proc unit*(y = 1.0): float = 12 +quantity() +var x = 2 diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 5cd5c1545..ab1e46d6f 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -120,7 +120,8 @@ proc gcTests(r: var TResults, cat: Category, options: string) = " --gc:markAndSweep", cat, actionRun) testSpec r, makeTest("tests/gc" / filename, options & " -d:release --gc:markAndSweep", cat, actionRun) - + + test "growobjcrash" test "gcbench" test "gcleak" test "gcleak2" @@ -229,17 +230,17 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) = else: testNoSpec r, makeTest(test, options, cat, actionCompile) -# ----------------------------- babel ---------------------------------------- +# ----------------------------- nimble ---------------------------------------- type PackageFilter = enum pfCoreOnly pfExtraOnly pfAll let - babelExe = findExe("babel") - babelDir = getHomeDir() / ".babel" - packageDir = babelDir / "pkgs" - packageIndex = babelDir / "packages.json" + nimbleExe = findExe("nimble") + nimbleDir = getHomeDir() / ".nimble" + packageDir = nimbleDir / "pkgs" + packageIndex = nimbleDir / "packages.json" proc waitForExitEx(p: Process): int = var outp = outputStream(p) @@ -254,7 +255,7 @@ proc waitForExitEx(p: Process): int = proc getPackageDir(package: string): string = ## TODO - Replace this with dom's version comparison magic. - var commandOutput = execCmdEx("babel path $#" % package) + var commandOutput = execCmdEx("nimble path $#" % package) if commandOutput.exitCode != QuitSuccess: return "" else: @@ -267,7 +268,7 @@ iterator listPackages(filter: PackageFilter): tuple[name, url: string] = let name = package["name"].str url = package["url"].str - isCorePackage = "nimrod-code" in normalize(url) + isCorePackage = "nim-lang" in normalize(url) case filter: of pfCoreOnly: if isCorePackage: @@ -278,13 +279,13 @@ iterator listPackages(filter: PackageFilter): tuple[name, url: string] = of pfAll: yield (name, url) -proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = - if babelExe == "": - echo("[Warning] - Cannot run babel tests: Babel binary not found.") +proc testNimblePackages(r: var TResults, cat: Category, filter: PackageFilter) = + if nimbleExe == "": + echo("[Warning] - Cannot run nimble tests: Nimble binary not found.") return - if execCmd("$# update" % babelExe) == QuitFailure: - echo("[Warning] - Cannot run babel tests: Babel update failed.") + if execCmd("$# update" % nimbleExe) == QuitFailure: + echo("[Warning] - Cannot run nimble tests: Nimble update failed.") return let packageFileTest = makeTest("PackageFileParsed", "", cat) @@ -293,7 +294,7 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = var test = makeTest(name, "", cat) echo(url) let - installProcess = startProcess(babelExe, "", ["install", "-y", name]) + installProcess = startProcess(nimbleExe, "", ["install", "-y", name]) installStatus = waitForExitEx(installProcess) installProcess.close if installStatus != QuitSuccess: @@ -303,7 +304,7 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = let buildPath = getPackageDir(name)[0.. -3] let - buildProcess = startProcess(babelExe, buildPath, ["build"]) + buildProcess = startProcess(nimbleExe, buildPath, ["build"]) buildStatus = waitForExitEx(buildProcess) buildProcess.close if buildStatus != QuitSuccess: @@ -311,13 +312,13 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = r.addResult(test, "", "", reSuccess) r.addResult(packageFileTest, "", "", reSuccess) except JsonParsingError: - echo("[Warning] - Cannot run babel tests: Invalid package file.") + echo("[Warning] - Cannot run nimble tests: Invalid package file.") r.addResult(packageFileTest, "", "", reBuildFailed) # ---------------------------------------------------------------------------- -const AdditionalCategories = ["debugger", "examples", "lib", "babel-core"] +const AdditionalCategories = ["debugger", "examples", "lib", "nimble-core"] proc `&.?`(a, b: string): string = # candidate for the stdlib? @@ -330,8 +331,9 @@ proc `&?.`(a, b: string): string = proc processCategory(r: var TResults, cat: Category, options: string) = case cat.string.normalize of "rodfiles": - compileRodFiles(r, cat, options) - runRodFiles(r, cat, options) + discard # Disabled for now + #compileRodFiles(r, cat, options) + #runRodFiles(r, cat, options) of "js": # XXX JS doesn't need to be special anymore jsTests(r, cat, options) @@ -354,12 +356,12 @@ proc processCategory(r: var TResults, cat: Category, options: string) = compileExample(r, "examples/*.nim", options, cat) compileExample(r, "examples/gtk/*.nim", options, cat) compileExample(r, "examples/talk/*.nim", options, cat) - of "babel-core": - testBabelPackages(r, cat, pfCoreOnly) - of "babel-extra": - testBabelPackages(r, cat, pfExtraOnly) - of "babel-all": - testBabelPackages(r, cat, pfAll) + of "nimble-core": + testNimblePackages(r, cat, pfCoreOnly) + of "nimble-extra": + testNimblePackages(r, cat, pfExtraOnly) + of "nimble-all": + testNimblePackages(r, cat, pfAll) else: for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"): testSpec r, makeTest(name, options, cat) diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim index e079eed62..2a8a4ea24 100644 --- a/tests/testament/specs.nim +++ b/tests/testament/specs.nim @@ -48,6 +48,7 @@ type err*: TResultEnum substr*, sortoutput*: bool targets*: set[TTarget] + nimout*: string const targetToExt*: array[TTarget, string] = ["c", "cpp", "m", "js"] @@ -94,6 +95,7 @@ proc parseSpec*(filename: string): TSpec = result.file = filename result.msg = "" result.outp = "" + result.nimout = "" result.ccodeCheck = "" result.cmd = cmdTemplate parseSpecAux: @@ -124,6 +126,8 @@ proc parseSpec*(filename: string): TSpec = of "errormsg": result.msg = e.value result.action = actionReject + of "nimout": + result.nimout = e.value of "disabled": if parseCfgBool(e.value): result.err = reIgnored of "cmd": result.cmd = e.value diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index 865ba9c75..881a41ce6 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -64,7 +64,9 @@ proc callCompiler(cmdTemplate, filename, options: string, var suc = "" var err = "" var x = newStringOfCap(120) + result.nimout = "" while outp.readLine(x.TaintedString) or running(p): + result.nimout.add(x & "\n") if x =~ pegOfInterest: # `err` should contain the last error/warning message err = x @@ -112,7 +114,9 @@ proc addResult(r: var TResults, test: TTest, expected = expected, given = given) r.data.addf("$#\t$#\t$#\t$#", name, expected, given, $success) - if success notin {reSuccess, reIgnored}: + if success == reIgnored: + styledEcho styleBright, name, fgYellow, " [", $success, "]" + elif success != reSuccess: styledEcho styleBright, name, fgRed, " [", $success, "]" echo"Expected:" styledEcho styleBright, expected @@ -134,7 +138,7 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) = proc generatedFile(path, name: string, target: TTarget): string = let ext = targetToExt[target] result = path / "nimcache" / - (if target == targetJS: path.splitPath.tail & "_" else: "") & + (if target == targetJS: path.splitPath.tail & "_" else: "compiler_") & name.changeFileExt(ext) proc codegenCheck(test: TTest, check: string, given: var TSpec) = @@ -151,6 +155,13 @@ proc codegenCheck(test: TTest, check: string, given: var TSpec) = except IOError: given.err = reCodeNotFound +proc nimoutCheck(test: TTest; expectedNimout: string; given: var TSpec) = + if expectedNimout.len > 0: + let exp = expectedNimout.strip.replace("\C\L", "\L") + let giv = given.nimout.strip.replace("\C\L", "\L") + if exp notin giv: + given.err = reMsgsDiffer + proc makeDeterministic(s: string): string = var x = splitLines(s) sort(x, system.cmp) @@ -172,6 +183,7 @@ proc testSpec(r: var TResults, test: TTest) = test.target) if given.err == reSuccess: codegenCheck(test, expected.ccodeCheck, given) + nimoutCheck(test, expected.nimout, given) r.addResult(test, "", given.msg, given.err) if given.err == reSuccess: inc(r.passed) of actionRun: @@ -205,6 +217,7 @@ proc testSpec(r: var TResults, test: TTest) = given.err = reOutputsDiffer if given.err == reSuccess: codeGenCheck(test, expected.ccodeCheck, given) + nimoutCheck(test, expected.nimout, given) if given.err == reSuccess: inc(r.passed) r.addResult(test, expected.outp, buf.string, given.err) else: diff --git a/tests/trmacros/tor.nim b/tests/trmacros/tor.nim index dc72a96cd..500851582 100644 --- a/tests/trmacros/tor.nim +++ b/tests/trmacros/tor.nim @@ -1,5 +1,5 @@ discard """ - output: '''3060 + output: '''3030 true 3''' """ diff --git a/tests/tuples/tgeneric_tuple.nim b/tests/tuples/tgeneric_tuple.nim new file mode 100644 index 000000000..32f081596 --- /dev/null +++ b/tests/tuples/tgeneric_tuple.nim @@ -0,0 +1,9 @@ +# bug #2121 + +type + Item[K,V] = tuple + key: K + value: V + +var q = newseq[Item[int,int]](0) +let (x,y) = q[0] diff --git a/tests/types/tauto_canbe_void.nim b/tests/types/tauto_canbe_void.nim new file mode 100644 index 000000000..60e83c510 --- /dev/null +++ b/tests/types/tauto_canbe_void.nim @@ -0,0 +1,9 @@ + +import future + +template tempo(s: expr) = + s("arg") + +tempo((s: string)->auto => echo(s)) +tempo((s: string) => echo(s)) + diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim index f8d22bdb8..2b07ba679 100644 --- a/tests/types/temptyseqs.nim +++ b/tests/types/temptyseqs.nim @@ -5,7 +5,7 @@ discard """ # bug #1708 let foo = { "1" : (bar: @["1"]), - "2" : (baz: @[]) + "2" : (bar: @[]) } # bug #871 diff --git a/tests/types/tforwty2.nim b/tests/types/tforwty2.nim index d103314c5..52af1c7dd 100644 --- a/tests/types/tforwty2.nim +++ b/tests/types/tforwty2.nim @@ -1,5 +1,5 @@ # Test for a hard to fix internal error -# occured in the SDL library +# occurred in the SDL library {.push dynlib: "SDL.dll", callconv: cdecl.} diff --git a/tests/vm/tconsttable.nim b/tests/vm/tconsttable.nim new file mode 100644 index 000000000..64a74a59d --- /dev/null +++ b/tests/vm/tconsttable.nim @@ -0,0 +1,19 @@ +discard """ + output: '''is +finally +nice!''' +""" + +import tables + +const + foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable() + +# protect against overly smart compiler: +var x = "this" + +echo foo[x] +x = "ah" +echo foo[x] +x = "possible." +echo foo[x] diff --git a/tinyc/arm-gen.c b/tinyc/arm-gen.c index 42feecf73..050a8ad88 100644 --- a/tinyc/arm-gen.c +++ b/tinyc/arm-gen.c @@ -1506,7 +1506,7 @@ void gen_opf(int op) case TOK_UGE: case TOK_ULE: case TOK_UGT: - error("unsigned comparision on floats?"); + error("unsigned comparison on floats?"); break; case TOK_LT: op=TOK_Nset; diff --git a/tinyc/c67-gen.c b/tinyc/c67-gen.c index 04f8a12b7..77c68a279 100644 --- a/tinyc/c67-gen.c +++ b/tinyc/c67-gen.c @@ -235,7 +235,7 @@ void gsym(int t) } // these are regs that tcc doesn't really know about, -// but asign them unique values so the mapping routines +// but assign them unique values so the mapping routines // can distinquish them #define C67_A0 105 diff --git a/tinyc/i386-asm.c b/tinyc/i386-asm.c index 21b28d7a0..12ff8f2ba 100644 --- a/tinyc/i386-asm.c +++ b/tinyc/i386-asm.c @@ -1105,7 +1105,7 @@ static void subst_asm_operand(CString *add_str, } } -/* generate prolog and epilog code for asm statment */ +/* generate prolog and epilog code for asm statement */ static void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, diff --git a/tinyc/lib/bcheck.c b/tinyc/lib/bcheck.c index 0ec2a4b47..c59d04eb8 100644 --- a/tinyc/lib/bcheck.c +++ b/tinyc/lib/bcheck.c @@ -628,7 +628,7 @@ int __bound_delete_region(void *p) } /* return the size of the region starting at p, or EMPTY_SIZE if non - existant region. */ + existent region. */ static unsigned long get_region_size(void *p) { unsigned long addr = (unsigned long)p; diff --git a/tinyc/tcc-doc.html b/tinyc/tcc-doc.html index e40532ed0..bd856d256 100644 --- a/tinyc/tcc-doc.html +++ b/tinyc/tcc-doc.html @@ -927,7 +927,7 @@ They can be defined several times in the same source. Use 'b' </tr></table> <h2 class="section"> 4.4 Directives </h2> -<p>All directives are preceeded by a '.'. The following directives are +<p>All directives are preceded by a '.'. The following directives are supported: </p> <ul class="toc"> @@ -1365,7 +1365,7 @@ reverse order, a first pass is done to reverse the argument order. </tr></table> <h2 class="section"> 8.4 Types </h2> -<p>The types are stored in a single 'int' variable. It was choosen in the +<p>The types are stored in a single 'int' variable. It was chosen in the first stages of development when tcc was much simpler. Now, it may not be the best solution. </p> @@ -1531,7 +1531,7 @@ current position in the code section. </dd> <dt> <code>stab_section</code></dt> <dt> <code>stabstr_section</code></dt> -<dd><p>are used when debugging is actived to store debug information +<dd><p>are used when debugging is activated to store debug information </p> </dd> <dt> <code>symtab_section</code></dt> diff --git a/tinyc/tcc-doc.texi b/tinyc/tcc-doc.texi index 7cc61bbdb..47a8c8b00 100644 --- a/tinyc/tcc-doc.texi +++ b/tinyc/tcc-doc.texi @@ -673,7 +673,7 @@ They can be defined several times in the same source. Use 'b' @cindex asciz directive @cindex ascii directive -All directives are preceeded by a '.'. The following directives are +All directives are preceded by a '.'. The following directives are supported: @itemize @@ -892,7 +892,7 @@ reverse order, a first pass is done to reverse the argument order. @section Types -The types are stored in a single 'int' variable. It was choosen in the +The types are stored in a single 'int' variable. It was chosen in the first stages of development when tcc was much simpler. Now, it may not be the best solution. @@ -1017,7 +1017,7 @@ are used when bound checking is activated @item stab_section @itemx stabstr_section -are used when debugging is actived to store debug information +are used when debugging is activated to store debug information @item symtab_section @itemx strtab_section diff --git a/tinyc/tccasm.c b/tinyc/tccasm.c index 8834b53fb..9b5289f77 100644 --- a/tinyc/tccasm.c +++ b/tinyc/tccasm.c @@ -229,7 +229,7 @@ static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) } else { goto cannot_relocate; } - pe->sym = NULL; /* same symbols can be substracted to NULL */ + pe->sym = NULL; /* same symbols can be subtracted to NULL */ } else { cannot_relocate: error("invalid operation with label"); diff --git a/tinyc/tccgen.c b/tinyc/tccgen.c index 3135e7b37..a88f32819 100644 --- a/tinyc/tccgen.c +++ b/tinyc/tccgen.c @@ -1203,7 +1203,7 @@ static inline int is_integer_btype(int bt) bt == VT_INT || bt == VT_LLONG); } -/* check types for comparison or substraction of pointers */ +/* check types for comparison or subtraction of pointers */ static void check_comparison_pointer_types(SValue *p1, SValue *p2, int op) { CType *type1, *type2, tmp_type1, tmp_type2; @@ -4686,7 +4686,7 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, if (sym->type.t & VT_EXTERN) { /* if the variable is extern, it was not allocated */ sym->type.t &= ~VT_EXTERN; - /* set array size if it was ommited in extern + /* set array size if it was omitted in extern declaration */ if ((sym->type.t & VT_ARRAY) && sym->type.ref->c < 0 && diff --git a/tinyc/tcctok.h b/tinyc/tcctok.h index 6dc477821..2be032fa4 100644 --- a/tinyc/tcctok.h +++ b/tinyc/tcctok.h @@ -422,7 +422,7 @@ DEF_FP(mul) DEF_ASM(fcom) - DEF_ASM(fcom_1) /* non existant op, just to have a regular table */ + DEF_ASM(fcom_1) /* non existent op, just to have a regular table */ DEF_FP1(com) DEF_FP(comp) diff --git a/tinyc/win32/include/fcntl.h b/tinyc/win32/include/fcntl.h index 32f4a90e8..d31bc84d5 100644 --- a/tinyc/win32/include/fcntl.h +++ b/tinyc/win32/include/fcntl.h @@ -50,7 +50,7 @@ #define _O_RANDOM 0x0010 #define _O_SEQUENTIAL 0x0020 -#define _O_TEMPORARY 0x0040 /* Make the file dissappear after closing. +#define _O_TEMPORARY 0x0040 /* Make the file disappear after closing. * WARNING: Even if not created by _open! */ #define _O_NOINHERIT 0x0080 diff --git a/todo.txt b/todo.txt index d64f4fdd4..1d180f737 100644 --- a/todo.txt +++ b/todo.txt @@ -1,11 +1,22 @@ -version 0.10 -============ +version 0.10.4 +============== +- improve GC-unsafety warnings +- make 'nil' work for 'add' and 'len' +- get rid of 'mget'; aka priority of 'var' needs to be 'var{lvalue}' +- 'result' shadowing warning +- disallow negative indexing +- improve the parser; deal with echo $foo gotcha + + +version 1.0 +=========== + +- figure out why C++ bootstrapping is so much slower - nimsuggest: auto-completion needs to work in 'class' macros - improve the docs for inheritance - The bitwise 'not' operator will be renamed to 'bnot' to prevent 'not 4 == 5' from compiling. -> requires 'mixin' annotation for procs! -- parameter lists without type end up in 'experimental' - iterators always require a return type - overloading of '=' @@ -25,7 +36,6 @@ Low priority: - support for exception propagation? (hard to implement) - the copying of the 'ref Promise' into the thead local storage only happens to work due to the write barrier's implementation -- clean up the C code generator. Full of cruft. Misc @@ -35,7 +45,6 @@ Misc - make tuple unpacking work in a non-var/let context - built-in 'getImpl' - prevent 'alloc(TypeWithGCedMemory)' -- some table related tests are wrong (memory usage checks) Bugs @@ -59,7 +68,6 @@ version 0.9.x - memory manager: add a measure of fragmentation - implement 'bits' pragmas - we need a magic thisModule symbol -- ensure (ref T)(a, b) works as a type conversion and type constructor - optimize 'genericReset'; 'newException' leads to code bloat - The 'do' notation might be trimmed so that its only purpose is to pass multiple multi line constructs to a macro. @@ -69,9 +77,7 @@ version 0.9.X ============= - macros as type pragmas -- implement type API for macros -- lazy overloading resolution: - * special case ``tyStmt`` +- document how lazy overloading resolution works - document NimMain and check whether it works for threading GC @@ -88,4 +94,3 @@ CGEN ==== - codegen should use "NIM_CAST" macro and respect aliasing rules for GCC - ``restrict`` pragma + backend support -- 'const' objects including case objects diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index a38f2a88f..aeae86300 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -24,7 +24,7 @@ Options: --re pattern is a regular expression (default); extended syntax for the regular expression is always turned on --recursive process directories recursively - --confirm confirm each occurence/replacement; there is a chance + --confirm confirm each occurrence/replacement; there is a chance to abort any time without touching the file --stdin read pattern from stdin (to avoid the shell's confusing quoting rules) diff --git a/tools/niminst/buildbat.tmpl b/tools/niminst/buildbat.tmpl index 415574273..3a11715bf 100644 --- a/tools/niminst/buildbat.tmpl +++ b/tools/niminst/buildbat.tmpl @@ -1,5 +1,5 @@ #! stdtmpl(subsChar='?') | standard -#proc generateBuildBatchScript(c: TConfigData, winIndex, cpuIndex: int): string = +#proc generateBuildBatchScript(c: ConfigData, winIndex, cpuIndex: int): string = # result = "@echo off\nREM Generated by niminst\n" SET CC=gcc SET LINKER=gcc diff --git a/tools/niminst/buildsh.tmpl b/tools/niminst/buildsh.tmpl index d9508f515..191c39282 100644 --- a/tools/niminst/buildsh.tmpl +++ b/tools/niminst/buildsh.tmpl @@ -1,5 +1,5 @@ #! stdtmpl(subsChar='?') | standard -#proc generateBuildShellScript(c: TConfigData): string = +#proc generateBuildShellScript(c: ConfigData): string = # result = "#! /bin/sh\n# Generated from niminst\n" & # "# Template is in tools/buildsh.tmpl\n" & # "# To regenerate run ``niminst csource`` or ``koch csource``\n" diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim index 574f7ea6b..bbd997981 100644 --- a/tools/niminst/debcreation.nim +++ b/tools/niminst/debcreation.nim @@ -84,7 +84,7 @@ proc createCopyright(pkgName, mtnName, mtnEmail, version: string, addN("Files: " & f) addN("License: " & license) -proc formatDateTime(t: TTimeInfo, timezone: string): string = +proc formatDateTime(t: TimeInfo, timezone: string): string = var day = ($t.weekday)[0..2] & ", " return "$1$2 $3 $4 $5:$6:$7 $8" % [day, intToStr(t.monthday, 2), diff --git a/tools/niminst/deinstall.tmpl b/tools/niminst/deinstall.tmpl index 15f912af6..c4717a257 100644 --- a/tools/niminst/deinstall.tmpl +++ b/tools/niminst/deinstall.tmpl @@ -1,5 +1,5 @@ #! stdtmpl(subsChar='?') | standard -#proc generateDeinstallScript(c: TConfigData): string = +#proc generateDeinstallScript(c: ConfigData): string = # result = "#! /bin/sh\n# Generated by niminst\n" # var proj = c.name.toLower diff --git a/tools/niminst/inno.tmpl b/tools/niminst/inno.tmpl index 3460c22a2..4acf0557c 100644 --- a/tools/niminst/inno.tmpl +++ b/tools/niminst/inno.tmpl @@ -1,5 +1,5 @@ #! stdtmpl | standard -#proc generateInnoSetup(c: TConfigData): string = +#proc generateInnoSetup(c: ConfigData): string = # result = "" ; Default Template for NimInst [Setup] @@ -19,7 +19,7 @@ ChangesEnvironment=yes Name: english; MessagesFile: compiler:Default.isl [Files] - #for i in low(TFileCategory)..fcWindows: + #for i in low(FileCategory)..fcWindows: # for f in items(c.cat[i]): Source: ${expandFilename(f).toWin}; DestDir: {app}\${splitFile(f).dir.toWin}; Flags: ignoreversion # end for diff --git a/tools/niminst/install.tmpl b/tools/niminst/install.tmpl index 437e13dfb..3ec42c287 100644 --- a/tools/niminst/install.tmpl +++ b/tools/niminst/install.tmpl @@ -1,5 +1,5 @@ #! stdtmpl(subsChar = '?') | standard -#proc generateInstallScript(c: TConfigData): string = +#proc generateInstallScript(c: ConfigData): string = # result = "#! /bin/sh\n# Generated by niminst\n" # var proj = c.name.toLower diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index c9eb9f89c..357c1ffbc 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -26,8 +26,8 @@ const deinstallShFile = "deinstall.sh" type - TAppType = enum appConsole, appGUI - TAction = enum + AppType = enum appConsole, appGUI + Action = enum actionNone, # action not yet known actionCSource # action: create C sources actionInno, # action: create Inno Setup installer @@ -36,7 +36,7 @@ type actionZip, # action: create zip file actionDeb # action: prepare deb package - TFileCategory = enum + FileCategory = enum fcWinBin, # binaries for Windows fcConfig, # configuration files fcData, # data files @@ -48,9 +48,9 @@ type fcUnixBin, # binaries for Unix fcDocStart # links to documentation for Windows installer - TConfigData = object of TObject - actions: set[TAction] - cat: array[TFileCategory, seq[string]] + ConfigData = object of RootObj + actions: set[Action] + cat: array[FileCategory, seq[string]] binPaths, authors, oses, cpus, downloads: seq[string] cfiles: array[1..maxOS, array[1..maxCPU, seq[string]]] platforms: array[1..maxOS, array[1..maxCPU, bool]] @@ -59,8 +59,8 @@ type libpath: string innoSetupFlag, installScript, uninstallScript: bool explicitPlatforms: bool - vars: PStringTable - app: TAppType + vars: StringTableRef + app: AppType nimArgs: string debOpts: TDebOptions @@ -69,9 +69,9 @@ const "$configdir", "$datadir", "$docdir", "$libdir" ] -proc initConfigData(c: var TConfigData) = +proc iniConfigData(c: var ConfigData) = c.actions = {} - for i in low(TFileCategory)..high(TFileCategory): c.cat[i] = @[] + for i in low(FileCategory)..high(FileCategory): c.cat[i] = @[] c.binPaths = @[] c.authors = @[] c.oses = @[] @@ -100,7 +100,7 @@ proc initConfigData(c: var TConfigData) = c.debOpts.shortDesc = "" c.debOpts.licenses = @[] -proc firstBinPath(c: TConfigData): string = +proc firstBinPath(c: ConfigData): string = if c.binPaths.len > 0: result = c.binPaths[0] else: result = "" @@ -151,7 +151,7 @@ Compile_options: will be passed to the Nim compiler """ -proc parseCmdLine(c: var TConfigData) = +proc parseCmdLine(c: var ConfigData) = var p = initOptParser() while true: next(p) @@ -209,19 +209,19 @@ proc addFiles(s: var seq[string], patterns: seq[string]) = inc(i) if i == 0: echo("[Warning] No file found that matches: " & p) -proc pathFlags(p: var TCfgParser, k, v: string, +proc pathFlags(p: var CfgParser, k, v: string, t: var tuple[path, flags: string]) = case normalize(k) of "path": t.path = v of "flags": t.flags = v else: quit(errorStr(p, "unknown variable: " & k)) -proc filesOnly(p: var TCfgParser, k, v: string, dest: var seq[string]) = +proc filesOnly(p: var CfgParser, k, v: string, dest: var seq[string]) = case normalize(k) of "files": addFiles(dest, split(v, {';'})) else: quit(errorStr(p, "unknown variable: " & k)) -proc yesno(p: var TCfgParser, v: string): bool = +proc yesno(p: var CfgParser, v: string): bool = case normalize(v) of "yes", "y", "on", "true": result = true @@ -235,7 +235,7 @@ proc incl(s: var seq[string], x: string): int = s.add(x) result = s.len-1 -proc platforms(c: var TConfigData, v: string) = +proc platforms(c: var ConfigData, v: string) = for line in splitLines(v): let p = line.find(": ") if p <= 1: continue @@ -246,9 +246,9 @@ proc platforms(c: var TConfigData, v: string) = let cpuIdx = c.cpus.incl(cpu) c.platforms[c.oses.len][cpuIdx+1] = true -proc parseIniFile(c: var TConfigData) = +proc parseIniFile(c: var ConfigData) = var - p: TCfgParser + p: CfgParser section = "" hasCpuOs = false var input = newFileStream(c.infile, fmRead) @@ -365,8 +365,8 @@ proc parseIniFile(c: var TConfigData) = # ------------------------- generate source based installation --------------- -proc readCFiles(c: var TConfigData, osA, cpuA: int) = - var p: TCfgParser +proc readCFiles(c: var ConfigData, osA, cpuA: int) = + var p: CfgParser var f = splitFile(c.infile).dir / "mapping.txt" c.cfiles[osA][cpuA] = @[] var input = newFileStream(f, fmRead) @@ -402,11 +402,11 @@ proc readCFiles(c: var TConfigData, osA, cpuA: int) = proc buildDir(os, cpu: int): string = return "c_code" / ($os & "_" & $cpu) -proc getOutputDir(c: var TConfigData): string = +proc getOutputDir(c: var ConfigData): string = if c.outdir.len > 0: c.outdir else: "build" proc writeFile(filename, content, newline: string) = - var f: TFile + var f: File if open(f, filename, fmWrite): for x in splitLines(content): write(f, x) @@ -415,7 +415,7 @@ proc writeFile(filename, content, newline: string) = else: quit("Cannot open for writing: " & filename) -proc removeDuplicateFiles(c: var TConfigData) = +proc removeDuplicateFiles(c: var ConfigData) = for osA in countdown(c.oses.len, 1): for cpuA in countdown(c.cpus.len, 1): if c.cfiles[osA][cpuA].isNil: c.cfiles[osA][cpuA] = @[] @@ -433,13 +433,13 @@ proc removeDuplicateFiles(c: var TConfigData) = removeFile(dup) c.cfiles[osA][cpuA][i] = orig -proc writeInstallScripts(c: var TConfigData) = +proc writeInstallScripts(c: var ConfigData) = if c.installScript: writeFile(installShFile, generateInstallScript(c), "\10") if c.uninstallScript: writeFile(deinstallShFile, generateDeinstallScript(c), "\10") -proc srcdist(c: var TConfigData) = +proc srcdist(c: var ConfigData) = if not existsDir(getOutputDir(c) / "c_code"): createDir(getOutputDir(c) / "c_code") for x in walkFiles(c.libpath / "lib/*.h"): @@ -486,7 +486,7 @@ proc srcdist(c: var TConfigData) = writeInstallScripts(c) # --------------------- generate inno setup ----------------------------------- -proc setupDist(c: var TConfigData) = +proc setupDist(c: var ConfigData) = let scrpt = generateInnoSetup(c) let n = "build" / "install_$#_$#.iss" % [toLower(c.name), c.version] writeFile(n, scrpt, "\13\10") @@ -503,7 +503,7 @@ proc setupDist(c: var TConfigData) = quit("External program failed") # --------------------- generate NSIS setup ----------------------------------- -proc setupDist2(c: var TConfigData) = +proc setupDist2(c: var ConfigData) = let scrpt = generateNsisSetup(c) let n = "build" / "install_$#_$#.nsi" % [toLower(c.name), c.version] writeFile(n, scrpt, "\13\10") @@ -521,7 +521,7 @@ proc setupDist2(c: var TConfigData) = # ------------------ generate ZIP file --------------------------------------- when haveZipLib: - proc zipDist(c: var TConfigData) = + proc zipDist(c: var ConfigData) = var proj = toLower(c.name) & "-" & c.version var n = "$#.zip" % proj if c.outdir.len == 0: n = "build" / n @@ -549,7 +549,7 @@ when haveZipLib: # -- prepare build files for .deb creation -proc debDist(c: var TConfigData) = +proc debDist(c: var ConfigData) = if not existsFile(getOutputDir(c) / "build.sh"): quit("No build.sh found.") if not existsFile(getOutputDir(c) / "install.sh"): quit("No install.sh found.") @@ -595,8 +595,8 @@ proc debDist(c: var TConfigData) = # ------------------- main ---------------------------------------------------- -var c: TConfigData -initConfigData(c) +var c: ConfigData +iniConfigData(c) parseCmdLine(c) parseIniFile(c) if actionInno in c.actions: diff --git a/tools/niminst/nsis.tmpl b/tools/niminst/nsis.tmpl index 23bbf3ac9..c21bfb9d5 100644 --- a/tools/niminst/nsis.tmpl +++ b/tools/niminst/nsis.tmpl @@ -1,5 +1,5 @@ #! stdtmpl(subsChar='?') | standard -#proc generateNsisSetup(c: TConfigData): string = +#proc generateNsisSetup(c: ConfigData): string = # result = "; NSIS script generated by niminst\n" & # "; To regenerate run ``niminst nsis`` or ``koch nsis``\n" @@ -50,8 +50,8 @@ SetCompressor /SOLID /FINAL lzma ; Installer and Uninstaller Icons - ; Icon "nimrod.ico" - ; UninstallIcon "nimrod.ico" + ; Icon "nim.ico" + ; UninstallIcon "nim.ico" ; Set installation details to be shown by default ShowInstDetails show @@ -113,7 +113,7 @@ SetOverwrite ifnewer ; Write all the files to the output directory. - #for i in low(TFileCategory)..fcWindows: + #for i in low(FileCategory)..fcWindows: # for f in items(c.cat[i]): SetOutPath "$INSTDIR\?{splitFile(f).dir.toWin}" File "?{expandFilename(f).toWin}" diff --git a/tools/nimrepl.nim b/tools/nimrepl.nim index 0c9f94616..3d818a556 100644 --- a/tools/nimrepl.nim +++ b/tools/nimrepl.nim @@ -130,7 +130,7 @@ proc initControls() = pack_start(MainBox, TopMenu, False, False, 0) - # VPaned - Seperates the InputTextView and the OutputTextView + # VPaned - Separates the InputTextView and the OutputTextView var paned = vpaned_new() set_position(paned, 450) pack_start(MainBox, paned, True, True, 0) diff --git a/tools/nimweb.nim b/tools/nimweb.nim index e74daf98f..8213cf418 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -319,7 +319,7 @@ proc buildAddDoc(c: var TConfigData, destPath: string) = # build additional documentation (without the index): var commands = newSeq[string](c.webdoc.len) for i, doc in pairs(c.webdoc): - commands[i] = "nim doc $# --docSeeSrcUrl:$#/$#/$# -o:$# $#" % + commands[i] = "nim doc2 $# --docSeeSrcUrl:$#/$#/$# -o:$# $#" % [c.nimArgs, c.gitRepo, c.gitCommit, doc.pathPart, destPath / changeFileExt(splitFile(doc).name, "html"), doc] mexec(commands, c.numProcessors) diff --git a/tools/website.tmpl b/tools/website.tmpl index e1fdf6701..bc3ed8e2c 100644 --- a/tools/website.tmpl +++ b/tools/website.tmpl @@ -7,7 +7,6 @@ <meta http-equiv="content-type" content="text/html; charset=utf-8"> <title>$c.projectTitle</title> <link rel="stylesheet" type="text/css" href="assets/style.css" /> - <link rel="shortcut icon" href="assets/images/favicon.ico"> #if len(rss) > 0: <link href="$rss" title="Recent changes" type="application/atom+xml" rel="alternate"> @@ -17,23 +16,23 @@ <header id="head"> <div class="page-layout tall"> <div id="head-logo"></div> - <a id="head-logo-link" href="http://nim-lang.org/index.html"></a> + <a id="head-logo-link" href="index.html"></a> <nav id="head-links"> #for i in 0.. c.tabs.len-1: - # var name = c.tabs[i].key - # var t = c.tabs[i].val - #if currentTab == t: - <a class="active" - #elif t == "community" or t == "news": - # continue - #else: - <a - #end if - #if t.contains('.'): - href="${t}" title = "$c.projectName - $name">$name</a> - #else: - href="${t}.html" title = "$c.projectName - $name">$name</a> - #end if + # let t = c.tabs[i].val + # if t != "index" and t != "community" and t != "news": + # let name = c.tabs[i].key + # if currentTab == t: + <a class="active" + # else: + <a + # end if + # if t.contains('.'): + href="${t}" title = "$c.projectName - $name">$name</a> + # else: + href="${t}.html" title = "$c.projectName - $name">$name</a> + # end if + # end if #end for </nav> </div> @@ -50,10 +49,25 @@ # if currentTab == "index": <div id="slideshow"> <!-- slides --> - <div id="slide0" class=""> + <div id="slide0" class="active"> + <h2><a name="why-should-i-be-excited">Why should I be excited?</a></h2> + <span class="desc">Nim is the only language that leverages automated proof technology to perform a <i>disjoint check</i> for your parallel code. Working on disjoint data means no locking is required and yet data races are impossible:</span><br><br> +<pre> +<span class="kwd">parallel</span>: +<span class="tab"> </span><span class="kwd">var</span> i = <span class="val">0</span> +<span class="tab"> </span><span class="kwd">while</span> i <= a.high: +<span class="tab"> <span class="tab"> </span></span></span><span class="kwd">spawn</span> f(a[i]) +<span class="tab"> <span class="tab"> </span></span></span><span class="kwd">spawn</span> f(a[i+<span class="val">1</span>]) +<span class="tab"> <span class="tab"> </span></span></span><span class="cmt"># ERROR: cannot prove a[i] is disjoint from a[i+1]</span> +<span class="tab"> <span class="tab"> </span></span></span><span class="cmt"># BUT: replace 'i += 1' with 'i += 2' and the code compiles!</span> +<span class="tab end"> <span class="tab end"> </span></span>i += <span class="val">1</span> +</pre> + </div> + <div id="slide1"> <div> - <h2>Nim looks like this..</h2> -<pre><span class="cmt"># compute average line length</span> + <h2>Nim is simple..</h2> +<pre> +<span class="cmt"># compute average line length</span> <span class="kwd">var</span> <span class="tab"> </span>sum = <span class="val">0</span> <span class="tab end"> </span>count = <span class="val">0</span> @@ -67,9 +81,10 @@ echo(<span class="val">"Average line length: "</span>, </pre> </div> <div> - <h2>..and this...</h2> -<pre><span class="cmt"># create and greet someone</span> -<span class="kwd">type</span> <span class="def">Person</span> = <span class="typ">object</span> + <h2>..and type safe...</h2> +<pre> +<span class="cmt"># create and greet someone</span> +<span class="kwd">type</span> <span class="def">Person</span> = <span class="kwd">object</span> <span class="tab"> </span>name: <span class="typ">string</span> <span class="tab end"> </span>age: <span class="typ">int</span> @@ -77,62 +92,47 @@ echo(<span class="val">"Average line length: "</span>, <span class="tab"> </span>echo <span class="val">"Hi, I'm "</span>, p.name, <span class="val">"."</span> <span class="tab end"> </span>echo <span class="val">"I am "</span>, p.age, <span class="val">" years old."</span> -<span class="kwd">var</span> p = <span class="typ">Person</span>(name:<span class="val">"Jon"</span>, age:<span class="val">18</span>) +<span class="kwd">let</span> p = <span class="typ">Person</span>(name:<span class="val">"Jon"</span>, age:<span class="val">18</span>) p.greet() <span class="cmt"># or greet(p)</span> </pre> </div> - </div> <!-- slide0 --> - <div id="slide1" class="active"> - <h2><a name="why-should-i-be-excited">Why should I be excited?</a></h2> - <span class="desc"> - Nim is the only language that leverages automated proof technology - to perform a <i>disjoint check</i> for your parallel - code. Working on disjoint data means no locking is - required and yet data races are impossible:</span> - <pre> -<span class="kwd">parallel</span>: -<span class="tab"> </span><span class="kwd">var</span> i = <span class="val">0</span> -<span class="tab"> </span><span class="kwd">while</span> i <= a.high: -<span class="tab"> </span>spawn f(a[i]) -<span class="tab"> </span>spawn f(a[i+<span class="val">1</span>]) -<span class="tab"> </span><span class="cmt"># ERROR: cannot prove a[i] is disjoint from a[i+1]</span> -<span class="tab"> </span><span class="cmt"># BUT: replace 'i += 1' with 'i += 2' and the code compiles!</span> -<span class="tab end"> </span>i += <span class="val">1</span> - </pre> </div> <div id="slide2" class=""> <div> - <h2>interfacing with C..</h2> - <pre> -<span class="kwd">proc</span> <span class="def">unsafeScanf</span>(f: <span class="typ">File</span>; s: <span class="typ">cstring</span>) -<span class="tab"> </span>{.importc: <span class="val">"fscanf"</span>, -<span class="tab end"> </span>header: <span class="val">"<stdio.h>"</span>, varargs.} - -<span class="kwd">var</span> x: cint -unsafeScanf(stdin, <span class="val">"%d"</span>, <span class="kwd">addr</span> x) - </pre></div> - + <h2>C FFI is easy in Nim..</h2> +<pre> +<span class="cmt"># declare a C procedure..</span> +<span class="kwd">proc</span> <span class="def">unsafeScanf</span>(f: <span class="typ">File</span>, s: <span class="typ">cstring</span>) +<span class="tab"> </span>{.varargs, +<span class="tab"> </span>importc: <span class="val">"fscanf"</span>, +<span class="tab end"> </span>header: <span class="val">"<stdio.h>"</span>.} + +<span class="cmt"># ..and use it...</span> +<span class="kwd">var</span> x: <span class="typ">cint</span> +stdin.unsafeScanf(<span class="val">"%d"</span>, <span class="kwd">addr</span> x) +</pre> + <p><span class="desc"><b>Compile and run with:</b><br> $ nim c -r example.nim</span></p> + </div> <div> - <h2>..and DSLs made easy</h2> + <h2>..and DSLs are too...</h2> <pre> -<span class="kwd">import</span> jester, asyncdispatch, htmlgen +<span class="cmt"># a simple html server</span> +<span class="kwd">import</span> + jester, asyncdispatch, htmlgen -routes: -<span class="tab"> </span>get <span class="val">"/"</span>: -<span class="tab end"> </span>resp h1(<span class="val">"Hello world"</span>) +<span class="kwd">routes</span>: +<span class="tab"> </span><span class="kwd">get</span> <span class="val">"/"</span>: +<span class="tab end"> <span class="tab end"> </span></span><span class="kwd">resp</span> h1(<span class="val">"Hello world"</span>) runForever() -</pre><p><span class="desc"> -Compile and run with:<br /> -nim c -r example.nim<br /> -View at: localhost:5000 -</span></p> +</pre> + <p><span class="desc"><b>View in browser at:</b><br> localhost:5000</span></p> </div> </div> </div> <div id="slideshow-nav"> - <div id="slideControl0" onclick="slideshow_click(0)"></div> - <div id="slideControl1" onclick="slideshow_click(1)" class="active"></div> + <div id="slideControl0" onclick="slideshow_click(0)" class="active"></div> + <div id="slideControl1" onclick="slideshow_click(1)"></div> <div id="slideControl2" onclick="slideshow_click(2)"></div> </div> # end @@ -146,12 +146,12 @@ View at: localhost:5000 # end for </div> # end if +# if len(c.ticker) > 0: <h3 class="blue">Latest News</h3> <div id="sidebar-news"> -# if len(c.ticker) > 0: $c.ticker -# end if </div> +# end if </aside> </div> </section> @@ -173,6 +173,7 @@ View at: localhost:5000 <div> <h4>Documentation</h4> <a href="documentation.html">Stable Documentation</a> + <a href="learn.html">Learning Resources</a> <!-- <a href="">Development Documentation</a> --> <a href="https://github.com/Araq/Nimrod">Issues & Requests</a> </div> @@ -190,9 +191,12 @@ View at: localhost:5000 </div> </div> </footer> - - <script> + +# if currentTab == "index": + <script src="assets/index.js"></script> +# end if # if c.gaId != nil: + <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) @@ -200,42 +204,7 @@ View at: localhost:5000 ga('create', '${c.gaId}', 'nim-lang.org'); ga('send', 'pageview'); -# end if - -var timer; -var prevIndex = 0; - -function setSlideShow(index, short) { - if (index > 2) index = 0; - for (var i = 0; i < 10; ++i) { - var x = document.getElementById("slide"+i); - if (!x) break; - x.className = ""; - document.getElementById("slideControl"+i).className = ""; - } - document.getElementById("slide"+index).className = "active"; - document.getElementById("slideControl"+index).className = "active"; - prevIndex = index; - startTimer(short ? 8000 : 32000); -} - -function nextSlide() { setSlideShow(prevIndex + 1, true); } -function startTimer(t) { timer = setTimeout(nextSlide, t); } - -function slideshow_enter() { clearTimeout(timer); } -function slideshow_exit () { startTimer(16000); } - -function slideshow_click(index) { - clearTimeout(timer); - setSlideShow(index, false); -} - -window.onload = function() { - var slideshow = document.getElementById("slideshow"); - slideshow.onmouseenter = slideshow_enter; - slideshow.onmouseleave = slideshow_exit; - startTimer(8000); -}; </script> +# end if </body> </html> diff --git a/web/assets/images/bg.jpg b/web/assets/images/bg.jpg deleted file mode 100644 index 4e33a79ce..000000000 --- a/web/assets/images/bg.jpg +++ /dev/null Binary files differdiff --git a/web/assets/images/bg.png b/web/assets/images/bg.png new file mode 100644 index 000000000..91f335913 --- /dev/null +++ b/web/assets/images/bg.png Binary files differdiff --git a/web/assets/images/docs-articles.png b/web/assets/images/docs-articles.png new file mode 100644 index 000000000..7f800ea33 --- /dev/null +++ b/web/assets/images/docs-articles.png Binary files differdiff --git a/web/assets/images/docs-examples.png b/web/assets/images/docs-examples.png new file mode 100644 index 000000000..e6d27e034 --- /dev/null +++ b/web/assets/images/docs-examples.png Binary files differdiff --git a/web/assets/images/docs-internals.png b/web/assets/images/docs-internals.png new file mode 100644 index 000000000..e03a952d5 --- /dev/null +++ b/web/assets/images/docs-internals.png Binary files differdiff --git a/web/assets/images/docs-libraries.png b/web/assets/images/docs-libraries.png new file mode 100644 index 000000000..b14952f7d --- /dev/null +++ b/web/assets/images/docs-libraries.png Binary files differdiff --git a/web/assets/images/docs-tools.png b/web/assets/images/docs-tools.png new file mode 100644 index 000000000..d83f0faaa --- /dev/null +++ b/web/assets/images/docs-tools.png Binary files differdiff --git a/web/assets/images/docs-tutorials.png b/web/assets/images/docs-tutorials.png new file mode 100644 index 000000000..926a4b58b --- /dev/null +++ b/web/assets/images/docs-tutorials.png Binary files differdiff --git a/web/assets/index.js b/web/assets/index.js new file mode 100644 index 000000000..f10dc603d --- /dev/null +++ b/web/assets/index.js @@ -0,0 +1,34 @@ +"use strict"; + +var timer; +var prevIndex = 0; +var slideCount = 2; + +function setSlideShow(index, short) { + if (index >= slideCount) index = 0; + document.getElementById("slide"+prevIndex).className = ""; + document.getElementById("slide"+index).className = "active"; + document.getElementById("slideControl"+prevIndex).className = ""; + document.getElementById("slideControl"+index).className = "active"; + prevIndex = index; + startTimer(short ? 8000 : 32000); +} + +function nextSlide() { setSlideShow(prevIndex + 1, true); } +function startTimer(t) { timer = setTimeout(nextSlide, t); } + +function slideshow_enter() { clearTimeout(timer); } +function slideshow_exit () { startTimer(16000); } + +function slideshow_click(index) { + clearTimeout(timer); + setSlideShow(index, false); +} + +window.onload = function() { + var slideshow = document.getElementById("slideshow"); + slideshow.onmouseenter = slideshow_enter; + slideshow.onmouseleave = slideshow_exit; + slideCount = slideshow.children.length; + startTimer(8000); +}; \ No newline at end of file diff --git a/web/assets/style.css b/web/assets/style.css index da4cff05c..b74cbc486 100644 --- a/web/assets/style.css +++ b/web/assets/style.css @@ -8,10 +8,18 @@ body { min-width:1030px; margin:0; font:13pt "arial"; - background:#152534 url("images/bg.jpg") no-repeat fixed center top; + background:#152534 url("images/bg.png") no-repeat center top; color:rgba(0,0,0,.8); } -pre { color:#fff;} +pre { + color:#fff; + margin:0; + padding:15px 10px; + font:10pt monospace; + line-height:14pt; + background:rgba(0,0,0,.4); + border-left:8px solid rgba(0,0,0,.3); + box-shadow:1px 2px 16px rgba(28,180,236,.4); } pre, pre * { cursor:text; } pre .cmt { color:rgb(255,229,106); } pre .kwd { color:#43A8CF; font-weight:bold; } @@ -23,8 +31,14 @@ pre .val { color:#8AB647; } pre .tab { border-left:1px dotted rgba(67,168,207,0.4); } pre .end { background:url("images/tabEnd.png") no-repeat left bottom; } +.page pre { background:rgba(0,0,0,.8); } +.page pre > .Comment { color:rgb(255,229,106); } +.page pre > .Keyword { color:#43A8CF; font-weight:bold; } +.page pre > .StringLit, +.page pre > .DecNumber { color:#8AB647; } + .tall { height:100%; } -.pre { padding:0 5px; font:11pt monospace; background:rgba(255,255,255,.15); border-radius:3px; } +.pre { padding:1px 5px; font:11pt monospace; background:#96A9B7; border-radius:3px; } .page-layout { margin:0 auto; width:1000px; } .docs-layout { margin:0 40px; } @@ -90,7 +104,7 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; } right:-16px; height:48px; background:url("images/glow-arrow.png") no-repeat right; } - glow-arrow.docs { left:280px; } + #glow-arrow.docs { left:280px; } #glow-line-vert { position:fixed; @@ -102,55 +116,35 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; } #slideshow { position:absolute; top:10px; left:10px; width:700px; height: 1000px; } #slideshow > div { - visibility:hidden; opacity:0; position:absolute; transition:visibility 0s linear 1s, opacity 1s ease-in-out; } + position:absolute; + margin:30px 0 0 10px; + visibility:hidden; + opacity:0; + transition: + visibility 0s linear 1s, + opacity 1s ease-in-out; } #slideshow > div.active { visibility:visible; opacity:1; transition-delay:0s; } #slideshow > div.init { transition-delay:0s; } #slideshow-nav { z-index:3; position:absolute; top:110px;; right:-12px; } #slideshow-nav > div { margin:5px 0; width:23px; height:23px; background:url("images/slideshow-nav.png") no-repeat; } #slideshow-nav > div:hover { background-image:url("images/slideshow-nav_active.png"); opacity:0.5; } #slideshow-nav > div.active { background-image:url("images/slideshow-nav_active.png"); opacity:1; } - - #slide0 { margin:30px 0 0 10px; } - #slide0 > div { float:left; width:320px; font:10pt monospace; } + + #slide0 { float:left; width:680px; font:10pt monospace; } #slide0 > div:first-child { margin:0 40px 0 0; } #slide0 h2 { margin:0 0 5px 0; color:rgba(162,198,223,.78); } - #slide0 > div > pre { - margin:0; - padding:15px 10px; - line-height:14pt; - background:rgba(0,0,0,.4); - border-left:8px solid rgba(0,0,0,.3); - box-shadow:1px 2px 16px rgba(28,180,236,.4); } - - #slide1 { margin:30px 0 0 10px; } - #slide1 { float:left; width:680px; font:10pt monospace; } + #slide0 .desc { margin:0 0 5px 0; color:rgba(162,198,223,.78); font:13pt "arial"; } + + #slide1 > div { float:left; width:320px; font:10pt monospace; } #slide1 > div:first-child { margin:0 40px 0 0; } #slide1 h2 { margin:0 0 5px 0; color:rgba(162,198,223,.78); } - #slide1 .desc { margin:0 0 5px 0; color:rgba(162,198,223,.78); - font:13pt "arial"; } - #slide1 pre { - padding:7px 10px; - line-height:14pt; - background:rgba(0,0,0,.4); - border-left:8px solid rgba(0,0,0,.3); - box-shadow:1px 2px 16px rgba(28,180,236,.4); } - - - #slide2 { margin:30px 0 0 10px; } + #slide2 > div { float:left; width:320px; font:10pt monospace; } #slide2 > div:first-child { margin:0 40px 0 0; } #slide2 h2 { margin:0 0 5px 0; color:rgba(162,198,223,.78); } - #slide2 > div > pre { - margin:0; - padding:15px 10px; - line-height:14pt; - background:rgba(0,0,0,.4); - border-left:8px solid rgba(0,0,0,.3); - box-shadow:1px 2px 16px rgba(28,180,236,.4); } - - #slide2 .desc { margin:0 0 5px 0; color:rgba(162,198,223,.78); - font:13pt "arial"; } - + + #slide2 .desc { margin:0 0 5px 0; color:rgba(162,198,223,.78); font:13pt "arial"; } + /* back when slide1 was the quote: #slide1 { margin-top:50px; } #slide1 > p { @@ -166,7 +160,7 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; } font-style:italic; font-weight:bold; color:rgba(93,155,199,.44); } - */ + */ #sidebar { z-index:2; position:absolute; @@ -524,14 +518,15 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; } .standout h2 { margin-bottom:10px; padding-bottom:10px; border-bottom:1px dashed rgba(0,0,0,.8); } .standout li { margin:0 !important; padding-top:10px; border-top:1px dashed rgba(0,0,0,.2); } .standout ul { padding-bottom:5px; } - .standout ul.tools { list-style:url("images/docs-tools.png"); } - .standout ul.library { list-style:url("images/docs-library.png"); } - .standout ul.internal { list-style:url("images/docs-internal.png"); } - .standout ul.tutorial { list-style:url("images/docs-tutorial.png"); } - .standout ul.example { list-style:url("images/docs-example.png"); } + .standout .tools ul { list-style:url("images/docs-tools.png"); } + .standout .libraries ul { list-style:url("images/docs-libraries.png"); } + .standout .internals ul { list-style:url("images/docs-internals.png"); } + .standout .tutorials ul { list-style:url("images/docs-tutorials.png"); } + .standout .examples ul { list-style:url("images/docs-examples.png"); } + .standout .articles ul { list-style:url("images/docs-articles.png"); } .standout li:first-child { padding-top:0; border-top:none; } .standout li p { margin:0 0 10px 0 !important; line-height:130%; } - .standout li > a { font-weight:bold; } + .standout li p > a { font-weight:bold; } .forum-user-info, .forum-user-info * { cursor:help } @@ -551,48 +546,13 @@ pre .end { background:url("images/tabEnd.png") no-repeat left bottom; } #foot-legal { float:right; font-size:10pt; color:rgba(255,255,255,.3); line-height:150%; text-align:right; } #foot-legal a { color:inherit; text-decoration:none; } #foot-legal > h4 > a { color:inherit; } - - #mascot { - z-index:2; - position:absolute; - top:-340px; - right:25px; - width:202px; - height:319px; - background:url("images/mascot.png") no-repeat; } - - -#body pre { - padding:20px; - border-left:10px solid #8f9698; - background:#f3f6f8; - font-size:15px; - font-family:courier, monospace; - letter-spacing:0; - line-height:17px; - color: #343739; -} - -#body span.pre { - background-color: #96A9B7; - padding: 1pt 3pt; - border-radius: 2pt; - -moz-border-radius: 2pt; - -webkit-border-radius: 2pt; -} -#body pre > .Comment { color:#858686; font-style:italic; } -#body pre > .Keyword { color:#1cb4ec; font-weight:bold; } -#body pre > .Operator { color:#777; } -#body pre > .StringLit, #page pre > .DecNumber { color:#ff7302; } #body .docutils th { border-bottom: 2px solid #1A1A1A; font-weight: normal; - padding: 8px; -} + padding: 8px; } #body table.docutils { border-collapse: collapse; text-align: left; - border-spacing: 0px; -} + border-spacing: 0px; } diff --git a/web/documentation.txt b/web/documentation.txt index 0bb2b8a0f..dbb737cd9 100644 --- a/web/documentation.txt +++ b/web/documentation.txt @@ -6,16 +6,17 @@ Nim's Documentation Standards & Guides ------------------ + .. container:: libraries - - | `Standard Library <lib.html>`_ - | This document describes Nim's standard library. + - | `Standard Library <lib.html>`_ + | This document describes Nim's standard library. - - | `Language Manual <manual.html>`_ - | The Nim manual is a draft that will evolve into a proper specification. + - | `Language Manual <manual.html>`_ + | The Nim manual is a draft that will evolve into a proper specification. - - | `Compiler user guide <nimc.html>`_ - | The user guide lists command line arguments, special features of the - compiler, etc. + - | `Compiler User Guide <nimc.html>`_ + | The user guide lists command line arguments, special features of the + compiler, etc. .. container:: standout @@ -23,12 +24,14 @@ Nim's Documentation Tools & Features ---------------- - - | `Source code filters <filters.html>`_ - | The Nim compiler supports source code filters as a simple yet powerful - builtin templating system. + .. container:: tools - - | `Tools documentation <tools.html>`_ - | Description of some tools that come with the standard distribution. + - | `Source Code Filters <filters.html>`_ + | The Nim compiler supports source code filters as a simple yet powerful + builtin templating system. + + - | `Tools Documentation <tools.html>`_ + | Description of some tools that come with the standard distribution. .. container:: standout @@ -36,13 +39,15 @@ Nim's Documentation Internal Details ---------------- - - | `Garbage Collector <gc.html>`_ - | Additional documentation about Nim's GC and how to operate it in a - | realtime setting. + .. container:: internals + + - | `Garbage Collector <gc.html>`_ + | Additional documentation about Nim's GC and how to operate it in a + realtime setting. - - | `Internal documentation <intern.html>`_ - | The internal documentation describes how the compiler is implemented. Read - this if you want to hack the compiler. + - | `Internal Documentation <intern.html>`_ + | The internal documentation describes how the compiler is implemented. Read + this if you want to hack the compiler. Search Options diff --git a/web/download.txt b/web/download.txt index 497781ad6..3d47467f2 100644 --- a/web/download.txt +++ b/web/download.txt @@ -1,13 +1,16 @@ +Download the compiler +===================== + You can download the latest version of the Nim compiler here. **Note:** The Nim compiler requires a C compiler to compile software. On Windows we recommend that you use `Mingw-w64 <http://mingw-w64.sourceforge.net/>`_. GCC is recommended on Linux -and clang on Mac OS X. +and Clang on Mac. Binaries -======== +-------- Unfortunately for now we only provide builds for Windows. * 32 bit: `nim-0.10.2_x32.exe <download/nim-0.10.2_x32.exe>`_ @@ -15,7 +18,7 @@ Unfortunately for now we only provide builds for Windows. Installation based on generated C code -====================================== +-------------------------------------- This installation method is the preferred way for Linux, Mac OS X, and other Unix like systems. Binary packages may be provided later. @@ -32,7 +35,7 @@ but these tend to cause more problems. Installation from github -======================== +------------------------ Use the following commands to build the compiler from source. Change the branch to suit your needs:: diff --git a/web/learn.txt b/web/learn.txt index 854b31668..7a9600e57 100644 --- a/web/learn.txt +++ b/web/learn.txt @@ -6,11 +6,13 @@ Learning Nim Tutorials --------- - - | `Tutorial (part I) <tut1.html>`_ - | Learn the basics of Nim's types, variables, procedures, control flow, etc... + .. container:: tutorials - - | `Tutorial (part II) <tut2.html>`_ - | Learn Nim's more advanced features such as OOP, generics, macros, etc... + - | `Tutorial (part I) <tut1.html>`_ + | Learn the basics of Nim's types, variables, procedures, control flow, etc... + + - | `Tutorial (part II) <tut2.html>`_ + | Learn Nim's more advanced features such as OOP, generics, macros, etc... .. container:: standout @@ -18,14 +20,16 @@ Learning Nim Examples -------- - - | `Nim by Example <http://nim-by-example.github.io/>`_ - | Nim by Example is an excellent starting place for beginners. + .. container:: examples + + - | `Nim by Example <http://nim-by-example.github.io/>`_ + | Nim by Example is an excellent starting place for beginners. - - | `Nim on Rosetta Code <http://rosettacode.org/wiki/Category:Nimrod>`_ - | Many different Nim code examples comparable to other languages for reference. + - | `Nim on Rosetta Code <http://rosettacode.org/wiki/Category:Nimrod>`_ + | Many different Nim code examples comparable to other languages for reference. - - | `Nim for C/C++ Programmers <https://github.com/Araq/Nim/wiki/Nim-for-C-programmers>`_ - | A useful cheat-sheet for those most familiar with C/C++ languages. + - | `Nim for C/C++ Programmers <https://github.com/Araq/Nim/wiki/Nim-for-C-programmers>`_ + | A useful cheat-sheet for those most familiar with C/C++ languages. .. container:: standout @@ -33,8 +37,16 @@ Learning Nim Articles -------- - - `Dr Dobbs Nimrod Publication <http://www.drdobbs.com/open-source/nimrod-a-new-systems-programming-languag/240165321>`_ - - `Bootstrapping Nim <http://goran.krampe.se/2014/10/15/bootstrapping-nim/>`_ + .. container:: articles + + - `How I Start: Nim <http://howistart.org/posts/nim/1>`_ + - `Getting Started With Nim <https://akehrer.github.io/nim/2015/01/05/getting-started-with-nim.html>`_ + - `Getting Started With Nim - Part 2 <https://akehrer.github.io/nim/2015/01/14/getting-started-with-nim-pt2.html>`_ + - `What is special about Nim? <http://hookrace.net/blog/what-is-special-about-nim>`_ + - `What makes Nim practical? <http://hookrace.net/blog/what-makes-nim-practical>`_ + - `Learn Nim in minutes <http://learnxinyminutes.com/docs/nim>`_ + - `Dr Dobbs Nimrod Publication <http://www.drdobbs.com/open-source/nimrod-a-new-systems-programming-languag/240165321>`_ + - `Nim articles by Göran Krampe <http://goran.krampe.se/category/nim>`_ Documentation diff --git a/web/news.txt b/web/news.txt index ac7971f20..aa093be46 100644 --- a/web/news.txt +++ b/web/news.txt @@ -20,7 +20,9 @@ News ``addHandler``, ``getHandlers``, ``setLogFilter`` and ``getLogFilter`` should be used instead. - ``nim idetools`` has been replaced by a separate tool `nimsuggest`_. - + - *arrow like* operators are not right associative anymore. + - Typeless parameters are now only allowed in templates and macros. The old + way turned out to be too error-prone. Language Additions ------------------ @@ -30,7 +32,28 @@ News - Automatic dereferencing is now done for the first argument of a routine call if overloading resolution produces no match otherwise. This feature has to be enabled with the `experimental`_ pragma. + - Objects that do not use inheritance nor ``case`` can be put into ``const`` + sections. This means that finally this is possible and produces rather + nice code: + + .. code-block:: nim + import tables + + const + foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable() + + - Ordinary parameters can follow after a varargs parameter. This means the + following is finally accepted by the compiler: + + .. code-block:: nim + template takesBlock(a, b: int, x: varargs[expr]; blck: stmt) = + blck + echo a, b + + takesBlock 1, 2, "some", 0.90, "random stuff": + echo "yay" + 2014-12-29 Version 0.10.2 released ================================== @@ -308,7 +331,7 @@ Library Additions The Nimrod development community is proud to announce the release of version 0.9.4 of the Nimrod compiler and tools. **Note: This release has to be considered beta quality! Lots of new features have been implemented but -unfortunately some do not fullfill our quality standards yet.** +unfortunately some do not fulfill our quality standards yet.** Prebuilt binaries and instructions for building from source are available on the `download page <download.html>`_. @@ -733,7 +756,7 @@ Changes affecting backwards compatibility - The default calling convention for a procedural **type** is now ``closure``, for procs it remains ``nimcall`` (which is compatible to ``closure``). Activate the warning ``ImplicitClosure`` to make the compiler list the - occurances of proc types which are affected. + occurrences of proc types which are affected. - The Nimrod type system now distinguishes ``openarray`` from ``varargs``. - Templates are now ``hygienic``. Use the ``dirty`` pragma to get the old behaviour. @@ -861,7 +884,7 @@ Language Additions ------------------ - Added new ``is`` and ``of`` operators. -- The built-in type ``void`` can be used to denote the absense of any type. +- The built-in type ``void`` can be used to denote the absence of any type. This is useful in generic code. - Return types may be of the type ``var T`` to return an l-value. - The error pragma can now be used to mark symbols whose *usage* should trigger diff --git a/web/question.txt b/web/question.txt index 1fb501e2c..28c7ece14 100644 --- a/web/question.txt +++ b/web/question.txt @@ -3,8 +3,8 @@ =========================================== -General -======= +General FAQ +=========== .. container:: standout @@ -124,8 +124,8 @@ General keyword. -Compilation -=========== +Compilation FAQ +=============== .. container:: standout @@ -149,16 +149,16 @@ Compilation Edit the ``config/nim.cfg`` file. Change the value of the ``cc`` variable to one of the following: - ============== ============================================ - Abbreviation C/C++ Compiler - ============== ============================================ - ``vcc`` Microsoft's Visual C++ - ``gcc`` Gnu C - ``llvm_gcc`` LLVM-GCC compiler - ``icc`` Intel C++ compiler - ``clang`` Clang compiler - ``ucc`` Generic UNIX C compiler - ============== ============================================ + ================ ============================================ + **Abbreviation** **C/C++ Compiler** + ================ ============================================ + ``vcc`` Microsoft's Visual C++ + ``gcc`` Gnu C + ``llvm_gcc`` LLVM-GCC compiler + ``icc`` Intel C++ compiler + ``clang`` Clang compiler + ``ucc`` Generic UNIX C compiler + ================ ============================================ Other C compilers are not officially supported, but might work too. diff --git a/web/support.txt b/web/support.txt new file mode 100644 index 000000000..f8375b6aa --- /dev/null +++ b/web/support.txt @@ -0,0 +1,39 @@ +Commercial and Community Support +================================ + +We offer a multitude of support networks including those in both a community +and commercial setting. + +Commercial support includes: + +.. container:: standout + + Priority Bug Fixes + ------------------ + + File a bug report and we will address them with the highest priority. Once + fixed, you will be able to access either the current Git build or at your + request a custom build against the latest release with your bug fixed. + + +.. container:: standout + + Feature Requests + ---------------- + + Suggest to us any feature that you might need, we will examine your request with + care and provide a proper answer about its potential for inclusion. + + Communication happens via email or for a slightly higher fee via Skype. + The pricing is based on the amount of hours spent on the bugfix / feature + implementation and is open to negotiation. + + +All interested parties should email ``support@nim-lang.org``. +The bid for contracting work is a commercial offer provided by: + +| **Andreas Rumpf** +| St.-Quentin-Ring 47 +| 67663 Kaiserslautern +| GERMANY +| EU VAT-IN: DE297783450 diff --git a/web/ticker.txt b/web/ticker.txt index 64218084e..724d29231 100644 --- a/web/ticker.txt +++ b/web/ticker.txt @@ -13,9 +13,4 @@ <p>Nimrod featured in Dr. Dobb's Journal</p> </a> -<a class="news" href="news.html#Z2014-01-15-andreas-rumpf-s-talk-on-nimrod-at-strange-loop-2013-is-now-online"> - <h4>Jan 15, 2014</h4> - <p>Andreas Rumpf's talk on Nimrod at Strange Loop 2013 is now online.</p> -</a> - <a href="news.html" class="blue">See All News...</a> diff --git a/web/nim.ini b/web/website.ini index 0190416b2..696829764 100644 --- a/web/nim.ini +++ b/web/website.ini @@ -15,9 +15,10 @@ Github_Repo: "http://github.com/Araq/Nim;link_github" [Tabs] # Menu entry: filename home: index -docs: documentation learn: learn +docs: documentation download: download +support: support forum: "http://forum.nim-lang.org" faq: question # these two are not in the list of "tabs", but do exist: @@ -27,19 +28,6 @@ news: news [Ticker] file: ticker.txt -[Quotations] -# Page: quote - Person -# Bad things will happen if you use multiple dashes here. -index: """Is it so bad, then, to be misunderstood? Pythagoras was misunderstood, -and Socrates, and Jesus, and Luther, and Copernicus, and Galileo, and Newton, -and every pure and wise spirit that ever took flesh. To be great is to be -misunderstood. - Ralph Waldo Emerson""" -documentation: """Incorrect documentation is often worse than no documentation. -- Bertrand Meyer""" -download: """There are two major products that come out of Berkeley: LSD and -UNIX. We don't believe this to be a coincidence. - Jeremy S. Anderson.""" -learn: """Repetition renders the ridiculous reasonable. - Norman Wildberger""" - [Documentation] doc: "endb;intern;apis;lib;manual.txt;tut1;tut2;nimc;overview;filters" doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt" @@ -61,7 +49,7 @@ srcdoc2: "pure/httpserver;pure/httpclient;pure/smtp;impure/ssl;pure/fsmonitor" srcdoc2: "pure/ropes;pure/unidecode/unidecode;pure/xmldom;pure/xmldomparser" srcdoc2: "pure/xmlparser;pure/htmlparser;pure/xmltree;pure/colors;pure/mimetypes" srcdoc2: "pure/json;pure/base64;pure/scgi;pure/redis;impure/graphics" -srcdoc2: "impure/rdstdin;wrappers/sphinx" +srcdoc2: "impure/rdstdin" srcdoc2: "pure/collections/tables;pure/collections/sets;pure/collections/lists" srcdoc2: "pure/collections/intsets;pure/collections/queues;pure/encodings" srcdoc2: "pure/events;pure/collections/sequtils;pure/cookies" @@ -71,19 +59,16 @@ srcdoc2: "pure/nimprof;pure/unittest;packages/docutils/highlite" srcdoc2: "packages/docutils/rst;packages/docutils/rstast" srcdoc2: "packages/docutils/rstgen;pure/logging;pure/asyncdispatch;pure/asyncnet" srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/future" -srcdoc2: "wrappers/expat;wrappers/readline/history" -srcdoc2: "wrappers/libsvm.nim;wrappers/libuv" -srcdoc2: "wrappers/zip/zlib;wrappers/zip/libzip" -srcdoc2: "pure/md5;wrappers/mysql;wrappers/iup" -srcdoc2: "posix/posix;wrappers/odbcsql" -srcdoc2: "wrappers/tre;wrappers/openssl;wrappers/pcre" -srcdoc2: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc" -srcdoc2: "wrappers/readline/readline;wrappers/readline/rltypedefs" -srcdoc2: "wrappers/joyent_http_parser" +srcdoc2: "pure/md5" +srcdoc2: "posix/posix" srcdoc2: "pure/fenv" +srcdoc2: "pure/basic2d;pure/basic3d" + +; Note: everything under 'webdoc' doesn't get listed in the index, so wrappers +; should live here -webdoc: "pure/md5;wrappers/mysql;wrappers/iup" -webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc" +webdoc: "wrappers/mysql;wrappers/iup;wrappers/sphinx" +webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc;wrappers/odbcsql" webdoc: "wrappers/expat;wrappers/pcre" webdoc: "wrappers/tre;wrappers/openssl" webdoc: "wrappers/libuv;wrappers/joyent_http_parser" |