diff options
514 files changed, 21477 insertions, 17229 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim index a26b94303..3f3d45ff7 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -16,9 +16,9 @@ type TAnalysisResult* = enum arNo, arMaybe, arYes -proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult +proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult -proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult = +proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult = result = arNo case n.kind of nkRecList: @@ -39,7 +39,7 @@ proc isPartOfAux(n: PNode, b: PType, marker: var TIntSet): TAnalysisResult = result = isPartOfAux(n.sym.typ, b, marker) else: internalError(n.info, "isPartOfAux()") -proc isPartOfAux(a, b: PType, marker: var TIntSet): TAnalysisResult = +proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult = result = arNo if a == nil or b == nil: return if containsOrIncl(marker, a.id): return diff --git a/compiler/ast.nim b/compiler/ast.nim index 7ad294695..762e09a95 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -291,6 +291,8 @@ const sfNoRoot* = sfBorrow # a local variable is provably no root so it doesn't # require RC ops + sfCompileToCpp* = sfInfixCall # compile the module as C++ code + sfCompileToObjc* = sfNamedParamCall # compile the module as Objective-C code const # getting ready for the future expr/stmt merge @@ -476,7 +478,7 @@ type # and first phase symbol lookup in generics skConditional, # symbol for the preprocessor (may become obsolete) skDynLib, # symbol represents a dynamic library; this is used - # internally; it does not exist in Nimrod code + # internally; it does not exist in Nim code skParam, # a parameter skGenericParam, # a generic parameter; eq in ``proc x[eq=`==`]()`` skTemp, # a temporary variable (introduced by compiler) @@ -501,7 +503,8 @@ type skStub, # symbol is a stub and not yet loaded from the ROD # file (it is loaded on demand, which may # mean: never) - skPackage # symbol is a package (used for canonicalization) + skPackage, # symbol is a package (used for canonicalization) + skAlias # an alias (needs to be resolved immediately) TSymKinds* = set[TSymKind] const @@ -678,7 +681,7 @@ type heapRoot*: PRope # keeps track of the enclosing heap object that # owns this location (required by GC algorithms # employing heap snapshots or sliding views) - a*: int # location's "address", i.e. slot for temporaries + #a*: int # location's "address", i.e. slot for temporaries # ---------------- end of backend information ------------------------------ @@ -731,8 +734,9 @@ type # check for the owner when touching 'usedGenerics'. usedGenerics*: seq[PInstantiation] tab*: TStrTable # interface table for modules + of skLet, skVar, skField: + guard*: PSym else: nil - magic*: TMagic typ*: PType name*: PIdent @@ -768,6 +772,7 @@ type # it won't cause problems TTypeSeq* = seq[PType] + TLockLevel* = distinct int16 TType* {.acyclic.} = object of TIdObj # \ # types are identical iff they have the # same id; there may be multiple copies of a type @@ -794,11 +799,12 @@ type deepCopy*: PSym # overriden 'deepCopy' operation size*: BiggestInt # the size of the type in bytes # -1 means that the size is unkwown - align*: int # the type's alignment requirements + align*: int16 # the type's alignment requirements + lockLevel*: TLockLevel # lock level as required for deadlock checking loc*: TLoc TPair*{.final.} = object - key*, val*: PObject + key*, val*: RootRef TPairSeq* = seq[TPair] TTable*{.final.} = object # the same as table[PObject] of PObject @@ -807,7 +813,7 @@ type TIdPair*{.final.} = object key*: PIdObj - val*: PObject + val*: RootRef TIdPairSeq* = seq[TIdPair] TIdTable*{.final.} = object # the same as table[PIdent] of PObject @@ -834,7 +840,7 @@ type counter*: int data*: TNodePairSeq - TObjectSeq* = seq[PObject] + TObjectSeq* = seq[RootRef] TObjectSet*{.final.} = object counter*: int data*: TObjectSeq @@ -872,7 +878,7 @@ const tyProc, tyString, tyError} ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, skClosureIterator, - skMacro, skTemplate, skConverter, skEnumField, skLet, skStub} + skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias} PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16, nfDotSetter, nfDotField, nfIsRef} @@ -1162,6 +1168,15 @@ proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, result.sons = @[name, pattern, genericParams, params, pragmas, exceptions, body] +const + UnspecifiedLockLevel* = TLockLevel(-1'i16) + MaxLockLevel* = 1000'i16 + UnknownLockLevel* = TLockLevel(1001'i16) + +proc `$`*(x: TLockLevel): string = + if x.ord == UnspecifiedLockLevel.ord: result = "<unspecified>" + elif x.ord == UnknownLockLevel.ord: result = "<unknown>" + else: result = $int16(x) proc newType(kind: TTypeKind, owner: PSym): PType = new(result) @@ -1170,10 +1185,11 @@ proc newType(kind: TTypeKind, owner: PSym): PType = result.size = - 1 result.align = 2 # default alignment result.id = getID() + result.lockLevel = UnspecifiedLockLevel when debugIds: registerId(result) - #if result.id < 2000 then - # MessageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id)) + #if result.id < 2000: + # messageOut(typeKindToStr[kind] & ' has id: ' & toString(result.id)) proc mergeLoc(a: var TLoc, b: TLoc) = if a.k == low(a.k): a.k = b.k @@ -1181,7 +1197,7 @@ proc mergeLoc(a: var TLoc, b: TLoc) = a.flags = a.flags + b.flags if a.t == nil: a.t = b.t if a.r == nil: a.r = b.r - if a.a == 0: a.a = b.a + #if a.a == 0: a.a = b.a proc assignType(dest, src: PType) = dest.kind = src.kind @@ -1192,6 +1208,7 @@ proc assignType(dest, src: PType) = dest.align = src.align dest.destructor = src.destructor dest.deepCopy = src.deepCopy + dest.lockLevel = src.lockLevel # this fixes 'type TLock = TSysLock': if src.sym != nil: if dest.sym != nil: @@ -1229,6 +1246,8 @@ proc copySym(s: PSym, keepId: bool = false): PSym = result.position = s.position result.loc = s.loc result.annex = s.annex # BUGFIX + if result.kind in {skVar, skLet, skField}: + result.guard = s.guard proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym = result = newSym(s.kind, newIdent, s.owner, info) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index eb7ffc63e..110b0c26e 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -14,7 +14,7 @@ import ast, hashes, intsets, strutils, options, msgs, ropes, idents, rodutils -proc hashNode*(p: PObject): THash +proc hashNode*(p: RootRef): THash proc treeToYaml*(n: PNode, indent: int = 0, maxRecDepth: int = - 1): PRope # Convert a tree into its YAML representation; this is used by the # YAML code generator and it is invaluable for debugging purposes. @@ -24,21 +24,21 @@ proc symToYaml*(n: PSym, indent: int = 0, maxRecDepth: int = - 1): PRope proc lineInfoToStr*(info: TLineInfo): PRope # ----------------------- node sets: --------------------------------------- -proc objectSetContains*(t: TObjectSet, obj: PObject): bool +proc objectSetContains*(t: TObjectSet, obj: RootRef): bool # returns true whether n is in t -proc objectSetIncl*(t: var TObjectSet, obj: PObject) +proc objectSetIncl*(t: var TObjectSet, obj: RootRef) # include an element n in the table t -proc objectSetContainsOrIncl*(t: var TObjectSet, obj: PObject): bool +proc objectSetContainsOrIncl*(t: var TObjectSet, obj: RootRef): bool # more are not needed ... # ----------------------- (key, val)-Hashtables ---------------------------- -proc tablePut*(t: var TTable, key, val: PObject) -proc tableGet*(t: TTable, key: PObject): PObject +proc tablePut*(t: var TTable, key, val: RootRef) +proc tableGet*(t: TTable, key: RootRef): RootRef type - TCmpProc* = proc (key, closure: PObject): bool {.nimcall.} # true if found + TCmpProc* = proc (key, closure: RootRef): bool {.nimcall.} # true if found -proc tableSearch*(t: TTable, key, closure: PObject, - comparator: TCmpProc): PObject +proc tableSearch*(t: TTable, key, closure: RootRef, + comparator: TCmpProc): RootRef # return val as soon as comparator returns true; if this never happens, # nil is returned @@ -79,9 +79,9 @@ proc debug*(n: PType) {.deprecated.} proc debug*(n: PNode) {.deprecated.} # --------------------------- ident tables ---------------------------------- -proc idTableGet*(t: TIdTable, key: PIdObj): PObject -proc idTableGet*(t: TIdTable, key: int): PObject -proc idTablePut*(t: var TIdTable, key: PIdObj, val: PObject) +proc idTableGet*(t: TIdTable, key: PIdObj): RootRef +proc idTableGet*(t: TIdTable, key: int): RootRef +proc idTablePut*(t: var TIdTable, key: PIdObj, val: RootRef) proc idTableHasObjectAsKey*(t: TIdTable, key: PIdObj): bool # checks if `t` contains the `key` (compared by the pointer value, not only # `key`'s id) @@ -196,7 +196,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym = else: internalError(list.info, "getSymFromList") result = nil -proc hashNode(p: PObject): THash = +proc hashNode(p: RootRef): THash = result = hash(cast[pointer](p)) proc mustRehash(length, counter: int): bool = @@ -245,13 +245,13 @@ proc lineInfoToStr(info: TLineInfo): PRope = toRope(toLinenumber(info)), toRope(toColumn(info))]) -proc treeToYamlAux(n: PNode, marker: var TIntSet, +proc treeToYamlAux(n: PNode, marker: var IntSet, indent, maxRecDepth: int): PRope -proc symToYamlAux(n: PSym, marker: var TIntSet, +proc symToYamlAux(n: PSym, marker: var IntSet, indent, maxRecDepth: int): PRope -proc typeToYamlAux(n: PType, marker: var TIntSet, +proc typeToYamlAux(n: PType, marker: var IntSet, indent, maxRecDepth: int): PRope -proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int, +proc strTableToYaml(n: TStrTable, marker: var IntSet, indent: int, maxRecDepth: int): PRope = var istr = spaces(indent + 2) result = toRope("[") @@ -277,13 +277,13 @@ proc ropeConstr(indent: int, c: openArray[PRope]): PRope = inc(i, 2) appf(result, "$N$1}", [spaces(indent)]) -proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int, +proc symToYamlAux(n: PSym, marker: var IntSet, indent: int, maxRecDepth: int): PRope = if n == nil: result = toRope("null") elif containsOrIncl(marker, n.id): result = ropef("\"$1 @$2\"", [toRope(n.name.s), toRope( - strutils.toHex(cast[TAddress](n), sizeof(n) * 2))]) + strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]) else: var ast = treeToYamlAux(n.ast, marker, indent + 2, maxRecDepth - 1) result = ropeConstr(indent, [toRope("kind"), @@ -298,13 +298,13 @@ proc symToYamlAux(n: PSym, marker: var TIntSet, indent: int, flagsToStr(n.options), toRope("position"), toRope(n.position)]) -proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int, +proc typeToYamlAux(n: PType, marker: var IntSet, indent: int, maxRecDepth: int): PRope = if n == nil: result = toRope("null") elif containsOrIncl(marker, n.id): result = ropef("\"$1 @$2\"", [toRope($n.kind), toRope( - strutils.toHex(cast[TAddress](n), sizeof(n) * 2))]) + strutils.toHex(cast[ByteAddress](n), sizeof(n) * 2))]) else: if sonsLen(n) > 0: result = toRope("[") @@ -326,7 +326,7 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int, toRope("align"), toRope(n.align), toRope("sons"), result]) -proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, +proc treeToYamlAux(n: PNode, marker: var IntSet, indent: int, maxRecDepth: int): PRope = if n == nil: result = toRope("null") @@ -469,7 +469,7 @@ proc nextTry(h, maxHash: THash): THash = # generates each int in range(maxHash) exactly once (see any text on # random-number generation for proof). -proc objectSetContains(t: TObjectSet, obj: PObject): bool = +proc objectSetContains(t: TObjectSet, obj: RootRef): bool = # returns true whether n is in t var h: THash = hashNode(obj) and high(t.data) # start with real hash value while t.data[h] != nil: @@ -478,7 +478,7 @@ proc objectSetContains(t: TObjectSet, obj: PObject): bool = h = nextTry(h, high(t.data)) result = false -proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) = +proc objectSetRawInsert(data: var TObjectSeq, obj: RootRef) = var h: THash = hashNode(obj) and high(data) while data[h] != nil: assert(data[h] != obj) @@ -493,12 +493,12 @@ proc objectSetEnlarge(t: var TObjectSet) = if t.data[i] != nil: objectSetRawInsert(n, t.data[i]) swap(t.data, n) -proc objectSetIncl(t: var TObjectSet, obj: PObject) = +proc objectSetIncl(t: var TObjectSet, obj: RootRef) = if mustRehash(len(t.data), t.counter): objectSetEnlarge(t) objectSetRawInsert(t.data, obj) inc(t.counter) -proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool = +proc objectSetContainsOrIncl(t: var TObjectSet, obj: RootRef): bool = # returns true if obj is already in the string table: var h: THash = hashNode(obj) and high(t.data) while true: @@ -516,7 +516,7 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool = inc(t.counter) result = false -proc tableRawGet(t: TTable, key: PObject): int = +proc tableRawGet(t: TTable, key: RootRef): int = var h: THash = hashNode(key) and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key == key: @@ -524,8 +524,8 @@ proc tableRawGet(t: TTable, key: PObject): int = h = nextTry(h, high(t.data)) result = -1 -proc tableSearch(t: TTable, key, closure: PObject, - comparator: TCmpProc): PObject = +proc tableSearch(t: TTable, key, closure: RootRef, + comparator: TCmpProc): RootRef = var h: THash = hashNode(key) and high(t.data) # start with real hash value while t.data[h].key != nil: if t.data[h].key == key: @@ -535,12 +535,12 @@ proc tableSearch(t: TTable, key, closure: PObject, h = nextTry(h, high(t.data)) result = nil -proc tableGet(t: TTable, key: PObject): PObject = +proc tableGet(t: TTable, key: RootRef): RootRef = var index = tableRawGet(t, key) if index >= 0: result = t.data[index].val else: result = nil -proc tableRawInsert(data: var TPairSeq, key, val: PObject) = +proc tableRawInsert(data: var TPairSeq, key, val: RootRef) = var h: THash = hashNode(key) and high(data) while data[h].key != nil: assert(data[h].key != key) @@ -556,7 +556,7 @@ proc tableEnlarge(t: var TTable) = if t.data[i].key != nil: tableRawInsert(n, t.data[i].key, t.data[i].val) swap(t.data, n) -proc tablePut(t: var TTable, key, val: PObject) = +proc tablePut(t: var TTable, key, val: RootRef) = var index = tableRawGet(t, key) if index >= 0: t.data[index].val = val @@ -626,6 +626,12 @@ proc strTableAdd(t: var TStrTable, n: PSym) = strTableRawInsert(t.data, n) inc(t.counter) +proc reallySameIdent(a, b: string): bool {.inline.} = + when defined(nimfix): + result = a[0] == b[0] + else: + result = true + proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} = # returns true if n is already in the string table: # It is essential that `n` is written nevertheless! @@ -635,7 +641,7 @@ proc strTableIncl*(t: var TStrTable, n: PSym): bool {.discardable.} = while true: var it = t.data[h] if it == nil: break - if it.name.id == n.name.id: + if it.name.id == n.name.id and reallySameIdent(it.name.s, n.name.s): t.data[h] = n # overwrite it with newer definition! return true # found it h = nextTry(h, high(t.data)) @@ -677,7 +683,7 @@ proc nextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym = ti.h = nextTry(h, high(tab.data)) proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, - excluding: TIntSet): PSym = + excluding: IntSet): PSym = var h: THash = ti.h and high(tab.data) var start = h result = tab.data[h] @@ -693,7 +699,7 @@ proc nextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, if result != nil and contains(excluding, result.id): result = nil proc firstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent, - excluding: TIntSet): PSym = + excluding: IntSet): PSym = ti.h = s.h ti.name = s if tab.counter == 0: result = nil @@ -740,22 +746,22 @@ proc idTableHasObjectAsKey(t: TIdTable, key: PIdObj): bool = if index >= 0: result = t.data[index].key == key else: result = false -proc idTableGet(t: TIdTable, key: PIdObj): PObject = +proc idTableGet(t: TIdTable, key: PIdObj): RootRef = var index = idTableRawGet(t, key.id) if index >= 0: result = t.data[index].val else: result = nil -proc idTableGet(t: TIdTable, key: int): PObject = +proc idTableGet(t: TIdTable, key: int): RootRef = var index = idTableRawGet(t, key) if index >= 0: result = t.data[index].val else: result = nil -iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] = +iterator pairs*(t: TIdTable): tuple[key: int, value: RootRef] = for i in 0..high(t.data): if t.data[i].key != nil: yield (t.data[i].key.id, t.data[i].val) -proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) = +proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: RootRef) = var h: THash h = key.id and high(data) while data[h].key != nil: @@ -765,7 +771,7 @@ proc idTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) = data[h].key = key data[h].val = val -proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) = +proc idTablePut(t: var TIdTable, key: PIdObj, val: RootRef) = var index: int n: TIdPairSeq @@ -784,7 +790,7 @@ proc idTablePut(t: var TIdTable, key: PIdObj, val: PObject) = idTableRawInsert(t.data, key, val) inc(t.counter) -iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: PObject] = +iterator idTablePairs*(t: TIdTable): tuple[key: PIdObj, val: RootRef] = for i in 0 .. high(t.data): if not isNil(t.data[i].key): yield (t.data[i].key, t.data[i].val) diff --git a/compiler/bitsets.nim b/compiler/bitsets.nim index 740bdd5ef..a2324f4e2 100644 --- a/compiler/bitsets.nim +++ b/compiler/bitsets.nim @@ -1,14 +1,14 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# this unit handles Nimrod sets; it implements bit sets -# the code here should be reused in the Nimrod standard library +# this unit handles Nim sets; it implements bit sets +# the code here should be reused in the Nim standard library type TBitSet* = seq[int8] # we use byte here to avoid issues with diff --git a/compiler/canonicalizer.nim b/compiler/canonicalizer.nim index 3bc4eb029..14448f0e8 100644 --- a/compiler/canonicalizer.nim +++ b/compiler/canonicalizer.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -370,7 +370,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = # the last entry of a symbol: if s.ast != nil: # we used to attempt to save space here by only storing a dummy AST if - # it is not necessary, but Nimrod's heavy compile-time evaluation features + # it is not necessary, but Nim's heavy compile-time evaluation features # make that unfeasible nowadays: encodeNode(w, s.info, s.ast, result) diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index adcc95e84..b01a81c5e 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -103,9 +103,9 @@ proc openArrayLoc(p: BProc, n: PNode): PRope = result = ropef("$1, $1Len0", [rdLoc(a)]) of tyString, tySequence: if skipTypes(n.typ, abstractInst).kind == tyVar: - result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField()]) + result = ropef("(*$1)->data, (*$1)->$2", [a.rdLoc, lenField(p)]) else: - result = ropef("$1->data, $1->$2", [a.rdLoc, lenField()]) + result = ropef("$1->data, $1->$2", [a.rdLoc, lenField(p)]) of tyArray, tyArrayConstr: result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]) else: internalError("openArrayLoc: " & typeToString(a.t)) diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b5817de05..75f0f3a42 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -15,7 +15,7 @@ proc intLiteral(i: BiggestInt): PRope = if (i > low(int32)) and (i <= high(int32)): result = toRope(i) elif i == low(int32): - # Nimrod has the same bug for the same reasons :-) + # Nim has the same bug for the same reasons :-) result = ~"(-2147483647 -1)" elif i > low(int64): result = rfmt(nil, "IL64($1)", toRope(i)) @@ -409,7 +409,6 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) = d.k = locData d.t = getUniqueType(t) d.r = r - d.a = -1 proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) = var a: TLoc @@ -425,7 +424,6 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) = d.k = locExpr d.t = getUniqueType(t) d.r = r - d.a = -1 proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = var a, b: TLoc @@ -723,7 +721,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) = internalError(e.info, "genRecordField") field = lookupInRecord(ty.n, f.name) if field != nil: break - if gCmd != cmdCompileToCpp: app(r, ".Sup") + if not p.module.compileToCpp: app(r, ".Sup") ty = getUniqueType(ty.sons[0]) if field == nil: internalError(e.info, "genRecordField 2 ") if field.loc.r == nil: internalError(e.info, "genRecordField 3") @@ -775,7 +773,7 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) = assert(ty.kind in {tyTuple, tyObject}) field = lookupInRecord(ty.n, f.name) if field != nil: break - if gCmd != cmdCompileToCpp: app(r, ".Sup") + if not p.module.compileToCpp: app(r, ".Sup") ty = getUniqueType(ty.sons[0]) if field == nil: internalError(e.info, "genCheckedRecordField") if field.loc.r == nil: @@ -842,11 +840,11 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) = if ty.kind == tyString: linefmt(p, cpsStmts, "if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(b), rdLoc(a), lenField()) + rdLoc(b), rdLoc(a), lenField(p)) else: linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(b), rdLoc(a), lenField()) + rdLoc(b), rdLoc(a), lenField(p)) if d.k == locNone: d.s = OnHeap d.heapRoot = a.r if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: @@ -908,7 +906,7 @@ proc gcUsage(n: PNode) = if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree) proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = - # <Nimrod code> + # <Nim code> # s = 'Hello ' & name & ', how do you feel?' & 'z' # # <generated C code> @@ -939,7 +937,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}: inc(L, len(e.sons[i + 1].strVal)) else: - appf(lens, "$1->$2 + ", [rdLoc(a), lenField()]) + appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)]) app(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a))) linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, toRope(L)) app(p.s(cpsStmts), appends) @@ -951,7 +949,7 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = gcUsage(e) proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = - # <Nimrod code> + # <Nim code> # s &= 'Hello ' & name & ', how do you feel?' & 'z' # // BUG: what if s is on the left side too? # <generated C code> @@ -979,7 +977,7 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}: inc(L, len(e.sons[i + 2].strVal)) else: - appf(lens, "$1->$2 + ", [rdLoc(a), lenField()]) + appf(lens, "$1->$2 + ", [rdLoc(a), lenField(p)]) app(appends, rfmt(p.module, "#appendString($1, $2);$n", rdLoc(dest), rdLoc(a))) linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n", @@ -992,7 +990,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq &= x --> # seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x)); # seq->data[seq->len-1] = x; - let seqAppendPattern = if gCmd != cmdCompileToCpp: + let seqAppendPattern = if not p.module.compileToCpp: "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n" else: "$1 = ($2) #incrSeq($1, sizeof($3));$n" @@ -1005,7 +1003,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = getTypeDesc(p.module, skipTypes(e.sons[2].typ, abstractVar))]) keepAlive(p, a) initLoc(dest, locExpr, b.t, OnHeap) - dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField()) + dest.r = rfmt(nil, "$1->data[$1->$2-1]", rdLoc(a), lenField(p)) genAssignment(p, dest, b, {needToCopy, afDestIsNil}) gcUsage(e) @@ -1099,7 +1097,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = while ty != nil: field = lookupInRecord(ty.n, it.sons[0].sym.name) if field != nil: break - if gCmd != cmdCompileToCpp: app(tmp2.r, ".Sup") + if not p.module.compileToCpp: app(tmp2.r, ".Sup") ty = getUniqueType(ty.sons[0]) if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr") if it.len == 3 and optFieldCheck in p.options: @@ -1200,8 +1198,8 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) = if t.kind != tyVar: nilCheck = r r = rfmt(nil, "(*$1)", r) t = skipTypes(t.lastSon, typedescInst) - if gCmd != cmdCompileToCpp: - while (t.kind == tyObject) and (t.sons[0] != nil): + 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): @@ -1246,7 +1244,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)])) of tyString, tySequence: putIntoDest(p, b, e.typ, - ropef("$1->data, $1->$2", [rdLoc(a), lenField()])) + 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))])) @@ -1289,7 +1287,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)") else: unaryExpr(p, e, d, "strlen($1)") of tyString, tySequence: - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)") else: unaryExpr(p, e, d, "$1->Sup.len") else: @@ -1307,7 +1305,7 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) var t = skipTypes(e.sons[1].typ, abstractVar) - let setLenPattern = if gCmd != cmdCompileToCpp: + let setLenPattern = if not p.module.compileToCpp: "$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n" else: "$1 = ($3) #setLengthSeq($1, sizeof($4), $2);$n" @@ -1508,7 +1506,6 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) = linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n", getTypeDesc(p.module, srct), getTypeDesc(p.module, destt), lbl) tmp.k = locExpr - tmp.a = -1 tmp.t = srct tmp.s = OnStack tmp.flags = {} @@ -1564,11 +1561,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""): initLocExpr(p, e.sons[2], x) putIntoDest(p, d, e.typ, - rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField())) + rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p))) elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""): initLocExpr(p, e.sons[1], x) putIntoDest(p, d, e.typ, - rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField())) + rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p))) else: binaryExpr(p, e, d, "#eqStrings($1, $2)") @@ -1827,7 +1824,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = if t.kind != tyVar: nilCheck = r r = ropef("(*$1)", [r]) t = skipTypes(t.lastSon, abstractInst) - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: while t.kind == tyObject and t.sons[0] != nil: app(r, ".Sup") t = skipTypes(t.sons[0], abstractInst) @@ -1845,7 +1842,7 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) = [getTypeDesc(p.module, dest), addrLoc(a)])) proc downConv(p: BProc, n: PNode, d: var TLoc) = - if gCmd == cmdCompileToCpp: + if p.module.compileToCpp: expr(p, n.sons[0], d) # downcast does C++ for us else: var dest = skipTypes(n.typ, abstractPtrs) @@ -2031,7 +2028,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = initLocExpr(p, n.sons[0], a) of nkAsmStmt: genAsmStmt(p, n) of nkTryStmt: - if gCmd == cmdCompileToCpp: genTryCpp(p, n, d) + if p.module.compileToCpp: genTryCpp(p, n, d) else: genTry(p, n, d) of nkRaiseStmt: genRaiseStmt(p, n) of nkTypeSection: @@ -2043,6 +2040,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) = 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): var prc = n.sons[namePos].sym diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 2d27257ce..36da68d23 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -83,7 +83,7 @@ proc writeTypeCache(a: TIdTable, s: var string) = inc i s.add('}') -proc writeIntSet(a: TIntSet, s: var string) = +proc writeIntSet(a: IntSet, s: var string) = var i = 0 for x in items(a): if i == 10: @@ -200,7 +200,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TIdTable) = idTablePut(result, newFakeType(key), value.toRope) inc L.bufpos -proc readIntSet(L: var TBaseLexer, result: var TIntSet) = +proc readIntSet(L: var TBaseLexer, result: var IntSet) = if ^L.bufpos != '{': internalError("ccgmerge: '{' expected") inc L.bufpos while ^L.bufpos != '}': @@ -249,7 +249,7 @@ proc readMergeInfo*(cfilename: string, m: BModule) = break type - TMergeSections = object {.pure.} + TMergeSections = object f: TCFileSections p: TCProcSections diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 8b0a8e9bb..1545da81b 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -46,7 +46,6 @@ proc genVarTuple(p: BProc, n: PNode) = if useLowering: genStmts(p, lowerTupleUnpacking(n, p.prc)) return - genLineDir(p, n) initLocExpr(p, n.sons[L-1], tup) var t = tup.t @@ -294,8 +293,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = var alreadyPoppedCnt = p.inExceptBlock for i in countup(1, howManyTrys): - - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: # Pop safe points generated by try if alreadyPoppedCnt > 0: dec alreadyPoppedCnt @@ -317,7 +315,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) = for i in countdown(howManyTrys-1, 0): p.nestedTryStmts.add(stack[i]) - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: # Pop exceptions that was handled by the # except-blocks we are in for i in countdown(howManyExcepts-1, 0): @@ -448,7 +446,7 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) = assert(t.sons[0].kind == nkSym) var sym = t.sons[0].sym sym.loc.k = locOther - sym.loc.a = p.breakIdx + sym.position = p.breakIdx+1 expr(p, t.sons[1], d) endBlock(p) @@ -487,7 +485,7 @@ proc genBreakStmt(p: BProc, t: PNode) = assert(t.sons[0].kind == nkSym) var sym = t.sons[0].sym assert(sym.loc.k == locOther) - idx = sym.loc.a + idx = sym.position-1 else: # an unnamed 'break' can only break a loop after 'transf' pass: while idx >= 0 and not p.blocks[idx].isLoop: dec idx @@ -501,8 +499,10 @@ proc genBreakStmt(p: BProc, t: PNode) = lineF(p, cpsStmts, "goto $1;$n", [label]) proc getRaiseFrmt(p: BProc): string = - if gCmd == cmdCompileToCpp: + if p.module.compileToCpp: result = "throw NimException($1, $2);$n" + elif getCompilerProc("Exception") != nil: + result = "#raiseException((#Exception*)$1, $2);$n" else: result = "#raiseException((#E_Base*)$1, $2);$n" @@ -520,10 +520,10 @@ proc genRaiseStmt(p: BProc, t: PNode) = var typ = skipTypes(t.sons[0].typ, abstractPtrs) genLineDir(p, t) lineCg(p, cpsStmts, getRaiseFrmt(p), [e, makeCString(typ.sym.name.s)]) - else: + else: genLineDir(p, t) # reraise the last exception: - if gCmd == cmdCompileToCpp: + if p.module.compileToCpp: line(p, cpsStmts, ~"throw;$n") else: linefmt(p, cpsStmts, "#reraiseException();$n") @@ -559,7 +559,7 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc, proc genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc, rangeFormat, eqFormat: TFormatStr, until: int, a: TLoc): TLabel = - # generate a C-if statement for a Nimrod case statement + # generate a C-if statement for a Nim case statement var labId = p.labels for i in 1..until: inc(p.labels) @@ -747,7 +747,10 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = i, length, blen: int genLineDir(p, t) exc = getTempName() - discard cgsym(p.module, "E_Base") + if getCompilerProc("Exception") != nil: + discard cgsym(p.module, "Exception") + else: + discard cgsym(p.module, "E_Base") add(p.nestedTryStmts, t) startBlock(p, "try {$n") expr(p, t.sons[0], d) @@ -829,7 +832,10 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = discard lists.includeStr(p.module.headerFiles, "<setjmp.h>") genLineDir(p, t) var safePoint = getTempName() - discard cgsym(p.module, "E_Base") + if getCompilerProc("Exception") != nil: + discard cgsym(p.module, "Exception") + else: + discard cgsym(p.module, "E_Base") linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint) linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint) if isDefined("nimStdSetjmp"): diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index c00b931ef..60bc0fc4b 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index a5bf9e7a7..8bb820283 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -49,8 +49,8 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, n: PNode) = genTraverseProc(c, ropef("$1.$2", accessor, field.loc.r), field.loc.t) else: internalError(n.info, "genTraverseProc()") -proc parentObj(accessor: PRope): PRope {.inline.} = - if gCmd != cmdCompileToCpp: +proc parentObj(accessor: PRope; m: BModule): PRope {.inline.} = + if not m.compileToCpp: result = ropef("$1.Sup", accessor) else: result = accessor @@ -71,7 +71,7 @@ proc genTraverseProc(c: var TTraversalClosure, accessor: PRope, typ: PType) = lineF(p, cpsStmts, "}$n") of tyObject: for i in countup(0, sonsLen(typ) - 1): - genTraverseProc(c, accessor.parentObj, typ.sons[i]) + genTraverseProc(c, accessor.parentObj(c.p.module), typ.sons[i]) if typ.n != nil: genTraverseProc(c, accessor, typ.n) of tyTuple: let typ = getUniqueType(typ) @@ -91,7 +91,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: PRope, typ: PType) = var i: TLoc getTemp(p, getSysType(tyInt), i) lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n", - i.r, accessor, toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len")) + i.r, accessor, toRope(if c.p.module.compileToCpp: "len" else: "Sup.len")) genTraverseProc(c, ropef("$1->data[$2]", accessor, i.r), typ.sons[0]) lineF(p, cpsStmts, "}$n") diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index fc6febc6f..fbdea7e66 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -162,7 +162,7 @@ proc mapReturnType(typ: PType): TCTypeKind = if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr else: result = mapType(typ) -proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope +proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope proc needsComplexAssignment(typ: PType): bool = result = containsGarbageCollectedRef(typ) @@ -228,7 +228,7 @@ proc fillResult(param: PSym) = incl(param.loc.flags, lfIndirect) param.loc.s = OnUnknown -proc getParamTypeDesc(m: BModule, t: PType, check: var TIntSet): PRope = +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) @@ -243,7 +243,7 @@ proc paramStorageLoc(param: PSym): TStorageLoc = result = OnUnknown proc genProcParams(m: BModule, t: PType, rettype, params: var PRope, - check: var TIntSet, declareEnvironment=true) = + check: var IntSet, declareEnvironment=true) = params = nil if (t.sons[0] == nil) or isInvalidReturnType(t.sons[0]): rettype = ~"void" @@ -342,8 +342,8 @@ proc getTypePre(m: BModule, typ: PType): PRope = proc structOrUnion(t: PType): PRope = (if tfUnion in t.flags: toRope("union") else: toRope("struct")) -proc getForwardStructFormat(): string = - if gCmd == cmdCompileToCpp: result = "$1 $2;$n" +proc getForwardStructFormat(m: BModule): string = + if m.compileToCpp: result = "$1 $2;$n" else: result = "typedef $1 $2 $2;$n" proc getTypeForward(m: BModule, typ: PType): PRope = @@ -355,7 +355,7 @@ proc getTypeForward(m: BModule, typ: PType): PRope = of tySequence, tyTuple, tyObject: result = getTypeName(typ) if not isImportedType(typ): - appf(m.s[cfsForwardTypes], getForwardStructFormat(), + appf(m.s[cfsForwardTypes], getForwardStructFormat(m), [structOrUnion(typ), result]) idTablePut(m.forwTypeCache, typ, result) else: internalError("getTypeForward(" & $typ.kind & ')') @@ -370,7 +370,7 @@ proc mangleRecFieldName(field: PSym, rectype: PType): PRope = proc genRecordFieldsAux(m: BModule, n: PNode, accessExpr: PRope, rectype: PType, - check: var TIntSet): PRope = + check: var IntSet): PRope = var ae, uname, sname, a: PRope k: PNode @@ -419,19 +419,19 @@ proc genRecordFieldsAux(m: BModule, n: PNode, appf(result, "$1 $2;$n", [getTypeDescAux(m, fieldType, check), sname]) else: internalError(n.info, "genRecordFieldsAux()") -proc getRecordFields(m: BModule, typ: PType, check: var TIntSet): PRope = +proc getRecordFields(m: BModule, typ: PType, check: var IntSet): PRope = result = genRecordFieldsAux(m, typ.n, nil, typ, check) proc getRecordDesc(m: BModule, typ: PType, name: PRope, - check: var TIntSet): PRope = + check: var IntSet): PRope = # declare the record: var hasField = false var attribute: PRope = - if tfPacked in typ.flags: toRope(CC[ccompiler].packedPragma) + if tfPacked in typ.flags: toRope(CC[cCompiler].packedPragma) else: nil - result = ropecg(m, CC[ccompiler].structStmtFmt, + result = ropecg(m, CC[cCompiler].structStmtFmt, [structOrUnion(typ), name, attribute]) if typ.kind == tyObject: @@ -442,7 +442,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope, else: appcg(m, result, " {$n#TNimType* m_type;$n", [name, attribute]) hasField = true - elif gCmd == cmdCompileToCpp: + elif m.compileToCpp: appcg(m, result, " : public $1 {$n", [getTypeDescAux(m, typ.sons[0], check)]) hasField = true @@ -461,7 +461,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: PRope, app(result, "};" & tnl) proc getTupleDesc(m: BModule, typ: PType, name: PRope, - check: var TIntSet): PRope = + check: var IntSet): PRope = result = ropef("$1 $2 {$n", [structOrUnion(typ), name]) var desc: PRope = nil for i in countup(0, sonsLen(typ) - 1): @@ -474,7 +474,7 @@ proc getTupleDesc(m: BModule, typ: PType, name: PRope, proc pushType(m: BModule, typ: PType) = add(m.typeStack, typ) -proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = +proc getTypeDescAux(m: BModule, typ: PType, check: var IntSet): PRope = # returns only the type's name var name, rettype, desc, recdesc: PRope @@ -538,7 +538,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = if result == nil: result = getTypeName(t) if not isImportedType(t): - appf(m.s[cfsForwardTypes], getForwardStructFormat(), + appf(m.s[cfsForwardTypes], getForwardStructFormat(m), [structOrUnion(t), result]) idTablePut(m.forwTypeCache, t, result) assert(cacheGetType(m.typeCache, t) == nil) @@ -550,7 +550,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = cSeq = "struct $2 {$n" & " #TGenericSeq Sup;$n" appcg(m, m.s[cfsSeqTypes], - (if gCmd == cmdCompileToCpp: cppSeq else: cSeq) & + (if m.compileToCpp: cppSeq else: cSeq) & " $1 data[SEQ_DECL_SIZE];$n" & "};$n", [getTypeDescAux(m, t.sons[0], check), result]) else: @@ -570,7 +570,7 @@ proc getTypeDescAux(m: BModule, typ: PType, check: var TIntSet): PRope = if result == nil: result = getTypeName(t) if not isImportedType(t): - appf(m.s[cfsForwardTypes], getForwardStructFormat(), + appf(m.s[cfsForwardTypes], getForwardStructFormat(m), [structOrUnion(t), result]) idTablePut(m.forwTypeCache, t, result) idTablePut(m.typeCache, t, result) # always call for sideeffects: @@ -898,7 +898,7 @@ include ccgtrav proc genDeepCopyProc(m: BModule; s: PSym; result: PRope) = genProc(m, s) - appf(m.s[cfsTypeInit3], "$1.deepcopy = (N_NIMCALL_PTR(void*, void*)) $2;$n", + appf(m.s[cfsTypeInit3], "$1.deepcopy =(void* (N_RAW_NIMCALL*)(void*))$2;$n", [result, s.loc.r]) proc genTypeInfo(m: BModule, t: PType): PRope = diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 65957584a..7396c0bf8 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -149,7 +149,7 @@ proc getUniqueType*(key: PType): PType = idTablePut(gTypeTable[k], key, key) result = key -proc tableGetType*(tab: TIdTable, key: PType): PObject = +proc tableGetType*(tab: TIdTable, key: PType): RootRef = # returns nil if we need to declare this type result = idTableGet(tab, key) if (result == nil) and (tab.counter > 0): @@ -171,7 +171,7 @@ proc mangle*(name: string): string = ## Lowercases the given name and manges any non-alphanumeric characters ## so they are represented as `HEX____`. If the name starts with a number, ## `N` is prepended - result = "" + result = newStringOfCap(name.len) case name[0] of Letters: result.add(name[0].toLower) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 359fa3309..afeac8c88 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -55,7 +55,7 @@ proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) = result.s = s result.t = getUniqueType(typ) result.r = nil - result.a = - 1 + #result.a = - 1 result.flags = {} proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) = @@ -63,7 +63,7 @@ proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) = if a.k == locNone: a.k = k a.t = getUniqueType(typ) - a.a = - 1 + #a.a = - 1 a.s = s if a.r == nil: a.r = r @@ -139,7 +139,7 @@ proc ropecg(m: BModule, frmt: TFormatStr, args: varargs[PRope]): PRope = if i - 1 >= start: app(result, substr(frmt, start, i - 1)) -const compileTimeRopeFmt = not defined(booting) +const compileTimeRopeFmt = false when compileTimeRopeFmt: import macros @@ -186,7 +186,7 @@ when compileTimeRopeFmt: while s[i] in IdentChars: inc i yield (kind: ffSym, value: substr(s, j, i-1), intValue: 0) start = i - else: nil + else: discard while i < length: if s[i] != '$' and s[i] != '#': inc i @@ -201,7 +201,7 @@ when compileTimeRopeFmt: ## the compilation of nimrod itself or will the macro execution time ## offset the gains? result = newCall(bindSym"ropeConcat") - for frag in fmtStringFragments(fmt.strVal): + for frag in fmtStringFragments(fmt): case frag.kind of ffSym: result.add(newCall(bindSym"cgsym", m, newStrLitNode(frag.value))) @@ -297,6 +297,9 @@ proc accessThreadLocalVar(p: BProc, s: PSym) proc emulatedThreadVars(): bool {.inline.} proc genProc(m: BModule, prc: PSym) +template compileToCpp(m: BModule): expr = + gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags + include "ccgtypes.nim" # ------------------------------ Manager of temporaries ------------------ @@ -326,7 +329,7 @@ proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc, var r = rdLoc(a) if not takeAddr: r = ropef("(*$1)", [r]) var s = skipTypes(t, abstractInst) - if gCmd != cmdCompileToCpp: + if not p.module.compileToCpp: while (s.kind == tyObject) and (s.sons[0] != nil): app(r, ".Sup") s = skipTypes(s.sons[0], abstractInst) @@ -407,7 +410,7 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = 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.a = - 1 result.t = getUniqueType(t) result.s = OnStack result.flags = {} @@ -425,7 +428,7 @@ proc keepAlive(p: BProc, toKeepAlive: TLoc) = [getTypeDesc(p.module, toKeepAlive.t), fid]) inc(p.gcFrameId) result.k = locTemp - result.a = -1 + #result.a = -1 result.t = toKeepAlive.t result.s = OnStack result.flags = {} @@ -506,7 +509,7 @@ proc assignLocalVar(p: BProc, s: PSym) = #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # app(decl, " GC_GUARD") if sfVolatile in s.flags or (p.nestedTryStmts.len > 0 and - gCmd != cmdCompileToCpp): + not p.module.compileToCpp): app(decl, " volatile") appf(decl, " $1;$n", [s.loc.r]) else: @@ -587,8 +590,8 @@ proc initLocExpr(p: BProc, e: PNode, result: var TLoc) = initLoc(result, locNone, e.typ, OnUnknown) expr(p, e, result) -proc lenField: PRope {.inline.} = - result = toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len") +proc lenField(p: BProc): PRope = + result = toRope(if p.module.compileToCpp: "len" else: "Sup.len") include ccgcalls, "ccgstmts.nim", "ccgexprs.nim" @@ -812,7 +815,12 @@ proc genProcAux(m: BModule, prc: PSym) = app(generatedProc, returnStmt) app(generatedProc, ~"}$N") app(m.s[cfsProcs], generatedProc) - + +proc crossesCppBoundary(m: BModule; sym: PSym): bool {.inline.} = + result = sfCompileToCpp in m.module.flags and + sfCompileToCpp notin sym.getModule().flags and + gCmd != cmdCompileToCpp + proc genProcPrototype(m: BModule, sym: PSym) = useHeader(m, sym) if lfNoDecl in sym.loc.flags: return @@ -824,6 +832,8 @@ proc genProcPrototype(m: BModule, sym: PSym) = 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): + header = con("extern \"C\" ", header) if sfPure in sym.flags and hasNakedAttribute in CC[cCompiler].props: header.app(" __attribute__((naked))") app(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header)) @@ -915,30 +925,30 @@ proc addIntTypes(result: var PRope) {.inline.} = appf(result, "#define NIM_INTBITS $1", [ platform.CPU[targetCPU].intSize.toRope]) -proc getCopyright(cfilenoext: string): PRope = +proc getCopyright(cfile: string): PRope = if optCompileOnly in gGlobalOptions: - result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" & + result = ropeff("/* Generated by Nim Compiler v$1 */$N" & "/* (c) 2014 Andreas Rumpf */$N" & "/* The generated code is subject to the original license. */$N", - "; Generated by Nimrod Compiler v$1$N" & + "; Generated by Nim Compiler v$1$N" & "; (c) 2012 Andreas Rumpf$N", [toRope(VersionAsString)]) else: - result = ropeff("/* Generated by Nimrod Compiler v$1 */$N" & + result = ropeff("/* Generated by Nim Compiler v$1 */$N" & "/* (c) 2014 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 Nimrod Compiler v$1$N" & + "; Generated by Nim Compiler v$1$N" & "; (c) 2014 Andreas Rumpf$N" & "; Compiled for: $2, $3, $4$N" & "; Command for LLVM compiler:$N $5$N", [toRope(VersionAsString), toRope(platform.OS[targetOS].name), toRope(platform.CPU[targetCPU].name), toRope(extccomp.CC[extccomp.cCompiler].name), - toRope(getCompileCFileCmd(cfilenoext))]) + toRope(getCompileCFileCmd(cfile))]) -proc getFileHeader(cfilenoext: string): PRope = - result = getCopyright(cfilenoext) +proc getFileHeader(cfile: string): PRope = + result = getCopyright(cfile) addIntTypes(result) proc genFilenames(m: BModule): PRope = @@ -1078,9 +1088,9 @@ proc registerModuleToMain(m: PSym) = var init = m.getInitName datInit = m.getDatInitName - appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N", + appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", "declare void $1() noinline$N", [init]) - appff(mainModProcs, "N_NOINLINE(void, $1)(void);$N", + appff(mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", "declare void $1() noinline$N", [datInit]) if sfSystemModule notin m.flags: appff(mainDatInit, "\t$1();$N", "call void ()* $1$n", [datInit]) @@ -1092,7 +1102,7 @@ proc registerModuleToMain(m: PSym) = proc genInitCode(m: BModule) = var initname = getInitName(m.module) - var prc = ropeff("N_NOINLINE(void, $1)(void) {$N", + var prc = ropeff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", "define void $1() noinline {$n", [initname]) if m.typeNodes > 0: appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n", @@ -1135,7 +1145,7 @@ proc genInitCode(m: BModule) = app(prc, deinitGCFrame(m.initProc)) appf(prc, "}$N$N") - prc.appff("N_NOINLINE(void, $1)(void) {$N", + prc.appff("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N", "define void $1() noinline {$n", [getDatInitName(m.module)]) for i in cfsTypeInit1..cfsDynLibInit: @@ -1155,8 +1165,8 @@ proc genInitCode(m: BModule) = (i.ord - '0'.ord).toRope, el) app(m.s[cfsInitProc], ex) -proc genModule(m: BModule, cfilenoext: string): PRope = - result = getFileHeader(cfilenoext) +proc genModule(m: BModule, cfile: string): PRope = + result = getFileHeader(cfile) result.app(genMergeInfo(m)) generateHeaders(m) @@ -1297,7 +1307,11 @@ proc writeHeader(m: BModule) = writeRope(result, m.filename) proc getCFile(m: BModule): string = - result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), cExt) + let ext = + if m.compileToCpp: ".cpp" + elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m" + else: ".c" + result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext) proc myOpenCached(module: PSym, rd: PRodReader): PPassContext = assert optSymbolFiles in gGlobalOptions @@ -1326,10 +1340,10 @@ proc finishModule(m: BModule) = dec(gForwardedProcsCounter, i) setLen(m.forwardedProcs, 0) -proc shouldRecompile(code: PRope, cfile, cfilenoext: string): bool = +proc shouldRecompile(code: PRope, cfile: string): bool = result = true if optForceFullMake notin gGlobalOptions: - var objFile = toObjFile(cfilenoext) + var objFile = toObjFile(cfile) if writeRopeIfNotEqual(code, cfile): return if existsFile(objFile) and os.fileNewer(objFile, cfile): result = false else: @@ -1354,26 +1368,26 @@ proc writeModule(m: BModule, pending: bool) = app(m.s[cfsProcHeaders], mainModProcs) generateThreadVarsSize(m) - var code = genModule(m, cfilenoext) + var code = genModule(m, cfile) when hasTinyCBackend: if gCmd == cmdRun: tccgen.compileCCode(ropeToStr(code)) return - if shouldRecompile(code, cfile, cfilenoext): - addFileToCompile(cfilenoext) + if shouldRecompile(code, cfile): + addFileToCompile(cfile) elif pending and mergeRequired(m) and sfMainModule notin m.module.flags: mergeFiles(cfile, m) genInitCode(m) finishTypeDescriptions(m) - var code = genModule(m, cfilenoext) + var code = genModule(m, cfile) writeRope(code, cfile) - addFileToCompile(cfilenoext) + addFileToCompile(cfile) elif not existsFile(toObjFile(cfilenoext)): # Consider: first compilation compiles ``system.nim`` and produces # ``system.c`` but then compilation fails due to an error. This means # that ``system.o`` is missing, so we need to call the C compiler for it: - addFileToCompile(cfilenoext) + addFileToCompile(cfile) addFileToLink(cfilenoext) @@ -1385,9 +1399,9 @@ proc updateCachedModule(m: BModule) = mergeFiles(cfile, m) genInitCode(m) finishTypeDescriptions(m) - var code = genModule(m, cfilenoext) + var code = genModule(m, cfile) writeRope(code, cfile) - addFileToCompile(cfilenoext) + addFileToCompile(cfile) addFileToLink(cfilenoext) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index 12041c55b..508f98074 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -62,7 +62,7 @@ type frameLen*: int16 TCProc{.final.} = object # represents C proc that is currently generated - prc*: PSym # the Nimrod proc that this C proc belongs to + prc*: PSym # the Nim proc that this C proc belongs to beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed threadVarAccessed*: bool # true if the proc already accessed some threadvar nestedTryStmts*: seq[PNode] # in how many nested try statements we are @@ -101,10 +101,10 @@ type # without extension) typeCache*: TIdTable # cache the generated types forwTypeCache*: TIdTable # cache for forward declarations of types - declaredThings*: TIntSet # things we have declared in this .c file - declaredProtos*: TIntSet # prototypes we have declared in this .c file + declaredThings*: IntSet # things we have declared in this .c file + declaredProtos*: IntSet # prototypes we have declared in this .c file headerFiles*: TLinkedList # needed headers to include - typeInfoMarker*: TIntSet # needed for generating type information + typeInfoMarker*: IntSet # needed for generating type information initProc*: BProc # code for init procedure postInitProc*: BProc # code to be executed after the init proc preInitProc*: BProc # code executed before the init proc diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 948541302..6703b1ba5 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -115,7 +115,7 @@ proc relevantCol(methods: TSymSeq, col: int): bool = if not sameType(t2, t): return true -proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int = +proc cmpSignatures(a, b: PSym, relevantCols: IntSet): int = for col in countup(1, sonsLen(a.typ) - 1): if contains(relevantCols, col): var aa = skipTypes(a.typ.sons[col], skipPtrs) @@ -124,7 +124,7 @@ proc cmpSignatures(a, b: PSym, relevantCols: TIntSet): int = if (d != high(int)): return d -proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) = +proc sortBucket(a: var TSymSeq, relevantCols: IntSet) = # we use shellsort here; fast and simple var n = len(a) var h = 1 @@ -143,7 +143,7 @@ proc sortBucket(a: var TSymSeq, relevantCols: TIntSet) = a[j] = v if h == 1: break -proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym = +proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym = var base = lastSon(methods[0].ast).sym result = base var paramLen = sonsLen(base.typ) diff --git a/compiler/commands.nim b/compiler/commands.nim index 87e94d9c9..f8f6a9a33 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -26,7 +26,7 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none") import os, msgs, options, nversion, condsyms, strutils, extccomp, platform, lists, - wordrecg, parseutils, babelcmd, idents + wordrecg, parseutils, nimblecmd, idents, parseopt # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") @@ -43,7 +43,7 @@ type TCmdLinePass* = enum passCmd1, # first pass over the command line passCmd2, # second pass over the command line - passPP # preprocessor called ProcessCommand() + passPP # preprocessor called processCommand() proc processCommand*(switch: string, pass: TCmdLinePass) proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) @@ -51,7 +51,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) # implementation const - HelpMessage = "Nimrod Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & + HelpMessage = "Nim Compiler Version $1 (" & CompileDate & ") [$2: $3]\n" & "Copyright (c) 2006-2014 by Andreas Rumpf\n" const @@ -280,14 +280,15 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = of "path", "p": expectArg(switch, arg, pass, info) addPath(processPath(arg), info) - of "babelpath": - if pass in {passCmd2, passPP} and not options.gNoBabelPath: + of "nimblepath", "babelpath": + # keep the old name for compat + if pass in {passCmd2, passPP} and not options.gNoNimblePath: expectArg(switch, arg, pass, info) let path = processPath(arg, notRelativeToProj=true) - babelpath(path, info) - of "nobabelpath": + nimblePath(path, info) + of "nonimblepath", "nobabelpath": expectNoArg(switch, arg, pass, info) - options.gNoBabelPath = true + options.gNoNimblePath = true of "excludepath": expectArg(switch, arg, pass, info) let path = processPath(arg) @@ -307,8 +308,7 @@ proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = expectArg(switch, arg, pass, info) options.docSeeSrcUrl = arg of "mainmodule", "m": - expectArg(switch, arg, pass, info) - optMainModule = arg + discard "allow for backwards compatibility, but don't do anything" of "define", "d": expectArg(switch, arg, pass, info) defineSymbol(arg) @@ -572,3 +572,33 @@ proc processCommand(switch: string, pass: TCmdLinePass) = var cmd, arg: string splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) processSwitch(cmd, arg, pass, gCmdLineInfo) + + +var + arguments* = "" + # the arguments to be passed to the program that + # should be run + +proc processSwitch*(pass: TCmdLinePass; p: OptParser) = + # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") + # we fix this here + var bracketLe = strutils.find(p.key, '[') + if bracketLe >= 0: + var key = substr(p.key, 0, bracketLe - 1) + var val = substr(p.key, bracketLe + 1) & ':' & p.val + processSwitch(key, val, pass, gCmdLineInfo) + else: + processSwitch(p.key, p.val, pass, gCmdLineInfo) + +proc processArgument*(pass: TCmdLinePass; p: OptParser; + argsCount: var int): bool = + if argsCount == 0: + options.command = p.key + else: + if pass == passCmd1: options.commandArgs.add p.key + if argsCount == 1: + # support UNIX style filenames anywhere for portable build scripts: + options.gProjectName = unixToNativePath(p.key) + arguments = cmdLineRest(p) + result = true + inc argsCount diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index 238dbf5c7..137ec409f 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -14,7 +14,7 @@ import # We need to use a PStringTable here as defined symbols are always guaranteed # to be style insensitive. Otherwise hell would break lose. -var gSymbols: PStringTable +var gSymbols: StringTableRef proc defineSymbol*(symbol: string) = gSymbols[symbol] = "true" @@ -60,7 +60,7 @@ const quick release debug useWinAnsi useFork useNimRtl useMalloc useRealtimeGC ssl memProfiler - nodejs kwin + nodejs kwin nimfix usesysassert usegcassert tinyC useFFI useStdoutAsStdmsg createNimRtl @@ -85,6 +85,7 @@ proc initDefines*() = defineSymbol("nimnewshared") defineSymbol("nimrequiresnimframe") defineSymbol("nimparsebiggestfloatmagic") + defineSymbol("nimalias") # add platform specific symbols: for c in low(CPU)..high(CPU): diff --git a/compiler/crc.nim b/compiler/crc.nim index ae1df3ff1..a8b61f2a5 100644 --- a/compiler/crc.nim +++ b/compiler/crc.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -102,7 +102,7 @@ proc crcFromFile(filename: string): TCrc32 = const bufSize = 8000 # don't use 8K for the memory allocator! var - bin: TFile + bin: File result = InitCrc32 if not open(bin, filename): return # not equal if file does not exist diff --git a/compiler/depends.nim b/compiler/depends.nim index a43eaf844..115a98f84 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 4c9803401..273fcb7f3 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -23,7 +23,7 @@ type id: int # for generating IDs toc, section: TSections indexValFilename: string - seenSymbols: PStringTable # avoids duplicate symbol generation for HTML. + seenSymbols: StringTableRef # avoids duplicate symbol generation for HTML. PDoc* = ref TDocumentor ## Alias to type less. @@ -55,7 +55,7 @@ proc parseRst(text, filename: string, result = rstParse(text, filename, line, column, hasToc, rstOptions, docgenFindFile, compilerMsgHandler) -proc newDocumentor*(filename: string, config: PStringTable): PDoc = +proc newDocumentor*(filename: string, config: StringTableRef): PDoc = new(result) initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex), options.gConfigVars, filename, {roSupportRawDirective}, @@ -374,11 +374,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = cleanPlainSymbol = renderPlainSymbolName(nameNode) complexSymbol = complexName(k, n, cleanPlainSymbol) plainSymbolRope = toRope(cleanPlainSymbol) - plainSymbolEncRope = toRope(URLEncode(cleanPlainSymbol)) + plainSymbolEncRope = toRope(encodeUrl(cleanPlainSymbol)) itemIDRope = toRope(d.id) symbolOrId = d.newUniquePlainSymbol(complexSymbol) symbolOrIdRope = symbolOrId.toRope - symbolOrIdEncRope = URLEncode(symbolOrId).toRope + symbolOrIdEncRope = encodeUrl(symbolOrId).toRope var seeSrcRope: PRope = nil let docItemSeeSrc = getConfigVar("doc.item.seesrc") @@ -411,7 +411,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = setIndexTerm(d[], symbolOrId, name, linkTitle, xmltree.escape(plainDocstring.docstringSummary)) -proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): PJsonNode = +proc genJSONItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = if not isVisible(nameNode): return var name = getName(d, nameNode) @@ -471,7 +471,7 @@ proc generateDoc*(d: PDoc, n: PNode) = of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) else: discard -proc generateJson(d: PDoc, n: PNode, jArray: PJsonNode = nil): PJsonNode = +proc generateJson(d: PDoc, n: PNode, jArray: JsonNode = nil): JsonNode = case n.kind of nkCommentStmt: if n.comment != nil and startsWith(n.comment, "##"): diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index d76be8e3c..aa832b6df 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -26,7 +26,7 @@ proc close(p: PPassContext, n: PNode): PNode = writeOutput(g.doc, g.module.filename, HtmlExt, useWarning) try: generateIndex(g.doc) - except EIO: + except IOError: discard proc processNode(c: PPassContext, n: PNode): PNode = diff --git a/compiler/evalffi.nim b/compiler/evalffi.nim index f798a43ac..d6b3a1aa5 100644 --- a/compiler/evalffi.nim +++ b/compiler/evalffi.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This file implements the FFI part of the evaluator for Nimrod code. +## This file implements the FFI part of the evaluator for Nim code. import ast, astalgo, ropes, types, options, tables, dynlib, libffi, msgs, os diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 78cdbb45f..78cc691c0 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index f0e5dad11..7d9744bc5 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -323,10 +323,7 @@ const var cCompiler* = ccGcc # the used compiler - - cExt* = ".c" # extension of generated C/C++ files - # (can be changed to .cpp later) - + gMixedMode*: bool # true if some module triggered C++ codegen cIncludes*: seq[string] = @[] # directories to search for included files cLibs*: seq[string] = @[] # directories to search for lib files cLinkedLibs*: seq[string] = @[] # libraries to link @@ -387,8 +384,6 @@ proc initVars*() = # we need to define the symbol here, because ``CC`` may have never been set! for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name) defineSymbol(CC[cCompiler].name) - if gCmd == cmdCompileToCpp: cExt = ".cpp" - elif gCmd == cmdCompileToOC: cExt = ".m" addCompileOption(getConfigVar(cCompiler, ".options.always")) addLinkOption(getConfigVar(cCompiler, ".options.linker")) if len(ccompilerpath) == 0: @@ -397,9 +392,9 @@ proc initVars*() = proc completeCFilePath*(cfile: string, createSubDir: bool = true): string = result = completeGeneratedFilePath(cfile, createSubDir) -proc toObjFile*(filenameWithoutExt: string): string = +proc toObjFile*(filename: string): string = # Object file for compilation - result = changeFileExt(filenameWithoutExt, CC[cCompiler].objExt) + result = changeFileExt(filename, CC[cCompiler].objExt) proc addFileToCompile*(filename: string) = appendStr(toCompile, filename) @@ -497,6 +492,7 @@ proc getCompilerExe(compiler: TSystemCC): string = proc getLinkerExe(compiler: TSystemCC): string = result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe + elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler else: compiler.getCompilerExe proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = @@ -507,11 +503,11 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = if needsExeExt(): exe = addFileExt(exe, "exe") if optGenDynLib in gGlobalOptions and - ospNeedsPIC in platform.OS[targetOS].props: + ospNeedsPIC in platform.OS[targetOS].props: add(options, ' ' & CC[c].pic) var includeCmd, compilePattern: string - if not noAbsolutePaths(): + if not noAbsolutePaths(): # compute include paths: includeCmd = CC[c].includeCmd & quoteShell(libpath) @@ -519,26 +515,27 @@ proc getCompileCFileCmd*(cfilename: string, isExternal = false): string = includeCmd.add([CC[c].includeCmd, includeDir.quoteShell]) compilePattern = joinPath(ccompilerpath, exe) - else: + else: includeCmd = "" compilePattern = c.getCompilerExe - var cfile = if noAbsolutePaths(): extractFilename(cfilename) + var cfile = if noAbsolutePaths(): extractFilename(cfilename) else: cfilename - var objfile = if not isExternal or noAbsolutePaths(): - toObjFile(cfile) - else: + var objfile = if not isExternal or noAbsolutePaths(): + toObjFile(cfile) + else: completeCFilePath(toObjFile(cfile)) - cfile = quoteShell(addFileExt(cfile, cExt)) objfile = quoteShell(objfile) result = quoteShell(compilePattern % [ - "file", cfile, "objfile", objfile, "options", options, - "include", includeCmd, "nimrod", getPrefixDir(), "lib", libpath]) + "file", cfile, "objfile", objfile, "options", options, + "include", includeCmd, "nimrod", getPrefixDir(), + "nim", getPrefixDir(), "lib", libpath]) add(result, ' ') addf(result, CC[c].compileTmpl, [ - "file", cfile, "objfile", objfile, - "options", options, "include", includeCmd, - "nimrod", quoteShell(getPrefixDir()), + "file", cfile, "objfile", objfile, + "options", options, "include", includeCmd, + "nimrod", quoteShell(getPrefixDir()), + "nim", quoteShell(getPrefixDir()), "lib", quoteShell(libpath)]) proc footprint(filename: string): TCrc32 = @@ -551,7 +548,7 @@ proc footprint(filename: string): TCrc32 = proc externalFileChanged(filename: string): bool = var crcFile = toGeneratedFile(filename.withPackageName, "crc") var currentCrc = int(footprint(filename)) - var f: TFile + var f: File if open(f, crcFile, fmRead): var line = newStringOfCap(40) if not f.readLine(line): line = "0" @@ -668,7 +665,7 @@ proc callCCompiler*(projectfile: string) = proc genMappingFiles(list: TLinkedList): PRope = var it = PStrEntry(list.head) while it != nil: - appf(result, "--file:r\"$1\"$N", [toRope(addFileExt(it.data, cExt))]) + appf(result, "--file:r\"$1\"$N", [toRope(it.data)]) it = PStrEntry(it.next) proc writeMapping*(gSymbolMapping: PRope) = diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 0014e9c78..7b975dbaa 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module implements Nimrod's standard template filter. +# This module implements Nim's standard template filter. import llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, @@ -148,7 +148,7 @@ proc parseLine(p: var TTmplParser) = inc(j) else: if p.x[j] == p.subsChar: - # parse Nimrod expression: + # parse Nim expression: inc(j) case p.x[j] of '{': diff --git a/compiler/filters.nim b/compiler/filters.nim index ce0ffd196..783a320a4 100644 --- a/compiler/filters.nim +++ b/compiler/filters.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module implements Nimrod's simple filters and helpers for filters. +# This module implements Nim's simple filters and helpers for filters. import llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, diff --git a/compiler/guards.nim b/compiler/guards.nim index 431de6156..cd0aaf296 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -838,6 +838,22 @@ proc addAsgnFact*(m: var TModel, key, value: PNode) = fact.sons[2] = value m.add fact +proc sameSubexprs*(m: TModel; a, b: PNode): bool = + # This should be used to check whether two *path expressions* refer to the + # same memory location according to 'm'. This is tricky: + # lock a[i].guard: + # ... + # access a[i].guarded + # + # Here a[i] is the same as a[i] iff 'i' and 'a' are not changed via '...'. + # However, nil checking requires exactly the same mechanism! But for now + # we simply use sameTree and live with the unsoundness of the analysis. + var check = newNodeI(nkCall, a.info, 3) + check.sons[0] = newSymNode(opEq) + check.sons[1] = a + check.sons[2] = b + result = m.doesImply(check) == impYes + proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) = let branch = n.sons[i] if branch.kind == nkOfBranch: diff --git a/compiler/hlo.nim b/compiler/hlo.nim index c75d6519f..363d100be 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/idents.nim b/compiler/idents.nim index ec903826a..775bffa00 100644 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -15,7 +15,7 @@ import hashes, strutils type - TIdObj* = object of TObject + TIdObj* = object of RootObj id*: int # unique id; use this for comparisons and not the pointers PIdObj* = ref TIdObj diff --git a/compiler/idgen.nim b/compiler/idgen.nim index d932e3d9d..3c5669b54 100644 --- a/compiler/idgen.nim +++ b/compiler/idgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -53,7 +53,7 @@ proc saveMaxIds*(project: string) = f.close() proc loadMaxIds*(project: string) = - var f: TFile + var f: File if open(f, project.toGid, fmRead): var line = newStringOfCap(20) if f.readLine(line): diff --git a/compiler/importer.nim b/compiler/importer.nim index b4cae017e..159dfa6a5 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -113,7 +113,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) = e = nextIdentIter(it, fromMod.tab) else: rawImportSymbol(c, s) -proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) = +proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) = var i: TTabIter var s = initTabIter(i, fromMod.tab) while s != nil: @@ -126,10 +126,10 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: TIntSet) = s = nextIter(i, fromMod.tab) proc importAllSymbols*(c: PContext, fromMod: PSym) = - var exceptSet: TIntSet + var exceptSet: IntSet importAllSymbolsExcept(c, fromMod, exceptSet) -proc importForwarded(c: PContext, n: PNode, exceptSet: TIntSet) = +proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) = if n.isNil: return case n.kind of nkExportStmt: @@ -164,7 +164,7 @@ proc myImportModule(c: PContext, n: PNode): PSym = proc evalImport(c: PContext, n: PNode): PNode = result = n - var emptySet: TIntSet + var emptySet: IntSet for i in countup(0, sonsLen(n) - 1): var m = myImportModule(c, n.sons[i]) if m != nil: diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index dfe498e47..4772aecb5 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -71,8 +71,8 @@ type TGlobals = object typeInfo, code: PRope forwarded: seq[PSym] - generatedSyms: TIntSet - typeInfoGenerated: TIntSet + generatedSyms: IntSet + typeInfoGenerated: IntSet PGlobals = ref TGlobals PProc = ref TProc @@ -724,7 +724,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) = if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock") var sym = n.sons[0].sym sym.loc.k = locOther - sym.loc.a = idx + sym.position = idx+1 setLen(p.blocks, idx + 1) p.blocks[idx].id = - p.unique # negative because it isn't used yet let labl = p.unique @@ -741,7 +741,7 @@ proc genBreakStmt(p: PProc, n: PNode) = assert(n.sons[0].kind == nkSym) let sym = n.sons[0].sym assert(sym.loc.k == locOther) - idx = sym.loc.a + idx = sym.position-1 else: # an unnamed 'break' can only break a loop after 'transf' pass: idx = len(p.blocks) - 1 @@ -1654,6 +1654,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) = r.res = nil of nkGotoState, nkState: internalError(n.info, "first class iterators not implemented") + of nkPragmaBlock: gen(p, n.lastSon, r) else: internalError(n.info, "gen: unknown node type: " & $n.kind) var globals: PGlobals @@ -1664,7 +1665,7 @@ proc newModule(module: PSym): BModule = if globals == nil: globals = newGlobals() proc genHeader(): PRope = - result = ropef("/* Generated by the Nimrod Compiler v$1 */$n" & + result = ropef("/* Generated by the Nim Compiler v$1 */$n" & "/* (c) 2014 Andreas Rumpf */$n$n" & "$nvar Globals = this;$n" & "var framePtr = null;$n" & diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index 009fc7935..8b032c3ce 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 62e13b9c4..194396ddd 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -128,7 +128,7 @@ type obj: PType PEnv = ref TEnv - TEnv {.final.} = object of TObject + TEnv {.final.} = object of RootObj attachedNode, replacementNode: PNode createdVar: PNode # if != nil it is a used environment; for closure # iterators this can be 'envParam.env' @@ -140,12 +140,12 @@ type fn: PSym # function that belongs to this scope; # if up.fn != fn then we cross function boundaries. # This is an important case to consider. - vars: TIntSet # variables belonging to this environment + vars: IntSet # variables belonging to this environment TOuterContext = object fn: PSym # may also be a module! head: PEnv - capturedVars, processed: TIntSet + capturedVars, processed: IntSet localsToAccess: TIdNodeTable lambdasToEnv: TIdTable # PSym->PEnv mapping diff --git a/compiler/lexer.nim b/compiler/lexer.nim index ea51a1399..cbc87972d 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -21,10 +21,10 @@ import const MaxLineLength* = 80 # lines longer than this lead to a warning - numChars*: TCharSet = {'0'..'9', 'a'..'z', 'A'..'Z'} - SymChars*: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'} - SymStartChars*: TCharSet = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} - OpChars*: TCharSet = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', + numChars*: set[char] = {'0'..'9', 'a'..'z', 'A'..'Z'} + SymChars*: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'} + SymStartChars*: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} + OpChars*: set[char] = {'+', '-', '*', '/', '\\', '<', '>', '!', '?', '^', '.', '|', '=', '%', '&', '$', '@', '~', ':', '\x80'..'\xFF'} # don't forget to update the 'highlite' module if these charsets should change @@ -102,7 +102,7 @@ type # so that it is the correct default value base2, base8, base16 - TToken* = object # a Nimrod token + 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 @@ -148,7 +148,7 @@ proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") proc isKeyword(kind: TTokType): bool = result = (kind >= tokKeywordLow) and (kind <= tokKeywordHigh) -proc isNimrodIdentifier*(s: string): bool = +proc isNimIdentifier*(s: string): bool = if s[0] in SymStartChars: var i = 1 while i < s.len: @@ -229,7 +229,7 @@ proc lexMessagePos(L: var TLexer, msg: TMsgKind, pos: int, arg = "") = var info = newLineInfo(L.fileIdx, L.lineNumber, pos - L.lineStart) msgs.message(info, msg, arg) -proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) = +proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) = var pos = L.bufpos # use registers for pos, buf var buf = L.buf while true: @@ -246,7 +246,7 @@ proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: TCharSet) = inc(pos) L.bufpos = pos -proc matchTwoChars(L: TLexer, first: char, second: TCharSet): bool = +proc matchTwoChars(L: TLexer, first: char, second: set[char]): bool = result = (L.buf[L.bufpos] == first) and (L.buf[L.bufpos + 1] in second) proc isFloatLiteral(s: string): bool = @@ -429,9 +429,9 @@ proc getNumber(L: var TLexer): TToken = elif result.tokType == tkInt16Lit and (result.iNumber < int16.low or result.iNumber > int16.high): lexMessage(L, errNumberOutOfRange, result.literal) - except EInvalidValue: + except ValueError: lexMessage(L, errInvalidNumber, result.literal) - except EOverflow, EOutOfRange: + except OverflowError, RangeError: lexMessage(L, errNumberOutOfRange, result.literal) L.bufpos = endpos @@ -482,7 +482,7 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) = add(tok.literal, VT) inc(L.bufpos) of 't', 'T': - add(tok.literal, Tabulator) + add(tok.literal, '\t') inc(L.bufpos) of '\'', '\"': add(tok.literal, L.buf[L.bufpos]) @@ -519,7 +519,7 @@ proc handleCRLF(L: var TLexer, pos: int): int = lexMessagePos(L, hintLineTooLong, pos) if optEmbedOrigSrc in gGlobalOptions: - let lineStart = cast[TAddress](L.buf) + L.lineStart + let lineStart = cast[ByteAddress](L.buf) + L.lineStart let line = newString(cast[cstring](lineStart), col) addSourceLine(L.fileIdx, line) @@ -659,28 +659,32 @@ proc getOperator(L: var TLexer, tok: var TToken) = if buf[pos] in {CR, LF, nimlexbase.EndOfFile}: tok.strongSpaceB = -1 -proc scanComment(L: var TLexer, tok: var TToken) = +proc scanComment(L: var TLexer, tok: var TToken) = var pos = L.bufpos - var buf = L.buf - # a comment ends if the next line does not start with the # on the same - # column after only whitespace + var buf = L.buf + when not defined(nimfix): + assert buf[pos+1] == '#' + if buf[pos+2] == '[': + lexMessagePos(L, warnDeprecated, pos, "use '## [' instead; '##['") tok.tokType = tkComment # iNumber contains the number of '\n' in the token tok.iNumber = 0 - var col = getColNumber(L, pos) + when defined(nimfix): + var col = getColNumber(L, pos) while true: var lastBackslash = -1 while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: if buf[pos] == '\\': lastBackslash = pos+1 add(tok.literal, buf[pos]) inc(pos) - if lastBackslash > 0: - # a backslash is a continuation character if only followed by spaces - # plus a newline: - while buf[lastBackslash] == ' ': inc(lastBackslash) - if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}: - # false positive: - lastBackslash = -1 + when defined(nimfix): + if lastBackslash > 0: + # a backslash is a continuation character if only followed by spaces + # plus a newline: + while buf[lastBackslash] == ' ': inc(lastBackslash) + if buf[lastBackslash] notin {CR, LF, nimlexbase.EndOfFile}: + # false positive: + lastBackslash = -1 pos = handleCRLF(L, pos) buf = L.buf @@ -688,9 +692,16 @@ proc scanComment(L: var TLexer, tok: var TToken) = while buf[pos] == ' ': inc(pos) inc(indent) - if buf[pos] == '#' and (col == indent or lastBackslash > 0): + + when defined(nimfix): + template doContinue(): expr = + buf[pos] == '#' and (col == indent or lastBackslash > 0) + else: + template doContinue(): expr = + buf[pos] == '#' and buf[pos+1] == '#' + if doContinue(): tok.literal.add "\n" - col = indent + when defined(nimfix): col = indent inc tok.iNumber else: if buf[pos] > ' ': @@ -707,7 +718,7 @@ proc skip(L: var TLexer, tok: var TToken) = of ' ': inc(pos) inc(tok.strongSpaceA) - of Tabulator: + of '\t': lexMessagePos(L, errTabulatorsAreNotAllowed, pos) inc(pos) of CR, LF: @@ -718,10 +729,24 @@ proc skip(L: var TLexer, tok: var TToken) = inc(pos) inc(indent) tok.strongSpaceA = 0 - if buf[pos] > ' ': + when defined(nimfix): + template doBreak(): expr = buf[pos] > ' ' + else: + template doBreak(): expr = + buf[pos] > ' ' and (buf[pos] != '#' or buf[pos+1] == '#') + if doBreak(): tok.indent = indent L.currLineIndent = indent break + of '#': + when defined(nimfix): + break + else: + # do not skip documentation comment: + if buf[pos+1] == '#': break + if buf[pos+1] == '[': + lexMessagePos(L, warnDeprecated, pos, "use '# [' instead; '#['") + while buf[pos] notin {CR, LF, nimlexbase.EndOfFile}: inc(pos) else: break # EndOfFile also leaves the loop L.bufpos = pos diff --git a/compiler/lists.nim b/compiler/lists.nim index efffe60fe..1b2b91bff 100644 --- a/compiler/lists.nim +++ b/compiler/lists.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,7 +12,7 @@ import os type PListEntry* = ref TListEntry - TListEntry* = object of TObject + TListEntry* = object of RootObj prev*, next*: PListEntry TStrEntry* = object of TListEntry diff --git a/compiler/llstream.nim b/compiler/llstream.nim index 5aefd468a..be469548d 100644 --- a/compiler/llstream.nim +++ b/compiler/llstream.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -21,9 +21,9 @@ type llsString, # stream encapsulates a string llsFile, # stream encapsulates a file llsStdIn # stream encapsulates stdin - TLLStream* = object of TObject + TLLStream* = object of RootObj kind*: TLLStreamKind # accessible for low-level access (lexbase uses this) - f*: TFile + f*: File s*: string rd*, wr*: int # for string streams lineOffset*: int # for fake stdin line numbers @@ -31,8 +31,8 @@ type PLLStream* = ref TLLStream proc llStreamOpen*(data: string): PLLStream -proc llStreamOpen*(f: var TFile): PLLStream -proc llStreamOpen*(filename: string, mode: TFileMode): PLLStream +proc llStreamOpen*(f: var File): PLLStream +proc llStreamOpen*(filename: string, mode: FileMode): PLLStream proc llStreamOpen*(): PLLStream proc llStreamOpenStdIn*(): PLLStream proc llStreamClose*(s: PLLStream) @@ -50,12 +50,12 @@ proc llStreamOpen(data: string): PLLStream = result.s = data result.kind = llsString -proc llStreamOpen(f: var TFile): PLLStream = +proc llStreamOpen(f: var File): PLLStream = new(result) result.f = f result.kind = llsFile -proc llStreamOpen(filename: string, mode: TFileMode): PLLStream = +proc llStreamOpen(filename: string, mode: FileMode): PLLStream = new(result) result.kind = llsFile if not open(result.f, filename, mode): result = nil diff --git a/compiler/lookups.nim b/compiler/lookups.nim index aee64f52f..07ac43f38 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ import intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread, - renderer, wordrecg, idgen + renderer, wordrecg, idgen, prettybase proc ensureNoMissingOrUnusedSymbols(scope: PScope) @@ -40,11 +40,8 @@ proc considerQuotedIdent*(n: PNode): PIdent = template addSym*(scope: PScope, s: PSym) = strTableAdd(scope.symbols, s) -proc addUniqueSym*(scope: PScope, s: PSym): TResult = - if strTableIncl(scope.symbols, s): - result = Failure - else: - result = Success +proc addUniqueSym*(scope: PScope, s: PSym): bool = + result = not strTableIncl(scope.symbols, s) proc openScope*(c: PContext): PScope {.discardable.} = result = PScope(parent: c.currentScope, @@ -65,6 +62,17 @@ iterator walkScopes*(scope: PScope): PScope = yield current current = current.parent +proc skipAlias*(s: PSym; n: PNode): PSym = + if s == nil or s.kind != skAlias: + result = s + else: + result = s.owner + if gCmd == cmdPretty: + prettybase.replaceDeprecated(n.info, s, result) + else: + message(n.info, warnDeprecated, "use " & result.name.s & " instead; " & + s.name.s) + proc localSearchInScope*(c: PContext, s: PIdent): PSym = result = strTableGet(c.currentScope.symbols, s) @@ -106,7 +114,7 @@ type mode*: TOverloadIterMode symChoiceIndex*: int scope*: PScope - inSymChoice: TIntSet + inSymChoice: IntSet proc getSymRepr*(s: PSym): string = case s.kind @@ -139,14 +147,14 @@ proc wrongRedefinition*(info: TLineInfo, s: string) = localError(info, errAttemptToRedefine, s) proc addDecl*(c: PContext, sym: PSym) = - if c.currentScope.addUniqueSym(sym) == Failure: + if not c.currentScope.addUniqueSym(sym): wrongRedefinition(sym.info, sym.name.s) proc addPrelimDecl*(c: PContext, sym: PSym) = discard c.currentScope.addUniqueSym(sym) proc addDeclAt*(scope: PScope, sym: PSym) = - if scope.addUniqueSym(sym) == Failure: + if not scope.addUniqueSym(sym): wrongRedefinition(sym.info, sym.name.s) proc addInterfaceDeclAux(c: PContext, sym: PSym) = @@ -163,7 +171,7 @@ proc addOverloadableSymAt*(scope: PScope, fn: PSym) = if fn.kind notin OverloadableSyms: internalError(fn.info, "addOverloadableSymAt") return - var check = strTableGet(scope.symbols, fn.name) + let check = strTableGet(scope.symbols, fn.name) if check != nil and check.kind notin OverloadableSyms: wrongRedefinition(fn.info, fn.name.s) else: @@ -179,20 +187,41 @@ proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) = addOverloadableSymAt(scope, sym) addInterfaceDeclAux(c, sym) +when defined(nimfix): + import strutils + + # when we cannot find the identifier, retry with a changed identifer: + proc altSpelling(x: PIdent): PIdent = + case x.s[0] + of 'A'..'Z': result = getIdent(toLower(x.s[0]) & x.s.substr(1)) + of 'a'..'z': result = getIdent(toLower(x.s[0]) & x.s.substr(1)) + else: result = x + + template fixSpelling(n: PNode; ident: PIdent; op: expr) = + let alt = ident.altSpelling + result = op(c, alt).skipAlias(n) + if result != nil: + prettybase.replaceDeprecated(n.info, ident, alt) + return result +else: + template fixSpelling(n: PNode; ident: PIdent; op: expr) = discard + proc lookUp*(c: PContext, n: PNode): PSym = # Looks up a symbol. Generates an error in case of nil. case n.kind of nkIdent: - result = searchInScopes(c, n.ident) - if result == nil: + result = searchInScopes(c, n.ident).skipAlias(n) + if result == nil: + fixSpelling(n, n.ident, searchInScopes) localError(n.info, errUndeclaredIdentifier, n.ident.s) result = errorSym(c, n) of nkSym: result = n.sym of nkAccQuoted: var ident = considerQuotedIdent(n) - result = searchInScopes(c, ident) + result = searchInScopes(c, ident).skipAlias(n) if result == nil: + fixSpelling(n, ident, searchInScopes) localError(n.info, errUndeclaredIdentifier, ident.s) result = errorSym(c, n) else: @@ -206,36 +235,38 @@ type TLookupFlag* = enum checkAmbiguity, checkUndeclared -proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym = +proc qualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym = case n.kind of nkIdent, nkAccQuoted: var ident = considerQuotedIdent(n) - result = searchInScopes(c, ident) - if result == nil and checkUndeclared in flags: + result = searchInScopes(c, ident).skipAlias(n) + if result == nil and checkUndeclared in flags: + fixSpelling(n, ident, searchInScopes) localError(n.info, errUndeclaredIdentifier, ident.s) result = errorSym(c, n) - elif checkAmbiguity in flags and result != nil and - contains(c.ambiguousSymbols, result.id): + elif checkAmbiguity in flags and result != nil and + contains(c.ambiguousSymbols, result.id): localError(n.info, errUseQualifier, ident.s) of nkSym: result = n.sym - if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id): + if checkAmbiguity in flags and contains(c.ambiguousSymbols, result.id): localError(n.info, errUseQualifier, n.sym.name.s) - of nkDotExpr: + of nkDotExpr: result = nil var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared}) - if (m != nil) and (m.kind == skModule): + if m != nil and m.kind == skModule: var ident: PIdent = nil - if n.sons[1].kind == nkIdent: + if n.sons[1].kind == nkIdent: ident = n.sons[1].ident - elif n.sons[1].kind == nkAccQuoted: + elif n.sons[1].kind == nkAccQuoted: ident = considerQuotedIdent(n.sons[1]) - if ident != nil: - if m == c.module: - result = strTableGet(c.topLevelScope.symbols, ident) - else: - result = strTableGet(m.tab, ident) - if result == nil and checkUndeclared in flags: + if ident != nil: + if m == c.module: + result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n) + else: + result = strTableGet(m.tab, ident).skipAlias(n) + if result == nil and checkUndeclared in flags: + fixSpelling(n.sons[1], ident, searchInScopes) localError(n.sons[1].info, errUndeclaredIdentifier, ident.s) result = errorSym(c, n.sons[1]) elif n.sons[1].kind == nkSym: @@ -256,7 +287,7 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = o.scope = c.currentScope o.mode = oimNoQualifier while true: - result = initIdentIter(o.it, o.scope.symbols, ident) + result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n) if result != nil: break else: @@ -277,11 +308,12 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = if ident != nil: if o.m == c.module: # a module may access its private members: - result = initIdentIter(o.it, c.topLevelScope.symbols, ident) + result = initIdentIter(o.it, c.topLevelScope.symbols, + ident).skipAlias(n) o.mode = oimSelfModule - else: - result = initIdentIter(o.it, o.m.tab, ident) - else: + else: + result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n) + else: localError(n.sons[1].info, errIdentifierExpected, renderTree(n.sons[1])) result = errorSym(c, n.sons[1]) @@ -307,18 +339,18 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = result = nil of oimNoQualifier: if o.scope != nil: - result = nextIdentIter(o.it, o.scope.symbols) + result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n) while result == nil: o.scope = o.scope.parent if o.scope == nil: break - result = initIdentIter(o.it, o.scope.symbols, o.it.name) + result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n) # BUGFIX: o.it.name <-> n.ident else: result = nil of oimSelfModule: - result = nextIdentIter(o.it, c.topLevelScope.symbols) + result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n) of oimOtherModule: - result = nextIdentIter(o.it, o.m.tab) + result = nextIdentIter(o.it, o.m.tab).skipAlias(n) of oimSymChoice: if o.symChoiceIndex < sonsLen(n): result = n.sons[o.symChoiceIndex].sym @@ -329,31 +361,27 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = o.mode = oimSymChoiceLocalLookup o.scope = c.currentScope result = firstIdentExcluding(o.it, o.scope.symbols, - n.sons[0].sym.name, o.inSymChoice) + n.sons[0].sym.name, o.inSymChoice).skipAlias(n) while result == nil: o.scope = o.scope.parent if o.scope == nil: break result = firstIdentExcluding(o.it, o.scope.symbols, - n.sons[0].sym.name, o.inSymChoice) + n.sons[0].sym.name, o.inSymChoice).skipAlias(n) of oimSymChoiceLocalLookup: - result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice) + result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n) while result == nil: o.scope = o.scope.parent if o.scope == nil: break result = firstIdentExcluding(o.it, o.scope.symbols, - n.sons[0].sym.name, o.inSymChoice) + n.sons[0].sym.name, o.inSymChoice).skipAlias(n) if result != nil and result.kind == skStub: loadStub(result) -when false: - proc qualifiedLookUpPreferImmediate*(c: PContext, n: PNode, - flags = {checkUndeclared}): PSym = - var o: TOverloadIter - result = initOverloadIter(o, c, n) - var a = result - while a != nil: - if sfImmediate in a.flags: return a - a = nextOverloadIter(o, c, n) - if result == nil and checkUndeclared in flags: - localError(n.info, errUndeclaredIdentifier, n.considerQuotedIdent.s) - result = errorSym(c, n) +proc pickSym*(c: PContext, n: PNode; kind: TSymKind; + flags: TSymFlags = {}): PSym = + var o: TOverloadIter + var a = initOverloadIter(o, c, n) + while a != nil: + if a.kind == kind and flags <= a.flags: + return a + a = nextOverloadIter(o, c, n) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index e1fb09e44..8e5ffd48a 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -261,7 +261,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner, barrier.typ, barrier) body.add varSection2 - body.add callCodeGenProc("barrierEnter", threadLocalBarrier.newSymNode) + body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode) var threadLocalProm: PSym if spawnKind == srByVar: threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv) @@ -276,7 +276,7 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode, "owner", fv.info), threadParam.newSymNode) - body.add callCodeGenProc("nimArgsPassingDone", threadParam.newSymNode) + body.add callCodegenProc("nimArgsPassingDone", threadParam.newSymNode) if spawnKind == srByVar: body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call) elif fv != nil: @@ -289,11 +289,11 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym; if barrier == nil: # by now 'fv' is shared and thus might have beeen overwritten! we need # to use the thread-local view instead: - body.add callCodeGenProc("nimFlowVarSignal", threadLocalProm.newSymNode) + body.add callCodegenProc("nimFlowVarSignal", threadLocalProm.newSymNode) else: body.add call if barrier != nil: - body.add callCodeGenProc("barrierLeave", threadLocalBarrier.newSymNode) + body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode) var params = newNodeI(nkFormalParams, f.info) params.add emptyNode @@ -543,7 +543,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; # create flowVar: result.add newFastAsgnStmt(fvField, callProc(spawnExpr[2])) if barrier == nil: - result.add callCodeGenProc("nimFlowVarCreateCondVar", fvField) + result.add callCodegenProc("nimFlowVarCreateCondVar", fvField) elif spawnKind == srByVar: var field = newSym(skField, getIdent"fv", owner, n.info) @@ -556,7 +556,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType; let wrapper = createWrapperProc(fn, threadParam, argsParam, varSection, varInit, call, barrierAsExpr, fvAsExpr, spawnKind) - result.add callCodeGenProc("nimSpawn", wrapper.newSymNode, + result.add callCodegenProc("nimSpawn", wrapper.newSymNode, genAddrOf(scratchObj.newSymNode)) if spawnKind == srFlowVar: result.add fvField diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 475326161..6d4c65268 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -35,7 +35,7 @@ proc registerSysType(t: PType) = proc newSysType(kind: TTypeKind, size: int): PType = result = newType(kind, systemModule) result.size = size - result.align = size + result.align = size.int16 proc getSysSym(name: string): PSym = result = strTableGet(systemModule.tab, getIdent(name)) @@ -44,6 +44,7 @@ proc getSysSym(name: string): PSym = result = newSym(skError, getIdent(name), systemModule, systemModule.info) result.typ = newType(tyError, systemModule) if result.kind == skStub: loadStub(result) + if result.kind == skAlias: result = result.owner proc getSysMagic*(name: string, m: TMagic): PSym = var ti: TIdentIter @@ -165,13 +166,14 @@ proc setIntLitType*(result: PNode) = proc getCompilerProc(name: string): PSym = var ident = getIdent(name, hashIgnoreStyle(name)) result = strTableGet(compilerprocs, ident) - if result == nil: + if result == nil: result = strTableGet(rodCompilerprocs, ident) - if result != nil: + if result != nil: strTableAdd(compilerprocs, result) if result.kind == skStub: loadStub(result) - -proc registerCompilerProc(s: PSym) = + if result.kind == skAlias: result = result.owner + +proc registerCompilerProc(s: PSym) = strTableAdd(compilerprocs, s) proc finishSystem(tab: TStrTable) = discard diff --git a/compiler/main.nim b/compiler/main.nim index b4af49248..82e55058c 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -15,8 +15,7 @@ import wordrecg, sem, semdata, idents, passes, docgen, extccomp, cgen, jsgen, json, nversion, platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, - tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists, - pretty + tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists from magicsys import systemModule, resetSysTypes @@ -164,19 +163,6 @@ proc commandEval(exp: string) = var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" evalNim(echoExp.parseString, makeStdinModule()) -proc commandPrettyOld = - var projectFile = addFileExt(mainCommandArg(), NimExt) - var module = parseFile(projectFile.fileInfoIdx) - if module != nil: - renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt)) - -proc commandPretty = - msgs.gErrorMax = high(int) # do not stop after first error - semanticPasses() - registerPass(prettyPass) - compileProject() - pretty.overwriteFiles() - proc commandScan = var f = addFileExt(mainCommandArg(), NimExt) var stream = llStreamOpen(f, fmRead) @@ -217,25 +203,6 @@ proc commandSuggest = else: gProjectMainIdx compileProject(projFile) -proc wantMainModule = - if gProjectFull.len == 0: - if optMainModule.len == 0: - fatal(gCmdLineInfo, errCommandExpectsFilename) - else: - gProjectName = optMainModule - gProjectFull = gProjectPath / gProjectName - - gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx - -proc requireMainModuleOption = - if optMainModule.len == 0: - fatal(gCmdLineInfo, errMainModuleMustBeSpecified) - else: - gProjectName = optMainModule - gProjectFull = gProjectPath / gProjectName - - gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx - proc resetMemory = resetCompilationLists() ccgutils.resetCaches() @@ -299,30 +266,22 @@ proc mainCommand* = # current path is always looked first for modules prependStr(searchPaths, gProjectPath) setId(100) - passes.gIncludeFile = includeModule - passes.gImportModule = importModule case command.normalize of "c", "cc", "compile", "compiletoc": # compile means compileToC currently gCmd = cmdCompileToC - wantMainModule() commandCompileToC() of "cpp", "compiletocpp": - extccomp.cExt = ".cpp" gCmd = cmdCompileToCpp if cCompiler == ccGcc: setCC("gcc") - wantMainModule() defineSymbol("cpp") commandCompileToC() of "objc", "compiletooc": - extccomp.cExt = ".m" gCmd = cmdCompileToOC - wantMainModule() defineSymbol("objc") commandCompileToC() of "run": gCmd = cmdRun - wantMainModule() when hasTinyCBackend: extccomp.setCC("tcc") commandCompileToC() @@ -330,41 +289,33 @@ proc mainCommand* = rawMessage(errInvalidCommandX, command) of "js", "compiletojs": gCmd = cmdCompileToJS - wantMainModule() commandCompileToJS() of "compiletollvm": gCmd = cmdCompileToLLVM - wantMainModule() when hasLLVM_Backend: CommandCompileToLLVM() else: rawMessage(errInvalidCommandX, command) - of "pretty": - gCmd = cmdPretty - wantMainModule() - commandPretty() of "doc": + wantMainModule() gCmd = cmdDoc loadConfigs(DocConfig) - wantMainModule() commandDoc() of "doc2": gCmd = cmdDoc loadConfigs(DocConfig) - wantMainModule() defineSymbol("nimdoc") commandDoc2() of "rst2html": gCmd = cmdRst2html loadConfigs(DocConfig) - wantMainModule() commandRst2Html() of "rst2tex": gCmd = cmdRst2tex loadConfigs(DocTexConfig) - wantMainModule() commandRst2TeX() of "jsondoc": + wantMainModule() gCmd = cmdDoc loadConfigs(DocConfig) wantMainModule() @@ -376,12 +327,11 @@ proc mainCommand* = commandBuildIndex() of "gendepend": gCmd = cmdGenDepend - wantMainModule() commandGenDepend() of "dump": gCmd = cmdDump if getConfigVar("dump.format") == "json": - requireMainModuleOption() + wantMainModule() var definedSymbols = newJArray() for s in definedSymbolNames(): definedSymbols.elems.add(%s) @@ -405,7 +355,6 @@ proc mainCommand* = for it in iterSearchPath(searchPaths): msgWriteln(it) of "check": gCmd = cmdCheck - wantMainModule() commandCheck() of "parse": gCmd = cmdParse @@ -429,7 +378,6 @@ proc mainCommand* = if gEvalExpr != "": commandEval(gEvalExpr) else: - wantMainModule() commandSuggest() of "serve": isServing = true diff --git a/compiler/modules.nim b/compiler/modules.nim index b102224cd..05b795473 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -117,7 +117,7 @@ proc newModule(fileIdx: int32): PSym = result.kind = skModule let filename = fileIdx.toFullPath result.name = getIdent(splitFile(filename).name) - if not isNimrodIdentifier(result.name.s): + if not isNimIdentifier(result.name.s): rawMessage(errInvalidModuleName, result.name.s) result.info = newLineInfo(fileIdx, 1, 1) @@ -177,7 +177,7 @@ proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} = proc `==^`(a, b: string): bool = try: result = sameFile(a, b) - except EOS: + except OSError: result = false proc compileSystemModule* = @@ -185,8 +185,18 @@ proc compileSystemModule* = systemFileIdx = fileInfoIdx(options.libpath/"system.nim") discard compileModule(systemFileIdx, {sfSystemModule}) -proc compileProject*(projectFile = gProjectMainIdx) = +proc wantMainModule* = + if gProjectFull.len == 0: + fatal(gCmdLineInfo, errCommandExpectsFilename) + gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx + +passes.gIncludeFile = includeModule +passes.gImportModule = importModule + +proc compileProject*(projectFileIdx = -1'i32) = + wantMainModule() let systemFileIdx = fileInfoIdx(options.libpath / "system.nim") + let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx if projectFile == systemFileIdx: discard compileModule(projectFile, {sfMainModule, sfSystemModule}) else: diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 730cb9605..8368fe5fd 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -119,12 +119,12 @@ type warnDifferentHeaps, warnWriteToForeignHeap, warnUnsafeCode, warnEachIdentIsTuple, warnShadowIdent, warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2, - warnUninit, warnGcMem, warnUser, + warnUninit, warnGcMem, warnUnguardedAccess, warnUser, hintSuccess, hintSuccessX, hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded, hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled, hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, - hintConditionAlwaysTrue, hintPattern, + hintConditionAlwaysTrue, hintName, hintPattern, hintUser const @@ -368,7 +368,7 @@ const warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored [OctalEscape]", warnXIsNeverRead: "\'$1\' is never read [XIsNeverRead]", warnXmightNotBeenInit: "\'$1\' might not have been initialized [XmightNotBeenInit]", - warnDeprecated: "\'$1\' is deprecated [Deprecated]", + warnDeprecated: "$1 is deprecated [Deprecated]", warnConfigDeprecated: "config file '$1' is deprecated [ConfigDeprecated]", warnSmallLshouldNotBeUsed: "\'l\' should not be used as an identifier; may look like \'1\' (one) [SmallLshouldNotBeUsed]", warnUnknownMagic: "unknown magic \'$1\' might crash the compiler [UnknownMagic]", @@ -387,9 +387,10 @@ const warnProveField: "cannot prove that field '$1' is accessible [ProveField]", warnProveIndex: "cannot prove index '$1' is valid [ProveIndex]", warnGcUnsafe: "not GC-safe: '$1' [GcUnsafe]", - warnGcUnsafe2: "cannot prove '$1' is GC-safe. This will become a compile time error in the future.", + warnGcUnsafe2: "cannot prove '$1' is GC-safe. Does not compile with --threads:on.", warnUninit: "'$1' might not have been initialized [Uninit]", warnGcMem: "'$1' uses GC'ed memory [GcMem]", + warnUnguardedAccess: "'$1' is accessed without its guard [UnguardedAccess]", warnUser: "$1 [User]", hintSuccess: "operation successful [Success]", hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#) [SuccessX]", @@ -405,11 +406,12 @@ const hintConf: "used config file \'$1\' [Conf]", hintPath: "added path: '$1' [Path]", hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]", + hintName: "name should be: '$1' [Name]", hintPattern: "$1 [Pattern]", hintUser: "$1 [User]"] const - WarningsToStr*: array[0..26, string] = ["CannotOpenFile", "OctalEscape", + WarningsToStr*: array[0..27, string] = ["CannotOpenFile", "OctalEscape", "XIsNeverRead", "XmightNotBeenInit", "Deprecated", "ConfigDeprecated", "SmallLshouldNotBeUsed", "UnknownMagic", @@ -418,12 +420,12 @@ const "AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap", "UnsafeCode", "EachIdentIsTuple", "ShadowIdent", "ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit", - "GcMem", "User"] + "GcMem", "UnguardedAccess", "User"] - HintsToStr*: array[0..15, string] = ["Success", "SuccessX", "LineTooLong", + HintsToStr*: array[0..16, string] = ["Success", "SuccessX", "LineTooLong", "XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded", "ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf", - "Path", "CondTrue", "Pattern", + "Path", "CondTrue", "Name", "Pattern", "User"] const @@ -441,7 +443,7 @@ type TNoteKinds* = set[TNoteKind] TFileInfo*{.final.} = object - fullPath*: string # This is a canonical full filesystem path + fullPath: string # This is a canonical full filesystem path projPath*: string # This is relative to the project's root shortName*: string # short name of the module quotedName*: PRope # cached quoted short name for codegen @@ -468,8 +470,8 @@ type TErrorOutputs* = set[TErrorOutput] - ERecoverableError* = object of EInvalidValue - ESuggestDone* = object of E_Base + ERecoverableError* = object of ValueError + ESuggestDone* = object of Exception const InvalidFileIDX* = int32(-1) @@ -567,7 +569,7 @@ var gErrorMax*: int = 1 # stop after gErrorMax errors when useCaas: - var stdoutSocket*: TSocket + var stdoutSocket*: Socket proc unknownLineInfo*(): TLineInfo = result.line = int16(-1) @@ -858,7 +860,7 @@ proc sourceLine*(i: TLineInfo): PRope = try: for line in lines(i.toFullPath): addSourceLine i.fileIndex, line.string - except EIO: + except IOError: discard internalAssert i.fileIndex < fileInfos.len # can happen if the error points to EOF: diff --git a/compiler/nimrod.ini b/compiler/nim.ini index 44e16cec8..3833a77cd 100644 --- a/compiler/nimrod.ini +++ b/compiler/nim.ini @@ -1,5 +1,5 @@ [Project] -Name: "Nimrod" +Name: "Nim" Version: "$version" Platforms: """ windows: i386;amd64 @@ -13,15 +13,15 @@ Platforms: """ """ Authors: "Andreas Rumpf" -Description: """This is the Nimrod Compiler. Nimrod is a new statically typed, +Description: """This is the Nim Compiler. Nim is a new statically typed, imperative programming language, that supports procedural, functional, object oriented and generic programming styles while remaining simple and efficient. -A special feature that Nimrod inherited from Lisp is that Nimrod's abstract +A special feature that Nim inherited from Lisp is that Nim's abstract syntax tree (AST) is part of the specification - this allows a powerful macro system which can be used to create domain specific languages. -Nimrod is a compiled, garbage-collected systems programming language -which has an excellent productivity/performance ratio. Nimrod's design +Nim is a compiled, garbage-collected systems programming language +which has an excellent productivity/performance ratio. Nim's design focuses on the 3E: efficiency, expressiveness, elegance (in the order of priority).""" @@ -58,7 +58,7 @@ Files: "icons/koch.res" Files: "icons/koch_icon.o" Files: "compiler/readme.txt" -Files: "compiler/nimrod.ini" +Files: "compiler/nim.ini" Files: "compiler/nimrod.cfg" Files: "compiler/*.nim" Files: "compiler/c2nim/*.nim" @@ -114,7 +114,7 @@ Files: "examples/*.tmpl" [Windows] -Files: "bin/nimrod.exe" +Files: "bin/nim.exe" Files: "bin/c2nim.exe" Files: "bin/niminst.exe" Files: "bin/nimgrep.exe" @@ -128,7 +128,7 @@ InnoSetup: "Yes" [UnixBin] -Files: "bin/nimrod" +Files: "bin/nim" [Unix] @@ -149,6 +149,5 @@ flags = "-w" [deb] buildDepends: "gcc (>= 4:4.3.2)" pkgDepends: "gcc (>= 4:4.3.2)" -shortDesc: "The Nimrod Compiler" -licenses: "bin/nimrod,MIT;lib/*,MIT;" - +shortDesc: "The Nim Compiler" +licenses: "bin/nim,MIT;lib/*,MIT;" diff --git a/compiler/nimrod.nim b/compiler/nim.nim index 618d98698..a87e0a1ac 100644 --- a/compiler/nimrod.nim +++ b/compiler/nim.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -40,7 +40,7 @@ proc handleCmdLine() = if gProjectName != "": try: gProjectFull = canonicalizePath(gProjectName) - except EOS: + except OSError: gProjectFull = gProjectName var p = splitFile(gProjectFull) gProjectPath = p.dir @@ -58,7 +58,7 @@ proc handleCmdLine() = if msgs.gErrorCounter == 0: when hasTinyCBackend: if gCmd == cmdRun: - tccgen.run(service.arguments) + tccgen.run(commands.arguments) if optRun in gGlobalOptions: if gCmd == cmdCompileToJS: var ex: string @@ -67,7 +67,7 @@ proc handleCmdLine() = else: ex = quoteShell( completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir)) - execExternalProgram("node " & ex & ' ' & service.arguments) + execExternalProgram("node " & ex & ' ' & commands.arguments) else: var binPath: string if options.outFile.len > 0: @@ -77,7 +77,7 @@ proc handleCmdLine() = # Figure out ourselves a valid binary name. binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir var ex = quoteShell(binPath) - execExternalProgram(ex & ' ' & service.arguments) + execExternalProgram(ex & ' ' & commands.arguments) when declared(GC_setMaxPause): GC_setMaxPause 2_000 diff --git a/compiler/nimrod.nimrod.cfg b/compiler/nim.nimrod.cfg index 2c6e6f249..ba7697c4c 100644 --- a/compiler/nimrod.nimrod.cfg +++ b/compiler/nim.nimrod.cfg @@ -1,6 +1,4 @@ -# Special configuration file for the Nimrod project - -mainModule:"nimrod.nim" +# Special configuration file for the Nim project # gc:markAndSweep @@ -21,3 +19,4 @@ define:useStdoutAsStdmsg cs:partial #define:useNodeIds +symbol:nimfix diff --git a/compiler/babelcmd.nim b/compiler/nimblecmd.nim index 7fa233732..049b94aa9 100644 --- a/compiler/babelcmd.nim +++ b/compiler/nimblecmd.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Implements some helper procs for Babel (Nimrod's package manager) support. +## Implements some helper procs for Nimble (Nim's package manager) support. import parseutils, strutils, strtabs, os, options, msgs, lists @@ -43,7 +43,7 @@ proc `<.`(a, b: string): bool = if a[i] == '.': inc i if b[j] == '.': inc j -proc addPackage(packages: PStringTable, p: string) = +proc addPackage(packages: StringTableRef, p: string) = let x = versionSplitPos(p) let name = p.substr(0, x-1) if x < p.len: @@ -53,12 +53,12 @@ proc addPackage(packages: PStringTable, p: string) = else: packages[name] = latest -iterator chosen(packages: PStringTable): string = +iterator chosen(packages: StringTableRef): string = for key, val in pairs(packages): let res = if val == latest: key else: key & '-' & val yield res -proc addBabelPath(p: string, info: TLineInfo) = +proc addNimblePath(p: string, info: TLineInfo) = if not contains(options.searchPaths, p): if gVerbosity >= 1: message(info, hintPath, p) lists.prependStr(options.lazyPaths, p) @@ -70,10 +70,10 @@ proc addPathWithNimFiles(p: string, info: TLineInfo) = result = true break if hasNimFile(p): - addBabelPath(p, info) + addNimblePath(p, info) else: for kind, p2 in walkDir(p): - if hasNimFile(p2): addBabelPath(p2, info) + if hasNimFile(p2): addNimblePath(p2, info) proc addPathRec(dir: string, info: TLineInfo) = var packages = newStringTable(modeStyleInsensitive) @@ -83,8 +83,8 @@ proc addPathRec(dir: string, info: TLineInfo) = if k == pcDir and p[pos] != '.': addPackage(packages, p) for p in packages.chosen: - addBabelPath(p, info) + addNimblePath(p, info) -proc babelPath*(path: string, info: TLineInfo) = +proc nimblePath*(path: string, info: TLineInfo) = addPathRec(path, info) - addBabelPath(path, info) + addNimblePath(path, info) diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index 136a0d454..98fe831d3 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -14,7 +14,7 @@ import options, idents, wordrecg # ---------------- configuration file parser ----------------------------- -# we use Nimrod's scanner here to safe space and work +# we use Nim's scanner here to safe space and work proc ppGetTok(L: var TLexer, tok: var TToken) = # simple filter @@ -224,8 +224,8 @@ proc loadConfigs*(cfg: string) = if libpath == "": # choose default libpath: var prefix = getPrefixDir() - if prefix == "/usr": libpath = "/usr/lib/nimrod" - elif prefix == "/usr/local": libpath = "/usr/local/lib/nimrod" + if prefix == "/usr": libpath = "/usr/lib/nim" + elif prefix == "/usr/local": libpath = "/usr/local/lib/nim" else: libpath = joinPath(prefix, "lib") if optSkipConfigFile notin gGlobalOptions: @@ -244,5 +244,6 @@ proc loadConfigs*(cfg: string) = if gProjectName.len != 0: # new project wide config file: - readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg")) - + let projectConfig = changeFileExt(gProjectFull, "nim.cfg") + if fileExists(projectConfig): readConfigFile(projectConfig) + else: readConfigFile(changeFileExt(gProjectFull, "nimrod.cfg")) diff --git a/compiler/nimeval.nim b/compiler/nimeval.nim index 0ee108d48..5693cbe91 100644 --- a/compiler/nimeval.nim +++ b/compiler/nimeval.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## exposes the Nimrod VM to clients. +## exposes the Nim VM to clients. import ast, modules, passes, passaux, condsyms, diff --git a/compiler/nimfix.nim b/compiler/nimfix.nim new file mode 100644 index 000000000..15174fd48 --- /dev/null +++ b/compiler/nimfix.nim @@ -0,0 +1,105 @@ +# +# +# The Nim Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Nimfix is a tool that helps to convert old-style Nimrod code to Nim code. + +import strutils, os, parseopt +import options, commands, modules, sem, passes, passaux, pretty, msgs, nimconf, + extccomp, condsyms, lists + +const Usage = """ +Nimfix - Tool to patch Nim code +Usage: + nimfix [options] projectflie.nim + +Options: + --overwriteFiles:on|off overwrite the original nim files. + DEFAULT is ON! + --onlyMainfile overwrite only the main file. + --checkExtern:on|off style check also extern names + --styleCheck:on|off|auto performs style checking for identifiers + and suggests an alternative spelling; + 'auto' corrects the spelling. + +In addition, all command line options of Nim are supported. +""" + +proc mainCommand = + #msgs.gErrorMax = high(int) # do not stop after first error + registerPass verbosePass + registerPass semPass + gCmd = cmdPretty + appendStr(searchPaths, options.libpath) + if gProjectFull.len != 0: + # current path is always looked first for modules + prependStr(searchPaths, gProjectPath) + + compileProject() + pretty.overwriteFiles() + +proc processCmdLine*(pass: TCmdLinePass, cmd: string) = + var p = parseopt.initOptParser(cmd) + var argsCount = 0 + while true: + parseopt.next(p) + case p.kind + of cmdEnd: break + of cmdLongoption, cmdShortOption: + case p.key.normalize + of "overwritefiles": + case p.val.normalize + of "on": gOverWrite = true + of "off": gOverWrite = false + else: localError(gCmdLineInfo, errOnOrOffExpected) + of "checkextern": + case p.val.normalize + of "on": gCheckExtern = true + of "off": gCheckExtern = false + else: localError(gCmdLineInfo, errOnOrOffExpected) + of "stylecheck": + case p.val.normalize + of "off": gStyleCheck = StyleCheck.None + of "on": gStyleCheck = StyleCheck.Warn + of "auto": gStyleCheck = StyleCheck.Auto + else: localError(gCmdLineInfo, errOnOrOffExpected) + of "onlymainfile": gOnlyMainfile = true + else: + processSwitch(pass, p) + of cmdArgument: + options.gProjectName = unixToNativePath(p.key) + # if processArgument(pass, p, argsCount): break + +proc handleCmdLine() = + if paramCount() == 0: + stdout.writeln(Usage) + else: + processCmdLine(passCmd1, "") + if gProjectName != "": + try: + gProjectFull = canonicalizePath(gProjectName) + except OSError: + gProjectFull = gProjectName + var p = splitFile(gProjectFull) + gProjectPath = p.dir + gProjectName = p.name + else: + gProjectPath = getCurrentDir() + loadConfigs(DefaultConfig) # load all config files + # now process command line arguments again, because some options in the + # command line can overwite the config file's settings + extccomp.initVars() + processCmdLine(passCmd2, "") + mainCommand() + +when compileOption("gc", "v2") or compileOption("gc", "refc"): + GC_disableMarkAndSweep() + +condsyms.initDefines() +defineSymbol "nimfix" +handleCmdline() diff --git a/compiler/nimfix.nim.cfg b/compiler/nimfix.nim.cfg new file mode 100644 index 000000000..61df6742e --- /dev/null +++ b/compiler/nimfix.nim.cfg @@ -0,0 +1,16 @@ +# Special configuration file for the Nim project +# gc:markAndSweep + +hint[XDeclaredButNotUsed]:off +path:"$projectPath/.." + +path:"$lib/packages/docutils" + +define:useStdoutAsStdmsg +symbol:nimfix +define:nimfix + +cs:partial +#define:useNodeIds +define:booting +define:noDocgen diff --git a/compiler/nimlexbase.nim b/compiler/nimlexbase.nim index 038573c35..e18e1c22a 100644 --- a/compiler/nimlexbase.nim +++ b/compiler/nimlexbase.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -37,7 +37,7 @@ const NewLines* = {CR, LF} type - TBaseLexer* = object of TObject + TBaseLexer* = object of RootObj bufpos*: int buf*: cstring bufLen*: int # length of buffer in characters diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index d65618e0a..aa7686d30 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# this unit handles Nimrod sets; it implements symbolic sets +# this unit handles Nim sets; it implements symbolic sets import ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer diff --git a/compiler/nversion.nim b/compiler/nversion.nim index bd1f79ac6..968feb081 100644 --- a/compiler/nversion.nim +++ b/compiler/nversion.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module contains Nimrod's version. It is the only place where it needs +# This module contains Nim's version. It is the only place where it needs # to be changed. const diff --git a/compiler/options.nim b/compiler/options.nim index 02719cacc..838f99f8e 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -68,7 +68,7 @@ type # please make sure we have under 32 options # also: generate header file TGlobalOptions* = set[TGlobalOption] - TCommands* = enum # Nimrod's commands + TCommands* = enum # Nim's commands # **keep binary compatible** cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc, @@ -114,7 +114,7 @@ var gDirtyBufferIdx* = 0'i32 # indicates the fileIdx of the dirty version of # the tracked source X, saved by the CAAS client. gDirtyOriginalIdx* = 0'i32 # the original source file of the dirtified buffer. - gNoBabelPath* = false + gNoNimblePath* = false proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc @@ -139,7 +139,7 @@ const JsonExt* = "json" TexExt* = "tex" IniExt* = "ini" - DefaultConfig* = "nimrod.cfg" + DefaultConfig* = "nim.cfg" DocConfig* = "nimdoc.cfg" DocTexConfig* = "nimdoc.tex.cfg" @@ -152,7 +152,6 @@ var gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/ gProjectFull* = "" # projectPath/projectName gProjectMainIdx*: int32 # the canonical path id of the main module - optMainModule* = "" # the main module that should be used for idetools commands nimcacheDir* = "" command* = "" # the main command (e.g. cc, check, scan, etc) commandArgs*: seq[string] = @[] # any arguments after the main command @@ -189,8 +188,8 @@ proc getPrefixDir*(): string = result = splitPath(getAppDir()).head proc canonicalizePath*(path: string): string = - result = path.expandFilename - when not FileSystemCaseSensitive: result = result.toLower + when not FileSystemCaseSensitive: result = path.expandFilename.toLower + else: result = path.expandFilename proc shortenDir*(dir: string): string = ## returns the interesting part of a dir @@ -238,6 +237,9 @@ proc getPackageName*(path: string): string = #echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name return packageCache[d] inc parents + for file in walkFiles(d / "*.nimble"): + result = file.splitFile.name + break packageSearch for file in walkFiles(d / "*.babel"): result = file.splitFile.name break packageSearch @@ -295,7 +297,7 @@ proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = createDir(subdir) when noTimeMachine: excludeDirFromTimeMachine(subdir) - except EOS: + except OSError: writeln(stdout, "cannot create directory: " & subdir) quit(1) result = joinPath(subdir, tail) @@ -335,6 +337,16 @@ proc findFile*(f: string): string {.procvar.} = proc findModule*(modulename, currentModule: string): string = # returns path to module + when defined(nimfix): + # '.nimfix' modules are preferred over '.nim' modules so that specialized + # versions can be kept for 'nimfix'. + block: + let m = addFileExt(modulename, "nimfix") + let currentPath = currentModule.splitFile.dir + result = currentPath / m + if not existsFile(result): + result = findFile(m) + if existsFile(result): return result let m = addFileExt(modulename, NimExt) let currentPath = currentModule.splitFile.dir result = currentPath / m diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index bbdba8c22..300abea1e 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/parser.nim b/compiler/parser.nim index 6ff0c2dfc..20c037c00 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module implements the parser of the standard Nimrod syntax. +# This module implements the parser of the standard Nim syntax. # The parser strictly reflects the grammar ("doc/grammar.txt"); however # it uses several helper routines to keep the parser small. A special # efficient algorithm is used for the precedence levels. The parser here can @@ -84,7 +84,7 @@ proc openParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream, proc openParser*(p: var TParser, filename: string, inputStream: PLLStream, strongSpaces=false) = - openParser(p, filename.fileInfoIdx, inputstream, strongSpaces) + openParser(p, filename.fileInfoIdx, inputStream, strongSpaces) proc closeParser(p: var TParser) = ## Close a parser, freeing up its resources. diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 0ba9f22d0..f754c80e5 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/passes.nim b/compiler/passes.nim index 66a1a4954..a63e29b35 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -16,7 +16,7 @@ import nimsets, syntaxes, times, rodread, idgen type - TPassContext* = object of TObject # the pass's context + TPassContext* = object of RootObj # the pass's context fromCache*: bool # true if created by "openCached" PPassContext* = ref TPassContext diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 5e21289b5..3d71aa4d1 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/pbraces.nim b/compiler/pbraces.nim index ce6e0d9a9..cf4dbffc5 100644 --- a/compiler/pbraces.nim +++ b/compiler/pbraces.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 024401b86..4d6d311c9 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -24,7 +24,7 @@ const wCompilerproc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge, wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl, - wGensym, wInject, wRaises, wTags, wUses, wOperator, wDelegator, wGcSafe, + wGensym, wInject, wRaises, wTags, wLocks, wDelegator, wGcSafe, wOverride} converterPragmas* = procPragmas methodPragmas* = procPragmas @@ -36,8 +36,8 @@ const iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideeffect, wSideeffect, wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern, wImportCpp, wImportObjC, wError, wDiscardable, wGensym, wInject, wRaises, - wTags, wUses, wOperator, wGcSafe} - exprPragmas* = {wLine} + wTags, wLocks, wGcSafe} + exprPragmas* = {wLine, wLocks} stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints, wLinedir, wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, @@ -45,27 +45,27 @@ const wBreakpoint, wWatchPoint, wPassl, wPassc, wDeadCodeElim, wDeprecated, wFloatchecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto, - wInjectStmt} + wInjectStmt, wDeprecated} lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, wNosideeffect, wSideeffect, wNoreturn, wDynlib, wHeader, wDeprecated, wExtern, wThread, wImportCpp, wImportObjC, wAsmNoStackFrame, - wRaises, wUses, wTags, wGcSafe} + wRaises, wLocks, wTags, wGcSafe} typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, wPure, wHeader, wCompilerproc, wFinal, wSize, wExtern, wShallow, wImportCpp, wImportObjC, wError, wIncompleteStruct, wByCopy, wByRef, wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, wBorrow, wGcSafe} fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern, - wImportCpp, wImportObjC, wError} + wImportCpp, wImportObjC, wError, wGuard} varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, wMagic, wHeader, wDeprecated, wCompilerproc, wDynlib, wExtern, wImportCpp, wImportObjC, wError, wNoInit, wCompileTime, wGlobal, - wGensym, wInject, wCodegenDecl} + wGensym, wInject, wCodegenDecl, wGuard} constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl, wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect, - wThread, wRaises, wUses, wTags, wGcSafe} + wThread, wRaises, wLocks, wTags, wGcSafe} allRoutinePragmas* = procPragmas + iteratorPragmas + lambdaPragmas proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) @@ -128,12 +128,17 @@ proc processImportCpp(s: PSym, extname: string) = incl(s.flags, sfImportc) incl(s.flags, sfInfixCall) excl(s.flags, sfForward) + let m = s.getModule() + incl(m.flags, sfCompileToCpp) + extccomp.gMixedMode = true proc processImportObjC(s: PSym, extname: string) = setExternName(s, extname) incl(s.flags, sfImportc) incl(s.flags, sfNamedParamCall) excl(s.flags, sfForward) + let m = s.getModule() + incl(m.flags, sfCompileToObjC) proc newEmptyStrNode(n: PNode): PNode {.noinline.} = result = newNodeIT(nkStrLit, n.info, getSysType(tyString)) @@ -514,26 +519,27 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) = else: invalidPragma(n) -proc pragmaUses(c: PContext, n: PNode) = - proc processExc(c: PContext, x: PNode): PNode = - if x.kind in {nkAccQuoted, nkIdent, nkSym, - nkOpenSymChoice, nkClosedSymChoice}: - if considerQuotedIdent(x).s == "*": - return newSymNode(ast.anyGlobal) - result = c.semExpr(c, x) - if result.kind != nkSym or sfGlobal notin result.sym.flags: - localError(x.info, "'$1' is not a global variable" % result.renderTree) - result = newSymNode(ast.anyGlobal) - - if n.kind == nkExprColonExpr: - let it = n.sons[1] - if it.kind notin {nkCurly, nkBracket}: - n.sons[1] = processExc(c, it) +proc pragmaLockStmt(c: PContext; it: PNode) = + if it.kind != nkExprColonExpr: + invalidPragma(it) + else: + let n = it[1] + if n.kind != nkBracket: + localError(n.info, errGenerated, "locks pragma takes a list of expressions") else: - for i in 0 .. <it.len: - it.sons[i] = processExc(c, it.sons[i]) + for i in 0 .. <n.len: + n.sons[i] = c.semExpr(c, n.sons[i]) + +proc pragmaLocks(c: PContext, it: PNode): TLockLevel = + if it.kind != nkExprColonExpr: + invalidPragma(it) else: - invalidPragma(n) + if it[1].kind != nkNilLit: + let x = expectIntLit(c, it) + if x < 0 or x > MaxLockLevel: + localError(it[1].info, "integer must be within 0.." & $MaxLockLevel) + else: + result = TLockLevel(x) proc typeBorrow(sym: PSym, n: PNode) = if n.kind == nkExprColonExpr: @@ -542,11 +548,50 @@ proc typeBorrow(sym: PSym, n: PNode) = localError(n.info, "a type can only borrow `.` for now") incl(sym.typ.flags, tfBorrowDot) +proc markCompilerProc(s: PSym) = + makeExternExport(s, "$1", s.info) + incl(s.flags, sfCompilerProc) + incl(s.flags, sfUsed) + registerCompilerProc(s) + +proc deprecatedStmt(c: PContext; pragma: PNode) = + let pragma = pragma[1] + if pragma.kind != nkBracket: + localError(pragma.info, "list of key:value pairs expected"); return + for n in pragma: + if n.kind in {nkExprColonExpr, nkExprEqExpr}: + let dest = qualifiedLookUp(c, n[1]) + let src = considerQuotedIdent(n[0]) + let alias = newSym(skAlias, src, dest, n[0].info) + incl(alias.flags, sfExported) + if sfCompilerProc in dest.flags: markCompilerProc(alias) + addInterfaceDecl(c, alias) + else: + localError(n.info, "key:value pair expected") + +proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym = + if it.kind != nkExprColonExpr: + invalidPragma(it); return + let n = it[1] + if n.kind == nkSym: + result = n.sym + elif kind == skField: + # First check if the guard is a global variable: + result = qualifiedLookUp(c, n, {}) + if result.isNil or result.kind notin {skLet, skVar} or + sfGlobal notin result.flags: + # We return a dummy symbol; later passes over the type will repair it. + # Generic instantiation needs to know about this too. But we're lazy + # and perform the lookup on demand instead. + result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info) + else: + result = qualifiedLookUp(c, n) + proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, validPragmas: TSpecialWords): bool = var it = n.sons[i] var key = if it.kind == nkExprColonExpr: it.sons[0] else: it - if key.kind == nkIdent: + if key.kind == nkIdent: var userPragma = strTableGet(c.userPragmas, key.ident) if userPragma != nil: inc c.instCounter @@ -578,11 +623,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, of wAlign: if sym.typ == nil: invalidPragma(it) var align = expectIntLit(c, it) - if not isPowerOfTwo(align) and align != 0: + if (not isPowerOfTwo(align) and align != 0) or align >% high(int16): localError(it.info, errPowerOfTwoExpected) else: - sym.typ.align = align - of wSize: + sym.typ.align = align.int16 + of wSize: if sym.typ == nil: invalidPragma(it) var size = expectIntLit(c, it) if not isPowerOfTwo(size) or size <= 0 or size > 8: @@ -648,17 +693,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, processDynLib(c, it, sym) of wCompilerproc: noVal(it) # compilerproc may not get a string! - if sfFromGeneric notin sym.flags: - makeExternExport(sym, "$1", it.info) - incl(sym.flags, sfCompilerProc) - incl(sym.flags, sfUsed) # suppress all those stupid warnings - registerCompilerProc(sym) - of wProcVar: + if sfFromGeneric notin sym.flags: markCompilerProc(sym) + of wProcVar: noVal(it) incl(sym.flags, sfProcvar) - of wDeprecated: - noVal(it) - if sym != nil: incl(sym.flags, sfDeprecated) + of wDeprecated: + if it.kind == nkExprColonExpr: deprecatedStmt(c, it) + elif sym != nil: incl(sym.flags, sfDeprecated) else: incl(c.module.flags, sfDeprecated) of wVarargs: noVal(it) @@ -789,10 +830,15 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int, if sym == nil: invalidPragma(it) of wLine: pragmaLine(c, it) of wRaises, wTags: pragmaRaisesOrTags(c, it) - of wUses: pragmaUses(c, it) - of wOperator: - if sym == nil: invalidPragma(it) - else: sym.position = expectIntLit(c, it) + of wLocks: + if sym == nil: pragmaLockStmt(c, it) + elif sym.typ == nil: invalidPragma(it) + else: sym.typ.lockLevel = pragmaLocks(c, it) + of wGuard: + if sym == nil or sym.kind notin {skVar, skLet, skField}: + invalidPragma(it) + else: + sym.guard = pragmaGuard(c, it, sym.kind) of wInjectStmt: if it.kind != nkExprColonExpr: localError(it.info, errExprExpected) diff --git a/compiler/pretty.nim b/compiler/pretty.nim index 17311f9e6..acac574af 100644 --- a/compiler/pretty.nim +++ b/compiler/pretty.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -8,60 +8,38 @@ # ## This module implements the code "prettifier". This is part of the toolchain -## to convert Nimrod code into a consistent style. +## to convert Nim code into a consistent style. import - strutils, os, options, ast, astalgo, msgs, ropes, idents, passes, - intsets, strtabs, semdata - -const - removeTP = false # when true, "nimrod pretty" converts TTyp to Typ. + strutils, os, options, ast, astalgo, msgs, ropes, idents, + intsets, strtabs, semdata, prettybase type - TGen = object of TPassContext - module*: PSym - PGen = ref TGen - - TSourceFile = object - lines: seq[string] - dirty: bool - fullpath: string + StyleCheck* {.pure.} = enum None, Warn, Auto var - gSourceFiles: seq[TSourceFile] = @[] - gCheckExtern: bool - rules: PStringTable - -proc loadFile(info: TLineInfo) = - let i = info.fileIndex - if i >= gSourceFiles.len: - gSourceFiles.setLen(i+1) - if gSourceFiles[i].lines.isNil: - gSourceFiles[i].lines = @[] - let path = info.toFullPath - gSourceFiles[i].fullpath = path - # we want to die here for EIO: - for line in lines(path): - gSourceFiles[i].lines.add(line) + gOverWrite* = true + gStyleCheck*: StyleCheck + gCheckExtern*, gOnlyMainfile*: bool proc overwriteFiles*() = - let overWrite = options.getConfigVar("pretty.overwrite").normalize == "on" let doStrip = options.getConfigVar("pretty.strip").normalize == "on" for i in 0 .. high(gSourceFiles): - if not gSourceFiles[i].dirty: continue - let newFile = if overWrite: gSourceFiles[i].fullpath - else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim") - try: - var f = open(newFile, fmWrite) - for line in gSourceFiles[i].lines: - if doStrip: - f.write line.strip(leading = false, trailing = true) - else: - f.write line - f.write("\L") - f.close - except EIO: - rawMessage(errCannotOpenFile, newFile) + if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and + (not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx): + let newFile = if gOverWrite: gSourceFiles[i].fullpath + else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim") + try: + var f = open(newFile, fmWrite) + for line in gSourceFiles[i].lines: + if doStrip: + f.write line.strip(leading = false, trailing = true) + else: + f.write line + f.write(gSourceFiles[i].newline) + f.close + except IOError: + rawMessage(errCannotOpenFile, newFile) proc `=~`(s: string, a: openArray[string]): bool = for x in a: @@ -78,9 +56,6 @@ proc beautifyName(s: string, k: TSymKind): string = case k of skType, skGenericParam: # Types should start with a capital unless builtins like 'int' etc.: - when removeTP: - if s[0] == 'T' and s[1] in {'A'..'Z'}: - i = 1 if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string", "char", "byte", "bool", "openArray", "seq", "array", "void", "pointer", "float", "csize", "cdouble", "cchar", "cschar", @@ -115,167 +90,63 @@ proc beautifyName(s: string, k: TSymKind): string = result.add s[i] inc i -proc checkStyle*(info: TLineInfo, s: string, k: TSymKind) = - let beau = beautifyName(s, k) - if s != beau: - message(info, errGenerated, "name should be: " & beau) - -const - Letters = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'} - -proc identLen(line: string, start: int): int = - while start+result < line.len and line[start+result] in Letters: - inc result - -proc differ(line: string, a, b: int, x: string): bool = - let y = line[a..b] - result = cmpIgnoreStyle(y, x) == 0 and y != x - when false: - var j = 0 - for i in a..b: - if line[i] != x[j]: return true - inc j - return false - -proc checkDef*(n: PNode; s: PSym) = - # operators stay as they are: - if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return - if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return - - if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern: - checkStyle(n.info, s.name.s, s.kind) - -proc checkDef(c: PGen; n: PNode) = - if n.kind != nkSym: return - checkDef(n, n.sym) - -proc checkUse*(info: TLineInfo; s: PSym) = - if info.fileIndex < 0: return - # we simply convert it to what it looks like in the definition - # for consistency - - # operators stay as they are: - if s.kind in {skResult, skTemp} or s.name.s[0] notin Letters: return - if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return - let newName = s.name.s - +proc replaceInFile(info: TLineInfo; newName: string) = loadFile(info) let line = gSourceFiles[info.fileIndex].lines[info.line-1] var first = min(info.col.int, line.len) if first < 0: return #inc first, skipIgnoreCase(line, "proc ", first) - while first > 0 and line[first-1] in Letters: dec first + while first > 0 and line[first-1] in prettybase.Letters: dec first if first < 0: return if line[first] == '`': inc first let last = first+identLen(line, first)-1 if differ(line, first, last, newName): # last-first+1 != newName.len or - var x = line.substr(0, first-1) & newName & line.substr(last+1) - when removeTP: - # the WinAPI module is full of 'TX = X' which after the substitution - # becomes 'X = X'. We remove those lines: - if x.match(peg"\s* {\ident} \s* '=' \s* y$1 ('#' .*)?"): - x = "" - + var x = line.substr(0, first-1) & newName & line.substr(last+1) system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x) gSourceFiles[info.fileIndex].dirty = true -when false: - var cannotRename = initIntSet() - - proc beautifyName(s: string, k: TSymKind): string = - let allUpper = allCharsInSet(s, {'A'..'Z', '0'..'9', '_'}) - result = newStringOfCap(s.len) - var i = 0 - case k - of skType, skGenericParam: - # skip leading 'T' - when removeTP: - if s[0] == 'T' and s[1] in {'A'..'Z'}: - i = 1 - if s =~ ["int", "uint", "cint", "cuint", "clong", "cstring", "string", - "char", "byte", "bool", "openArray", "seq", "array", "void", - "pointer", "float", "csize", "cdouble", "cchar", "cschar", - "cshort", "cu"]: - result.add s[i] - else: - result.add toUpper(s[i]) - of skConst, skEnumField: - # for 'const' we keep how it's spelt; either upper case or lower case: - result.add s[0] +proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) = + let beau = beautifyName(s, k) + if s != beau: + if gStyleCheck == StyleCheck.Auto: + sym.name = getIdent(beau) + replaceInFile(info, beau) else: - # as a special rule, don't transform 'L' to 'l' - if s.len == 1 and s[0] == 'L': result.add 'L' - else: result.add toLower(s[0]) - inc i - while i < s.len: - if s[i] == '_': - inc i - result.add toUpper(s[i]) - elif allUpper: - result.add toLower(s[i]) - else: - result.add s[i] - inc i + message(info, hintName, beau) -proc check(c: PGen, n: PNode) = - case n.kind - of nkSym: checkUse(n.info, n.sym) - of nkBlockStmt, nkBlockExpr, nkBlockType: - checkDef(c, n[0]) - check(c, n.sons[1]) - of nkForStmt, nkParForStmt: - let L = n.len - for i in countup(0, L-3): - checkDef(c, n[i]) - check(c, n[L-2]) - check(c, n[L-1]) - of nkProcDef, nkLambdaKinds, nkMethodDef, nkIteratorDef, nkTemplateDef, - nkMacroDef, nkConverterDef: - checkDef(c, n[namePos]) - for i in namePos+1 .. <n.len: check(c, n.sons[i]) - of nkIdentDefs, nkVarTuple: - let a = n - checkMinSonsLen(a, 3) - let L = len(a) - for j in countup(0, L-3): checkDef(c, a.sons[j]) - check(c, a.sons[L-2]) - check(c, a.sons[L-1]) - of nkTypeSection, nkConstSection: - for i in countup(0, sonsLen(n) - 1): - let a = n.sons[i] - if a.kind == nkCommentStmt: continue - checkSonsLen(a, 3) - checkDef(c, a.sons[0]) - check(c, a.sons[1]) - check(c, a.sons[2]) - else: - for i in 0 .. <n.safeLen: check(c, n.sons[i]) +proc styleCheckDefImpl(info: TLineInfo; s: PSym; k: TSymKind) = + # operators stay as they are: + if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return + if k in {skType, skGenericParam} and sfAnon in s.flags: return + if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern: + checkStyle(info, s.name.s, k, s) -proc processSym(c: PPassContext, n: PNode): PNode = - result = n - check(PGen(c), n) +template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) = + when defined(nimfix): + if gStyleCheck != StyleCheck.None: styleCheckDefImpl(info, s, k) -proc myOpen(module: PSym): PPassContext = - var g: PGen - new(g) - g.module = module - gCheckExtern = options.getConfigVar("pretty.checkextern").normalize == "on" - result = g - if rules.isNil: - rules = newStringTable(modeStyleInsensitive) - when removeTP: - # XXX activate when the T/P stuff is deprecated - let path = joinPath([getPrefixDir(), "config", "rename.rules.cfg"]) - for line in lines(path): - if line.len > 0: - let colon = line.find(':') - if colon > 0: - rules[line.substr(0, colon-1)] = line.substr(colon+1) - else: - rules[line] = line +template styleCheckDef*(info: TLineInfo; s: PSym) = + styleCheckDef(info, s, s.kind) +template styleCheckDef*(s: PSym) = + styleCheckDef(s.info, s, s.kind) + +proc styleCheckUseImpl(info: TLineInfo; s: PSym) = + if info.fileIndex < 0: return + # we simply convert it to what it looks like in the definition + # for consistency + + # operators stay as they are: + if s.kind in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: + return + if s.kind in {skType, skGenericParam} and sfAnon in s.flags: return + let newName = s.name.s -const prettyPass* = makePass(open = myOpen, process = processSym) + replaceInFile(info, newName) + #if newName == "File": writeStackTrace() +template styleCheckUse*(info: TLineInfo; s: PSym) = + when defined(nimfix): + if gStyleCheck != StyleCheck.None: styleCheckUseImpl(info, s) diff --git a/compiler/prettybase.nim b/compiler/prettybase.nim new file mode 100644 index 000000000..225b78479 --- /dev/null +++ b/compiler/prettybase.nim @@ -0,0 +1,93 @@ +# +# +# The Nim Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +import ast, msgs, strutils, idents, lexbase, streams +from os import splitFile + +type + TSourceFile* = object + lines*: seq[string] + dirty*, isNimfixFile*: bool + fullpath*, newline*: string + fileIdx*: int32 + +var + gSourceFiles*: seq[TSourceFile] = @[] + +proc loadFile*(info: TLineInfo) = + let i = info.fileIndex + if i >= gSourceFiles.len: + gSourceFiles.setLen(i+1) + if gSourceFiles[i].lines.isNil: + gSourceFiles[i].fileIdx = info.fileIndex + gSourceFiles[i].lines = @[] + let path = info.toFullPath + gSourceFiles[i].fullpath = path + gSourceFiles[i].isNimfixFile = path.splitFile.ext == ".nimfix" + # we want to die here for IOError: + for line in lines(path): + gSourceFiles[i].lines.add(line) + # extract line ending of the file: + var lex: BaseLexer + open(lex, newFileStream(path, fmRead)) + var pos = lex.bufpos + while true: + case lex.buf[pos] + of '\c': + gSourceFiles[i].newline = "\c\L" + break + of '\L', '\0': + gSourceFiles[i].newline = "\L" + break + else: discard + inc pos + close(lex) + +const + Letters* = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '_'} + +proc identLen*(line: string, start: int): int = + while start+result < line.len and line[start+result] in Letters: + inc result + +proc differ*(line: string, a, b: int, x: string): bool = + let y = line[a..b] + result = cmpIgnoreStyle(y, x) == 0 and y != x + +proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PIdent) = + loadFile(info) + + let line = gSourceFiles[info.fileIndex].lines[info.line-1] + var first = min(info.col.int, line.len) + if first < 0: return + #inc first, skipIgnoreCase(line, "proc ", first) + while first > 0 and line[first-1] in Letters: dec first + if first < 0: return + if line[first] == '`': inc first + + let last = first+identLen(line, first)-1 + if cmpIgnoreStyle(line[first..last], oldSym.s) == 0: + var x = line.substr(0, first-1) & newSym.s & line.substr(last+1) + system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x) + gSourceFiles[info.fileIndex].dirty = true + #if newSym.s == "File": writeStackTrace() + +proc replaceDeprecated*(info: TLineInfo; oldSym, newSym: PSym) = + replaceDeprecated(info, oldSym.name, newSym.name) + +proc replaceComment*(info: TLineInfo) = + loadFile(info) + + let line = gSourceFiles[info.fileIndex].lines[info.line-1] + var first = info.col.int + if line[first] != '#': inc first + + var x = line.substr(0, first-1) & "discard " & line.substr(first+1).escape + system.shallowCopy(gSourceFiles[info.fileIndex].lines[info.line-1], x) + gSourceFiles[info.fileIndex].dirty = true diff --git a/compiler/procfind.nim b/compiler/procfind.nim index 9f52cc117..46d6c9929 100644 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/readme.txt b/compiler/readme.txt index 3d3cf4b29..c4934e031 100644 --- a/compiler/readme.txt +++ b/compiler/readme.txt @@ -1,4 +1,4 @@ -This directory contains the Nimrod compiler written in Nimrod. Note that this +This directory contains the Nim compiler written in Nim. Note that this code has been translated from a bootstrapping version written in Pascal, so -the code is **not** a poster child of good Nimrod code. +the code is **not** a poster child of good Nim code. diff --git a/compiler/renderer.nim b/compiler/renderer.nim index c97b2f321..a4469acda 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1,13 +1,13 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This module implements the renderer of the standard Nimrod representation. +# This module implements the renderer of the standard Nim representation. import lexer, options, idents, strutils, ast, msgs, lists @@ -1009,9 +1009,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = put(g, tkElse, " else") putWithSpace(g, tkColon, ":") gsub(g, n.sons[0]) - of nkTypeOfExpr: + of nkTypeOfExpr: putWithSpace(g, tkType, "type") - gsub(g, n.sons[0]) + if n.len > 0: gsub(g, n.sons[0]) of nkRefTy: if sonsLen(n) > 0: putWithSpace(g, tkRef, "ref") @@ -1306,7 +1306,7 @@ proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string = proc renderModule(n: PNode, filename: string, renderFlags: TRenderFlags = {}) = var - f: TFile + f: File g: TSrcGen initSrcGen(g, renderFlags) for i in countup(0, sonsLen(n) - 1): diff --git a/compiler/rodread.nim b/compiler/rodread.nim index 036e6cc3c..3b3538e5d 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -121,7 +121,7 @@ type r*: string # writers use this offset*: int # readers use this - TRodReader* = object of TObject + TRodReader* = object of RootObj pos: int # position; used for parsing s: cstring # mmap'ed file contents options: TOptions @@ -137,7 +137,7 @@ type line: int # only used for debugging, but is always in the code moduleID: int syms: TIdTable # already processed symbols - memfile: TMemFile # unfortunately there is no point in time where we + memfile: MemFile # unfortunately there is no point in time where we # can close this! XXX methods*: TSymSeq origFile: string @@ -280,11 +280,6 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) = loc.r = toRope(decodeStr(r.s, r.pos)) else: loc.r = nil - if r.s[r.pos] == '?': - inc(r.pos) - loc.a = decodeVInt(r.s, r.pos) - else: - loc.a = 0 if r.s[r.pos] == '>': inc(r.pos) else: internalError(info, "decodeLoc " & r.s[r.pos]) @@ -326,7 +321,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType = result.size = - 1 if r.s[r.pos] == '=': inc(r.pos) - result.align = decodeVInt(r.s, r.pos) + result.align = decodeVInt(r.s, r.pos).int16 else: result.align = 2 decodeLoc(r, result.loc, info) @@ -503,7 +498,7 @@ proc processCompilerProcs(r: PRodReader, module: PSym) = idTablePut(r.syms, s, s) strTableAdd(rodCompilerprocs, s) -proc processIndex(r: PRodReader; idx: var TIndex; outf: TFile = nil) = +proc processIndex(r: PRodReader; idx: var TIndex; outf: File = nil) = var key, val, tmp: int inc(r.pos, 2) # skip "(\10" inc(r.line) @@ -659,7 +654,7 @@ proc newRodReader(modfilename: string, crc: TCrc32, new(result) try: result.memfile = memfiles.open(modfilename) - except EOS: + except OSError: return nil result.files = @[] result.modDeps = @[] @@ -916,7 +911,7 @@ initIdTable(gTypeTable) initStrTable(rodCompilerprocs) # viewer: -proc writeNode(f: TFile; n: PNode) = +proc writeNode(f: File; n: PNode) = f.write("(") if n != nil: f.write($n.kind) @@ -947,7 +942,7 @@ proc writeNode(f: TFile; n: PNode) = writeNode(f, n.sons[i]) f.write(")") -proc writeSym(f: TFile; s: PSym) = +proc writeSym(f: File; s: PSym) = if s == nil: f.write("{}\n") return @@ -985,7 +980,7 @@ proc writeSym(f: TFile; s: PSym) = f.writeNode(s.ast) f.write("}\n") -proc writeType(f: TFile; t: PType) = +proc writeType(f: File; t: PType) = if t == nil: f.write("[]\n") return diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 09b92cd8a..e0ef3c397 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 4231da2d0..9fed7ac52 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -187,9 +187,6 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = if loc.r != nil: add(result, '!') encodeStr(ropeToStr(loc.r), result) - if loc.a != 0: - add(result, '?') - encodeVInt(loc.a, result) if oldLen + 1 == result.len: # no data was necessary, so remove the '<' again: setLen(result, oldLen) @@ -297,7 +294,7 @@ proc encodeSym(w: PRodWriter, s: PSym, result: var string) = # the last entry of a symbol: if s.ast != nil: # we used to attempt to save space here by only storing a dummy AST if - # it is not necessary, but Nimrod's heavy compile-time evaluation features + # it is not necessary, but Nim's heavy compile-time evaluation features # make that unfeasible nowadays: encodeNode(w, s.info, s.ast, result) when false: @@ -422,7 +419,7 @@ proc addStmt(w: PRodWriter, n: PNode) = proc writeRod(w: PRodWriter) = processStacks(w, true) - var f: TFile + var f: File if not open(f, completeGeneratedFilePath(changeFileExt( w.filename.withPackageName, RodExt)), fmWrite): diff --git a/compiler/ropes.nim b/compiler/ropes.nim index fcf5dd202..b14081694 100644 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,7 +12,7 @@ # Ropes are a data structure that represents a very long string # efficiently; especially concatenation is done in O(1) instead of O(N). # Ropes make use a lazy evaluation: They are essentially concatenation -# trees that are only flattened when converting to a native Nimrod +# trees that are only flattened when converting to a native Nim # string or when written to disk. The empty string is represented by a # nil pointer. # A little picture makes everything clear: @@ -64,7 +64,7 @@ type # copy the format strings # though it is not necessary) PRope* = ref TRope - TRope*{.acyclic.} = object of TObject # the empty rope is represented + TRope*{.acyclic.} = object of RootObj # the empty rope is represented # by nil to safe space left*, right*: PRope length*: int @@ -216,7 +216,7 @@ proc app(a: var PRope, b: PRope) = a = con(a, b) proc app(a: var PRope, b: string) = a = con(a, b) proc prepend(a: var PRope, b: PRope) = a = con(b, a) -proc writeRope*(f: TFile, c: PRope) = +proc writeRope*(f: File, c: PRope) = var stack = @[c] while len(stack) > 0: var it = pop(stack) @@ -228,7 +228,7 @@ proc writeRope*(f: TFile, c: PRope) = write(f, it.data) proc writeRope*(head: PRope, filename: string, useWarning = false) = - var f: TFile + var f: File if open(f, filename, fmWrite): if head != nil: writeRope(f, head) close(f) @@ -299,7 +299,7 @@ proc appf(c: var PRope, frmt: TFormatStr, args: varargs[PRope]) = const bufSize = 1024 # 1 KB is reasonable -proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool = +proc auxRopeEqualsFile(r: PRope, bin: var File, buf: pointer): bool = if r.data != nil: if r.length > bufSize: errorHandler(rTokenTooLong, r.data) @@ -312,7 +312,7 @@ proc auxRopeEqualsFile(r: PRope, bin: var TFile, buf: pointer): bool = if result: result = auxRopeEqualsFile(r.right, bin, buf) proc ropeEqualsFile(r: PRope, f: string): bool = - var bin: TFile + var bin: File result = open(bin, f) if not result: return # not equal if file does not exist diff --git a/compiler/saturate.nim b/compiler/saturate.nim index ed197bdd1..f4fe29a20 100644 --- a/compiler/saturate.nim +++ b/compiler/saturate.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/sem.nim b/compiler/sem.nim index 26a59334c..7446384d2 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -18,6 +18,9 @@ import evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity, semparallel, lowerings +when defined(nimfix): + import prettybase + # implementation proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode {.procvar.} @@ -308,6 +311,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, pushInfoContext(nOrig.info) markUsed(n.info, sym) + styleCheckUse(n.info, sym) if sym == c.p.owner: globalError(n.info, errRecursiveDependencyX, sym.name.s) @@ -340,7 +344,7 @@ type TSemGenericFlags = set[TSemGenericFlag] proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var TIntSet): PNode + ctx: var IntSet): PNode include semtypes, semtempl, semgnrc, semstmts, semexprs @@ -367,6 +371,8 @@ proc myOpen(module: PSym): PPassContext = c.semInferredLambda = semInferredLambda c.semGenerateInstance = generateInstance c.semTypeNode = semTypeNode + c.instDeepCopy = sigmatch.instDeepCopy + pushProcCon(c, module) pushOwner(c.module) c.importTable = openScope(c) diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim new file mode 100644 index 000000000..483d36bf3 --- /dev/null +++ b/compiler/semasgn.nim @@ -0,0 +1,197 @@ +# +# +# The Nim Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements lifting for assignments and ``deepCopy``. + +# included from sem.nim + +type + TLiftCtx = object + c: PContext + info: TLineInfo # for construction + result: PNode + kind: TTypeAttachedOp + +type + TFieldInstCtx = object # either 'tup[i]' or 'field' is valid + tupleType: PType # if != nil we're traversing a tuple + tupleIndex: int + field: PSym + replaceByFieldName: bool + +proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = + case n.kind + of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n + of nkIdent: + result = n + var L = sonsLen(forLoop) + if c.replaceByFieldName: + if n.ident.id == forLoop[0].ident.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 + result = newStrNode(nkStrLit, fieldName) + return + # other fields: + for i in ord(c.replaceByFieldName)..L-3: + if n.ident.id == forLoop[i].ident.id: + var call = forLoop.sons[L-2] + var tupl = call.sons[i+1-ord(c.replaceByFieldName)] + if c.field.isNil: + result = newNodeI(nkBracketExpr, n.info) + result.add(tupl) + result.add(newIntNode(nkIntLit, c.tupleIndex)) + else: + result = newNodeI(nkDotExpr, n.info) + result.add(tupl) + result.add(newSymNode(c.field, n.info)) + break + else: + if n.kind == nkContinueStmt: + localError(n.info, errGenerated, + "'continue' not supported in a 'fields' loop") + result = copyNode(n) + newSons(result, sonsLen(n)) + for i in countup(0, sonsLen(n)-1): + result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop) + +proc liftBodyObj(c: TLiftCtx; typ, x, y: PNode) = + case typ.kind + of nkSym: + var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid + fc.field = typ.sym + fc.replaceByFieldName = c.m == mFieldPairs + openScope(c.c) + inc c.c.inUnrolledContext + let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) + father.add(semStmt(c.c, body)) + dec c.c.inUnrolledContext + closeScope(c.c) + of nkNilLit: discard + of nkRecCase: + let L = forLoop.len + let call = forLoop.sons[L-2] + if call.len > 2: + localError(forLoop.info, errGenerated, + "parallel 'fields' iterator does not work for 'case' objects") + return + # iterate over the selector: + asgnForObjectFields(c, typ[0], forLoop, father) + # we need to generate a case statement: + var caseStmt = newNodeI(nkCaseStmt, c.info) + # generate selector: + var access = newNodeI(nkDotExpr, forLoop.info, 2) + access.sons[0] = call.sons[1] + access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info) + caseStmt.add(semExprWithType(c.c, access)) + # copy the branches over, but replace the fields with the for loop body: + for i in 1 .. <typ.len: + var branch = copyTree(typ[i]) + let L = branch.len + branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info) + semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1]) + caseStmt.add(branch) + father.add(caseStmt) + of nkRecList: + for t in items(typ): liftBodyObj(c, t, x, y) + else: + illFormedAst(typ) + +proc newAsgnCall(op: PSym; x, y: PNode): PNode = + result = newNodeI(nkCall, x.info) + result.add(newSymNode(op)) + result.add x + result.add y + +proc newAsgnStmt(le, ri: PNode): PNode = + result = newNodeI(nkAsgn, le.info, 2) + result.sons[0] = le + result.sons[1] = ri + +proc newDestructorCall(op: PSym; x: PNode): PNode = + result = newNodeIT(nkCall, x.info, op.typ.sons[0]) + result.add(newSymNode(op)) + result.add x + +proc newDeepCopyCall(op: PSym; x, y: PNode): PNode = + result = newAsgnStmt(x, newDestructorCall(op, y)) + +proc considerOverloadedOp(c: TLiftCtx; t: PType; x, y: PNode): bool = + let op = t.attachedOps[c.kind] + if op != nil: + markUsed(c.info, op) + styleCheckUse(c.info, op) + case c.kind + of attachedDestructor: + c.result.add newDestructorCall(op, x) + of attachedAsgn: + c.result.add newAsgnCall(op, x, y) + of attachedDeepCopy: + c.result.add newDeepCopyCall(op, x, y) + result = true + +proc defaultOp(c: TLiftCtx; t: PType; x, y: PNode) = + if c.kind != attachedDestructor: + c.result.add newAsgnStmt(x, y) + +proc liftBodyAux(c: TLiftCtx; t: PType; x, y: PNode) = + const hasAttachedOp: array[TTypeAttachedOp, TTypeIter] = [ + (proc (t: PType, closure: PObject): bool = + t.attachedOp[attachedDestructor] != nil), + (proc (t: PType, closure: PObject): bool = + t.attachedOp[attachedAsgn] != nil), + (proc (t: PType, closure: PObject): bool = + t.attachedOp[attachedDeepCopy] != nil)] + case t.kind + of tyNone, tyEmpty: discard + of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString: + defaultOp(c, t, x, y) + of tyPtr, tyString: + if not considerOverloadedOp(c, t, x, y): + defaultOp(c, t, x, y) + of tyArrayConstr, tyArray, tySequence: + if iterOverType(lastSon(t), hasAttachedOp[c.kind], nil): + # generate loop and call the attached Op: + + else: + defaultOp(c, t, x, y) + of tyObject: + liftBodyObj(c, t.n, x, y) + of tyTuple: + liftBodyTup(c, t, x, y) + of tyRef: + # we MUST not check for acyclic here as a DAG might still share nodes: + + of tyProc: + if t.callConv != ccClosure or c.kind != attachedDeepCopy: + defaultOp(c, t, x, y) + else: + # a big problem is that we don't know the enviroment's type here, so we + # have to go through some indirection; we delegate this to the codegen: + call = newNodeI(nkCall, n.info, 2) + call.typ = t + call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy)) + call.sons[1] = y + c.result.add newAsgnStmt(x, call) + of tyVarargs, tyOpenArray: + localError(c.info, errGenerated, "cannot copy openArray") + of tyFromExpr, tyIter, tyProxy, tyBuiltInTypeClass, tyUserTypeClass, + tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything, + tyMutable, tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt, + tyTypeDesc, tyGenericInvokation, tyBigNum, tyConst, tyForward: + internalError(c.info, "assignment requested for type: " & typeToString(t)) + of tyDistinct, tyOrdinal, tyRange, + tyGenericInst, tyFieldAccessor, tyStatic, tyVar: + liftBodyAux(c, lastSon(t)) + +proc liftBody(c: PContext; typ: PType; info: TLineInfo): PNode = + var a: TLiftCtx + a.info = info + a.result = newNodeI(nkStmtList, info) + liftBodyAux(a, typ) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index 927b23cf2..6f92a75a6 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -254,6 +254,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode = assert x.state == csMatch var finalCallee = x.calleeSym markUsed(n.sons[0].info, finalCallee) + styleCheckUse(n.sons[0].info, finalCallee) if finalCallee.ast == nil: internalError(n.info, "calleeSym.ast is nil") # XXX: remove this check! if finalCallee.ast.sons[genericParamsPos].kind != nkEmpty: @@ -286,6 +287,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode = initCandidate(c, m, s, n) var newInst = generateInstance(c, s, m.bindings, n.info) markUsed(n.info, s) + styleCheckUse(n.info, s) result = newSymNode(newInst, n.info) proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = diff --git a/compiler/semdata.nim b/compiler/semdata.nim index abecc1b6d..bc7b8cdc2 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -57,7 +57,7 @@ type # can access private object fields instCounter*: int # to prevent endless instantiations - ambiguousSymbols*: TIntSet # ids of all ambiguous symbols (cannot + ambiguousSymbols*: IntSet # ids of all ambiguous symbols (cannot # store this info in the syms themselves!) inTypeClass*: int # > 0 if we are in a user-defined type class inGenericContext*: int # > 0 if we are in a generic type @@ -83,15 +83,18 @@ type semInferredLambda*: proc(c: PContext, pt: TIdTable, n: PNode): PNode semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable, info: TLineInfo): PSym - includedFiles*: TIntSet # used to detect recursive include files + includedFiles*: IntSet # used to detect recursive include files userPragmas*: TStrTable evalContext*: PEvalContext - unknownIdents*: TIntSet # ids of all unknown identifiers to prevent + unknownIdents*: IntSet # ids of all unknown identifiers to prevent # naming it multiple times generics*: seq[TInstantiationPair] # pending list of instantiated generics to compile lastGenericIdx*: int # used for the generics stack hloLoopDetector*: int # used to prevent endless loops in the HLO inParallelStmt*: int + instDeepCopy*: proc (c: PContext; dc: PSym; t: PType; + info: TLineInfo): PSym {.nimcall.} + proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = result.genericSym = s diff --git a/compiler/semdestruct.nim b/compiler/semdestruct.nim index 3c30dc1bd..4ce610bf9 100644 --- a/compiler/semdestruct.nim +++ b/compiler/semdestruct.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index ff445ecd0..d3650f984 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,6 +13,7 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}): PNode = markUsed(n.info, s) + styleCheckUse(n.info, s) pushInfoContext(n.info) result = evalTemplate(n, s, getCurrOwner()) if efNoSemCheck notin flags: result = semAfterMacroCall(c, result, s, flags) @@ -79,6 +80,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = case s.kind of skConst: markUsed(n.info, s) + styleCheckUse(n.info, s) case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, tyTuple, tySet, tyUInt..tyUInt64: @@ -103,6 +105,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of skTemplate: result = semTemplateExpr(c, n, s, flags) of skVar, skLet, skResult, skParam, 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) @@ -115,6 +118,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = # var len = 0 # but won't be called # genericThatUsesLen(x) # marked as taking a closure? of skGenericParam: + styleCheckUse(n.info, s) if s.typ.kind == tyStatic: result = newSymNode(s, n.info) result.typ = s.typ @@ -125,12 +129,14 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = return n of skType: markUsed(n.info, s) + styleCheckUse(n.info, s) if s.typ.kind == tyStatic and s.typ.n != nil: return s.typ.n result = newSymNode(s, n.info) result.typ = makeTypeDesc(c, s.typ) else: markUsed(n.info, s) + styleCheckUse(n.info, s) result = newSymNode(s, n.info) type @@ -259,6 +265,7 @@ proc semConv(c: PContext, n: PNode): PNode = let status = checkConvertible(c, result.typ, it.typ) if status in {convOK, convNotNeedeed}: markUsed(n.info, it.sym) + styleCheckUse(n.info, it.sym) markIndirect(c, it.sym) return it localError(n.info, errUseQualifier, op.sons[0].sym.name.s) @@ -360,6 +367,7 @@ proc isOpImpl(c: PContext, n: PNode): PNode = result = newIntNode(nkIntLit, ord(t.kind == tyProc and t.callConv == ccClosure and tfIterator notin t.flags)) + else: discard else: var t2 = n[2].typ.skipTypes({tyTypeDesc}) maybeLiftType(t2, c, n.info) @@ -981,6 +989,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = var s = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if s != nil: markUsed(n.sons[1].info, s) + styleCheckUse(n.sons[1].info, s) return semSym(c, n, s, flags) n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType}) @@ -1004,6 +1013,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result.info = n.info result.typ = ty markUsed(n.info, f) + styleCheckUse(n.info, f) return of tyTypeParamsHolders: return readTypeParameter(c, ty, i, n.info) @@ -1036,12 +1046,13 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? markUsed(n.sons[1].info, f) + styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) # we now have the correct field n.typ = f.typ - if check == nil: + if check == nil: result = n - else: + else: check.sons[0] = n check.typ = n.typ result = check @@ -1049,6 +1060,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = f = getSymFromList(ty.n, i) if f != nil: markUsed(n.sons[1].info, f) + styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) n.typ = f.typ @@ -1465,6 +1477,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) markUsed(n.info, expandedSym) + styleCheckUse(n.info, expandedSym) for i in countup(1, macroCall.len-1): macroCall.sons[i] = semExprWithType(c, macroCall[i], {}) @@ -1614,6 +1627,10 @@ proc instantiateCreateFlowVarCall(c: PContext; t: PType; initIdTable(bindings) bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t) result = c.semGenerateInstance(c, sym, bindings, info) + # since it's an instantiation, we unmark it as a compilerproc. Otherwise + # codegen would fail: + result.flags = result.flags - {sfCompilerProc, sfExportC, sfImportC} + result.loc.r = nil proc setMs(n: PNode, s: PSym): PNode = result = n @@ -1816,7 +1833,7 @@ proc semTuplePositionsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = addSonSkipIntLit(typ, n.sons[i].typ) result.typ = typ -proc checkInitialized(n: PNode, ids: TIntSet, info: TLineInfo) = +proc checkInitialized(n: PNode, ids: IntSet, info: TLineInfo) = case n.kind of nkRecList: for i in countup(0, sonsLen(n) - 1): @@ -1897,6 +1914,7 @@ proc semBlock(c: PContext, n: PNode): PNode = addDecl(c, labl) n.sons[0] = newSymNode(labl, n.sons[0].info) suggestSym(n.sons[0].info, labl) + styleCheckDef(labl) n.sons[1] = semExpr(c, n.sons[1]) n.typ = n.sons[1].typ if isEmptyType(n.typ): n.kind = nkBlockStmt @@ -2014,9 +2032,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = checkMinSonsLen(n, 1) let mode = if nfDotField in n.flags: {} else: {checkUndeclared} var s = qualifiedLookUp(c, n.sons[0], mode) - if s != nil: - if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr: - pretty.checkUse(n.sons[0].sons[1].info, s) + if s != nil: + #if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr: + # pretty.checkUse(n.sons[0].sons[1].info, s) case s.kind of skMacro: if sfImmediate notin s.flags: diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 30e02dcc9..76ac23e0d 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -255,6 +255,7 @@ proc evalIs(n, a: PNode): PNode = result = newIntNode(nkIntLit, ord(t.kind == tyProc and t.callConv == ccClosure and tfIterator in t.flags)) + else: discard else: # XXX semexprs.isOpImpl is slightly different and requires a context. yay. let t2 = n[2].typ @@ -683,9 +684,9 @@ proc getConstExpr(m: PSym, n: PNode): PNode = result = evalIs(n, a) else: result = magicCall(m, n) - except EOverflow: + except OverflowError: localError(n.info, errOverOrUnderflow) - except EDivByZero: + except DivByZeroError: localError(n.info, errConstantDivisionByZero) of nkAddr: var a = getConstExpr(m, n.sons[0]) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index a004d1465..6c218fa0c 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -28,7 +28,7 @@ proc getIdentNode(n: PNode): PNode = proc semGenericStmtScope(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var TIntSet): PNode = + ctx: var IntSet): PNode = openScope(c) result = semGenericStmt(c, n, flags, ctx) closeScope(c) @@ -37,7 +37,7 @@ template macroToExpand(s: expr): expr = s.kind in {skMacro, skTemplate} and (s.typ.len == 1 or sfImmediate in s.flags) proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, - ctx: var TIntSet): PNode = + ctx: var IntSet): PNode = incl(s.flags, sfUsed) case s.kind of skUnknown: @@ -47,33 +47,40 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym, result = symChoice(c, n, s, scOpen) of skTemplate: if macroToExpand(s): + styleCheckUse(n.info, s) let n = fixImmediateParams(n) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: result = symChoice(c, n, s, scOpen) - of skMacro: + of skMacro: if macroToExpand(s): + styleCheckUse(n.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: result = symChoice(c, n, s, scOpen) of skGenericParam: result = newSymNodeTypeDesc(s, n.info) - of skParam: + styleCheckUse(n.info, s) + of skParam: result = n + styleCheckUse(n.info, s) of skType: if (s.typ != nil) and (s.typ.kind != tyGenericParam): result = newSymNodeTypeDesc(s, n.info) else: result = n - else: result = newSymNode(s, n.info) + styleCheckUse(n.info, s) + else: + result = newSymNode(s, n.info) + styleCheckUse(n.info, s) proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var TIntSet): PNode = + ctx: var IntSet): PNode = result = n let ident = considerQuotedIdent(n) - var s = searchInScopes(c, ident) + var s = searchInScopes(c, ident).skipAlias(n) if s == nil: if ident.id notin ctx and withinMixin notin flags: localError(n.info, errUndeclaredIdentifier, ident.s) @@ -92,7 +99,7 @@ proc newDot(n, b: PNode): PNode = result.add(b) proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, - ctx: var TIntSet): PNode = + ctx: var IntSet): PNode = assert n.kind == nkDotExpr let luf = if withinMixin notin flags: {checkUndeclared} else: {} @@ -104,7 +111,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, result = n let n = n[1] let ident = considerQuotedIdent(n) - var s = searchInScopes(c, ident) + var s = searchInScopes(c, ident).skipAlias(n) if s != nil and s.kind in routineKinds: if withinBind in flags: result = newDot(result, symChoice(c, n, s, scClosed)) @@ -117,8 +124,13 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags, else: result = newDot(result, sym) +proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) = + let s = newSymS(skUnknown, getIdentNode(n), c) + addPrelimDecl(c, s) + styleCheckDef(n.info, s, kind) + proc semGenericStmt(c: PContext, n: PNode, - flags: TSemGenericFlags, ctx: var TIntSet): PNode = + flags: TSemGenericFlags, ctx: var IntSet): PNode = result = n if gCmd == cmdIdeTools: suggestStmt(c, n) case n.kind @@ -161,13 +173,15 @@ proc semGenericStmt(c: PContext, n: PNode, case s.kind of skMacro: if macroToExpand(s): + styleCheckUse(fn.info, s) result = semMacroExpr(c, n, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) else: n.sons[0] = symChoice(c, n.sons[0], s, scOption) result = n - of skTemplate: + of skTemplate: if macroToExpand(s): + styleCheckUse(fn.info, s) let n = fixImmediateParams(n) result = semTemplateExpr(c, n, s, {efNoSemCheck}) result = semGenericStmt(c, result, {}, ctx) @@ -184,14 +198,17 @@ proc semGenericStmt(c: PContext, n: PNode, first = 1 of skGenericParam: result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info) + styleCheckUse(fn.info, s) first = 1 of skType: # bad hack for generics: if (s.typ != nil) and (s.typ.kind != tyGenericParam): result.sons[0] = newSymNodeTypeDesc(s, n.sons[0].info) + styleCheckUse(fn.info, s) first = 1 else: result.sons[0] = newSymNode(s, n.sons[0].info) + styleCheckUse(fn.info, s) first = 1 # Consider 'when defined(globalsSlot): ThreadVarSetValue(globalsSlot, ...)' # in threads.nim: the subtle preprocessing here binds 'globalsSlot' which @@ -226,14 +243,14 @@ proc semGenericStmt(c: PContext, n: PNode, openScope(c) n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, ctx) for i in countup(0, L - 3): - addPrelimDecl(c, newSymS(skUnknown, n.sons[i], c)) + addTempDecl(c, n.sons[i], skForVar) n.sons[L - 1] = semGenericStmt(c, n.sons[L-1], flags, ctx) closeScope(c) of nkBlockStmt, nkBlockExpr, nkBlockType: checkSonsLen(n, 2) openScope(c) if n.sons[0].kind != nkEmpty: - addPrelimDecl(c, newSymS(skUnknown, n.sons[0], c)) + addTempDecl(c, n.sons[0], skLabel) n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx) closeScope(c) of nkTryStmt: @@ -256,7 +273,7 @@ proc semGenericStmt(c: PContext, n: PNode, a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) for j in countup(0, L-3): - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) + addTempDecl(c, getIdentNode(a.sons[j]), skVar) of nkGenericParams: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] @@ -266,23 +283,23 @@ proc semGenericStmt(c: PContext, n: PNode, a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) # do not perform symbol lookup for default expressions for j in countup(0, L-3): - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) + addTempDecl(c, getIdentNode(a.sons[j]), skType) of nkConstSection: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue if (a.kind != nkConstDef): illFormedAst(a) checkSonsLen(a, 3) - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c)) + addTempDecl(c, getIdentNode(a.sons[0]), skConst) a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx) a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx) - of nkTypeSection: + of nkTypeSection: for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue if (a.kind != nkTypeDef): illFormedAst(a) checkSonsLen(a, 3) - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c)) + addTempDecl(c, getIdentNode(a.sons[0]), skType) for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue @@ -306,9 +323,9 @@ proc semGenericStmt(c: PContext, n: PNode, of nkIdent: a = n.sons[i] else: illFormedAst(n) addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[i]), c)) - of nkObjectTy, nkTupleTy: + of nkObjectTy, nkTupleTy: discard - of nkFormalParams: + of nkFormalParams: checkMinSonsLen(n, 1) if n.sons[0].kind != nkEmpty: n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx) @@ -320,17 +337,17 @@ proc semGenericStmt(c: PContext, n: PNode, a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx) a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx) for j in countup(0, L-3): - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c)) + addTempDecl(c, getIdentNode(a.sons[j]), skParam) of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, nkIteratorDef, nkLambdaKinds: checkSonsLen(n, bodyPos + 1) if n.kind notin nkLambdaKinds: - addPrelimDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c)) + addTempDecl(c, getIdentNode(n.sons[0]), skProc) openScope(c) n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], flags, ctx) if n.sons[paramsPos].kind != nkEmpty: - if n.sons[paramsPos].sons[0].kind != nkEmpty: + if n.sons[paramsPos].sons[0].kind != nkEmpty: addPrelimDecl(c, newSym(skUnknown, getIdent("result"), nil, n.info)) n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, ctx) n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, ctx) diff --git a/compiler/seminst.nim b/compiler/seminst.nim index b205eb09a..8ac3849b4 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index 1bece95c2..c685d602d 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -55,7 +55,7 @@ proc annotateType*(n: PNode, t: PType) = else: globalError(n.info, "() must have an object or tuple type") of nkBracket: - if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenarray}: + if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenArray}: n.typ = t for m in n: annotateType(m, x.elemType) else: diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index d4aeba32a..a72a6ab7d 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index 7c489c3b6..c4546f616 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -320,7 +320,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) = # since we already ensure sfAddrTaken is not in s.flags, we only need to # prevent direct assignments to the monotonic variable: let slot = c.getSlot(n[0].sym) - slot.blackListed = true + slot.blacklisted = true invalidateFacts(c.guards, n[0]) analyseSons(c, n) addAsgnFact(c.guards, n[0], n[1]) @@ -335,7 +335,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) = localError(n.info, "invalid control flow for 'parallel'") # 'break' that leaves the 'parallel' section is not valid either # or maybe we should generate a 'try' XXX - of nkVarSection: + of nkVarSection, nkLetSection: for it in n: let value = it.lastSon if value.kind != nkEmpty: @@ -396,7 +396,7 @@ proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode = proc transformSpawn(owner: PSym; n, barrier: PNode): PNode = case n.kind - of nkVarSection: + of nkVarSection, nkLetSection: result = nil for it in n: let b = it.lastSon @@ -464,6 +464,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode = result = newNodeI(nkStmtList, n.info) generateAliasChecks(a, result) result.add varSection - result.add callCodeGenProc("openBarrier", barrier) + result.add callCodegenProc("openBarrier", barrier) result.add transformSpawn(owner, body, barrier) - result.add callCodeGenProc("closeBarrier", barrier) + result.add callCodegenProc("closeBarrier", barrier) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index acc2425f1..94a3b49e3 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -57,26 +57,114 @@ discard """ c() --> we need a stack of scopes for this analysis -""" -const trackGlobals = false ## we don't need it for now + # XXX enhance the algorithm to care about 'dirty' expressions: + lock a[i].L: + inc i # mark 'i' dirty + lock a[j].L: + access a[i], a[j] # --> reject a[i] +""" type TEffects = object exc: PNode # stack of exceptions tags: PNode # list of tags - uses: PNode # list of used global variables bottom: int owner: PSym init: seq[int] # list of initialized variables guards: TModel # nested guards locked: seq[PNode] # locked locations - gcUnsafe, isRecursive: bool + gcUnsafe, isRecursive, isToplevel: bool + maxLockLevel, currLockLevel: TLockLevel PEffects = var TEffects +proc `<`(a, b: TLockLevel): bool {.borrow.} +proc `<=`(a, b: TLockLevel): bool {.borrow.} +proc `==`(a, b: TLockLevel): bool {.borrow.} +proc max(a, b: TLockLevel): TLockLevel {.borrow.} + proc isLocalVar(a: PEffects, s: PSym): bool = s.kind in {skVar, skResult} and sfGlobal notin s.flags and s.owner == a.owner +proc getLockLevel(t: PType): TLockLevel = + var t = t + # tyGenericInst(TLock {tyGenericBody}, tyStatic, tyObject): + if t.kind == tyGenericInst and t.len == 3: t = t.sons[1] + if t.kind == tyStatic and t.n != nil and t.n.kind in {nkCharLit..nkInt64Lit}: + result = t.n.intVal.TLockLevel + +proc lockLocations(a: PEffects; pragma: PNode) = + if pragma.kind != nkExprColonExpr: + localError(pragma.info, errGenerated, "locks pragma without argument") + return + var firstLL = TLockLevel(-1'i16) + for x in pragma[1]: + let thisLL = getLockLevel(x.typ) + if thisLL != 0.TLockLevel: + if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel: + localError(x.info, "invalid lock level: " & $thisLL) + elif firstLL < 0.TLockLevel: firstLL = thisLL + elif firstLL != thisLL: + localError(x.info, errGenerated, + "multi-lock requires the same static lock level for every operand") + a.maxLockLevel = max(a.maxLockLevel, firstLL) + a.locked.add x + if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel: + if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL: + localError(pragma.info, errGenerated, + "invalid nested locking") + a.currLockLevel = firstLL + +proc guardGlobal(a: PEffects; n: PNode; guard: PSym) = + # check whether the corresponding lock is held: + for L in a.locked: + if L.kind == nkSym and L.sym == guard: return + # we allow accesses nevertheless in top level statements for + # easier initialization: + #if a.isTopLevel: + # message(n.info, warnUnguardedAccess, renderTree(n)) + #else: + if not a.isTopLevel: + localError(n.info, errGenerated, "unguarded access: " & renderTree(n)) + +# 'guard*' are checks which are concerned with 'guard' annotations +# (var x{.guard: y.}: int) +proc guardDotAccess(a: PEffects; n: PNode) = + let ri = n.sons[1] + if ri.kind != nkSym or ri.sym.kind != skField: return + var g = ri.sym.guard + if g.isNil or a.isTopLevel: return + # fixup guard: + if g.kind == skUnknown: + var field: PSym = nil + var ty = n.sons[0].typ.skipTypes(abstractPtrs) + if ty.kind == tyTuple: + field = lookupInRecord(ty.n, g.name) + else: + while ty != nil and ty.kind == tyObject: + field = lookupInRecord(ty.n, g.name) + if field != nil: break + ty = ty.sons[0] + if ty == nil: break + ty = ty.skipTypes(abstractPtrs) + if field == nil: + localError(n.info, errGenerated, "invalid guard field: " & g.name.s) + return + g = field + #ri.sym.guard = field + # XXX unfortunately this is not correct for generic instantiations! + if g.kind == skField: + let dot = newNodeI(nkDotExpr, n.info, 2) + dot.sons[0] = n.sons[0] + dot.sons[1] = newSymNode(g) + dot.typ = g.typ + for L in a.locked: + #if a.guards.sameSubexprs(dot, L): return + if guards.sameTree(dot, L): return + localError(n.info, errGenerated, "unguarded access: " & renderTree(n)) + else: + guardGlobal(a, n, g) + proc initVar(a: PEffects, n: PNode) = if n.kind != nkSym: return let s = n.sym @@ -93,13 +181,6 @@ proc initVarViaNew(a: PEffects, n: PNode) = # are initialized: initVar(a, n) -when trackGlobals: - proc addUse(a: PEffects, e: PNode) = - var aa = a.uses - for i in 0 .. <aa.len: - if aa[i].sym.id == e.sym.id: return - a.uses.add(e) - proc useVar(a: PEffects, n: PNode) = let s = n.sym if isLocalVar(a, s): @@ -110,9 +191,8 @@ proc useVar(a: PEffects, n: PNode) = message(n.info, warnUninit, s.name.s) # prevent superfluous warnings about the same variable: a.init.add s.id - if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind == skVar: - when trackGlobals: - a.addUse(copyNode(n)) + if {sfGlobal, sfThread} * s.flags == {sfGlobal} and s.kind in {skVar, skLet}: + if s.guard != nil: guardGlobal(a, n, s.guard) if (tfHasGCedMem in s.typ.flags or s.typ.isGCedMem) and tfGcSafe notin s.typ.flags: if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) @@ -130,20 +210,27 @@ proc addToIntersection(inter: var TIntersection, s: int) = proc throws(tracked, n: PNode) = if n.typ == nil or n.typ.kind != tyError: tracked.add n - + +proc getEbase(): PType = + result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception" + else: sysTypeFromName"E_Base" + proc excType(n: PNode): PType = # reraise is like raising E_Base: - let t = if n.kind == nkEmpty: sysTypeFromName"E_Base" else: n.typ + let t = if n.kind == nkEmpty: getEbase() else: n.typ result = skipTypes(t, skipPtrs) proc createRaise(n: PNode): PNode = result = newNode(nkType) - result.typ = sysTypeFromName"E_Base" + result.typ = getEbase() if not n.isNil: result.info = n.info proc createTag(n: PNode): PNode = result = newNode(nkType) - result.typ = sysTypeFromName"TEffect" + if getCompilerProc("RootEffect") != nil: + result.typ = sysTypeFromName"RootEffect" + else: + result.typ = sysTypeFromName"TEffect" if not n.isNil: result.info = n.info proc createAnyGlobal(n: PNode): PNode = @@ -179,17 +266,11 @@ proc mergeTags(a: PEffects, b, comesFrom: PNode) = else: for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil) -when trackGlobals: - proc mergeUses(a: PEffects, b, comesFrom: PNode) = - if b.isNil: - addUse(a, createAnyGlobal(comesFrom)) - else: - for effect in items(b): addUse(a, effect) - proc listEffects(a: PEffects) = for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ)) for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ)) - for e in items(a.uses): message(e.info, hintUser, e.sym.name.s) + #if a.maxLockLevel != 0: + # message(e.info, hintUser, "lockLevel: " & a.maxLockLevel) proc catches(tracked: PEffects, e: PType) = let e = skipTypes(e, skipPtrs) @@ -315,7 +396,6 @@ proc documentRaises*(n: PNode) = if n.sons[namePos].kind != nkSym: return documentEffect(n, n.sons[pragmasPos], wRaises, exceptionEffects) documentEffect(n, n.sons[pragmasPos], wTags, tagEffects) - documentEffect(n, n.sons[pragmasPos], wUses, usesEffects) template notGcSafe(t): expr = {tfGcSafe, tfNoSideEffect} * t.flags == {} @@ -323,6 +403,24 @@ proc importedFromC(n: PNode): bool = # when imported from C, we assume GC-safety. result = n.kind == nkSym and sfImportc in n.sym.flags +proc getLockLevel(s: PSym): TLockLevel = + result = s.typ.lockLevel + if result == UnspecifiedLockLevel: + if {sfImportc, sfNoSideEffect} * s.flags != {} or + tfNoSideEffect in s.typ.flags: + result = 0.TLockLevel + else: + result = UnknownLockLevel + +proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) = + if lockLevel >= tracked.currLockLevel: + # if in lock section: + if tracked.currLockLevel > 0.TLockLevel: + localError n.info, errGenerated, + "expected lock level < " & $tracked.currLockLevel & + " but got lock level " & $lockLevel + tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel) + proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = let pragma = s.ast.sons[pragmasPos] let spec = effectSpec(pragma, wRaises) @@ -334,10 +432,7 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) = if notGcSafe(s.typ) and sfImportc notin s.flags: if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) tracked.gcUnsafe = true - - when trackGlobals: - let usesSpec = effectSpec(pragma, wUses) - mergeUses(tracked, usesSpec, n) + mergeLockLevels(tracked, n, s.getLockLevel) proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = let n = n.skipConv @@ -357,6 +452,13 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) = message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree) of impYes: discard +proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) = + addEffect(tracked, createRaise(n)) + addTag(tracked, createTag(n)) + let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel + else: op.lockLevel + mergeLockLevels(tracked, n, lockLevel) + proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = let op = skipConvAndClosure(n).typ if op != nil and op.kind == tyProc and n.kind != nkNilLit: @@ -372,9 +474,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = propagateEffects(tracked, n, n.sym) else: # we have no explicit effects so assume the worst: - addEffect(tracked, createRaise(n)) - addTag(tracked, createTag(n)) - when trackGlobals: addUse(tracked, createAnyGlobal(n)) + assumeTheWorst(tracked, n, op) # assume GcUnsafe unless in its type; 'forward' does not matter: if notGcSafe(op): if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) @@ -382,7 +482,6 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) = else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) - when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n) if notGcSafe(op): if warnGcUnsafe in gNotes: message(n.info, warnGcUnsafe, renderTree(n)) tracked.gcUnsafe = true @@ -511,8 +610,12 @@ proc track(tracked: PEffects, n: PNode) = # are indistinguishable from normal procs (both have tyProc type) and # we can detect them only by checking for attached nkEffectList. if op != nil and op.kind == tyProc and op.n.sons[0].kind == nkEffectList: - if a.kind == nkSym and a.sym == tracked.owner: - tracked.isRecursive = true + if a.kind == nkSym: + if a.sym == tracked.owner: tracked.isRecursive = true + # even for recursive calls we need to check the lock levels (!): + mergeLockLevels(tracked, n, a.sym.getLockLevel) + else: + mergeLockLevels(tracked, n, op.lockLevel) var effectList = op.n.sons[0] if a.kind == nkSym and a.sym.kind == skMethod: propagateEffects(tracked, n, a.sym) @@ -520,14 +623,10 @@ proc track(tracked: PEffects, n: PNode) = if isForwardedProc(a): propagateEffects(tracked, n, a.sym) elif isIndirectCall(a, tracked.owner): - addEffect(tracked, createRaise(n)) - addTag(tracked, createTag(n)) - when trackGlobals: addUse(tracked, createAnyGlobal(n)) - # XXX handle 'gcsafe' properly for callbacks! + assumeTheWorst(tracked, n, op) else: mergeEffects(tracked, effectList.sons[exceptionEffects], n) mergeTags(tracked, effectList.sons[tagEffects], n) - when trackGlobals: mergeUses(tracked, effectList.sons[usesEffects], n) if notGcSafe(op) and not importedFromC(a): # and it's not a recursive call: if not (a.kind == nkSym and a.sym == tracked.owner): @@ -539,6 +638,9 @@ proc track(tracked: PEffects, n: PNode) = initVarViaNew(tracked, n.sons[1]) for i in 0 .. <safeLen(n): track(tracked, n.sons[i]) + of nkDotExpr: + guardDotAccess(tracked, n) + for i in 0 .. <len(n): track(tracked, n.sons[i]) of nkCheckedFieldExpr: track(tracked, n.sons[0]) if warnProveField in gNotes: checkFieldAccess(tracked.guards, n) @@ -552,7 +654,7 @@ proc track(tracked: PEffects, n: PNode) = addAsgnFact(tracked.guards, n.sons[0], n.sons[1]) notNilCheck(tracked, n.sons[1], n.sons[0].typ) when false: cstringCheck(tracked, n) - of nkVarSection: + of nkVarSection, nkLetSection: for child in n: let last = lastSon(child) if child.kind == nkIdentDefs and last.kind != nkEmpty: @@ -594,6 +696,16 @@ proc track(tracked: PEffects, n: PNode) = if sfDiscriminant in x.sons[0].sym.flags: addDiscriminantFact(tracked.guards, x) setLen(tracked.guards, oldFacts) + of nkPragmaBlock: + let pragmaList = n.sons[0] + let oldLocked = tracked.locked.len + let oldLockLevel = tracked.currLockLevel + for i in 0 .. <pragmaList.len: + if whichPragma(pragmaList.sons[i]) == wLocks: + lockLocations(tracked, pragmaList.sons[i]) + track(tracked, n.lastSon) + setLen(tracked.locked, oldLocked) + tracked.currLockLevel = oldLockLevel of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef: discard @@ -641,13 +753,13 @@ proc checkMethodEffects*(disp, branch: PSym) = if not isNil(tagsSpec): checkRaisesSpec(tagsSpec, actual.sons[tagEffects], "can have an unlisted effect: ", hints=off, subtypeRelation) - let usesSpec = effectSpec(p, wUses) - if not isNil(usesSpec): - checkRaisesSpec(usesSpec, actual.sons[usesEffects], - "may use an unlisted global variable: ", hints=off, symbolPredicate) if sfThread in disp.flags and notGcSafe(branch.typ): localError(branch.info, "base method is GC-safe, but '$1' is not" % branch.name.s) + if branch.typ.lockLevel > disp.typ.lockLevel: + localError(branch.info, + "base method has lock level $1, but dispatcher has $2" % + [$branch.typ.lockLevel, $disp.typ.lockLevel]) proc setEffectsForProcType*(t: PType, n: PNode) = var effects = t.n.sons[0] @@ -656,29 +768,25 @@ proc setEffectsForProcType*(t: PType, n: PNode) = let raisesSpec = effectSpec(n, wRaises) tagsSpec = effectSpec(n, wTags) - usesSpec = effectSpec(n, wUses) - if not isNil(raisesSpec) or not isNil(tagsSpec) or not isNil(usesSpec): + if not isNil(raisesSpec) or not isNil(tagsSpec): internalAssert effects.len == 0 newSeq(effects.sons, effectListLen) if not isNil(raisesSpec): effects.sons[exceptionEffects] = raisesSpec if not isNil(tagsSpec): effects.sons[tagEffects] = tagsSpec - if not isNil(usesSpec): - effects.sons[usesEffects] = usesSpec proc initEffects(effects: PNode; s: PSym; t: var TEffects) = newSeq(effects.sons, effectListLen) effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info) effects.sons[tagEffects] = newNodeI(nkArgList, s.info) - effects.sons[usesEffects] = newNodeI(nkArgList, s.info) t.exc = effects.sons[exceptionEffects] t.tags = effects.sons[tagEffects] - t.uses = effects.sons[usesEffects] t.owner = s t.init = @[] t.guards = @[] + t.locked = @[] proc trackProc*(s: PSym, body: PNode) = var effects = s.typ.n.sons[0] @@ -710,17 +818,19 @@ proc trackProc*(s: PSym, body: PNode) = # after the check, use the formal spec: effects.sons[tagEffects] = tagsSpec - when trackGlobals: - let usesSpec = effectSpec(p, wUses) - if not isNil(usesSpec): - checkRaisesSpec(usesSpec, t.uses, - "uses an unlisted global variable: ", hints=on, symbolPredicate) - effects.sons[usesEffects] = usesSpec if optThreadAnalysis in gGlobalOptions: if sfThread in s.flags and t.gcUnsafe: - #localError(s.info, warnGcUnsafe2, s.name.s) - localError(s.info, "'$1' is not GC-safe" % s.name.s) + 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]) proc trackTopLevelStmt*(module: PSym; n: PNode) = if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, @@ -729,5 +839,5 @@ proc trackTopLevelStmt*(module: PSym; n: PNode) = var effects = newNode(nkEffectList, n.info) var t: TEffects initEffects(effects, module, t) - + t.isToplevel = true track(t, n) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d394a2ae5..255507548 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -29,17 +29,18 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode = of nkIdent: s = lookUp(c, n.sons[0]) of nkSym: s = n.sons[0].sym else: illFormedAst(n) - if s.kind == skLabel and s.owner.id == c.p.owner.id: + if s.kind == skLabel and s.owner.id == c.p.owner.id: var x = newSymNode(s) x.info = n.info incl(s.flags, sfUsed) n.sons[0] = x suggestSym(x.info, s) + styleCheckUse(x.info, s) else: localError(n.info, errInvalidControlFlowX, s.name.s) else: localError(n.info, errGenerated, "'continue' cannot have a label") - elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): + elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): localError(n.info, errInvalidControlFlowX, renderTree(n, {renderNoComments})) @@ -198,11 +199,12 @@ proc semCase(c: PContext, n: PNode): PNode = var covered: BiggestInt = 0 var typ = commonTypeBegin var hasElse = false + var notOrdinal = false case skipTypes(n.sons[0].typ, abstractVarRange-{tyTypeDesc}).kind of tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool: chckCovered = true of tyFloat..tyFloat128, tyString, tyError: - discard + notOrdinal = true else: localError(n.info, errSelectorMustBeOfCertainTypes) return @@ -232,6 +234,9 @@ proc semCase(c: PContext, n: PNode): PNode = hasElse = true else: illFormedAst(x) + if notOrdinal and not hasElse: + message(n.info, warnDeprecated, + "use 'else: discard'; non-ordinal case without 'else'") if chckCovered: if covered == toCover(n.sons[0].typ): hasElse = true @@ -263,7 +268,7 @@ proc semTry(c: PContext, n: PNode): PNode = checkMinSonsLen(a, 1) var length = sonsLen(a) if a.kind == nkExceptBranch: - # XXX what does this do? so that ``except [a, b, c]`` is supported? + # so that ``except [a, b, c]`` is supported: if length == 2 and a.sons[0].kind == nkBracket: a.sons[0..0] = a.sons[0].sons length = a.sonsLen @@ -323,6 +328,7 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = else: result = semIdentWithPragma(c, kind, n, {}) suggestSym(n.info, result) + styleCheckDef(result) proc checkNilable(v: PSym) = if sfGlobal in v.flags and {tfNotNil, tfNeedsInit} * v.typ.flags != {}: @@ -350,9 +356,14 @@ 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}) - # BUGFIX: ``fitNode`` is needed here! - # check type compability between def.typ and typ: - if typ != nil: def = fitNode(c, typ, def) + 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 + def = fitNode(c, typ, def) else: typ = skipIntLit(def.typ) if typ.kind in {tySequence, tyArray, tySet} and @@ -441,7 +452,7 @@ proc semConst(c: PContext, n: PNode): PNode = if typ == nil: localError(a.sons[2].info, errConstExprExpected) continue - if not typeAllowed(typ, skConst): + if not typeAllowed(typ, skConst) and def.kind != nkNilLit: localError(a.info, errXisNoType, typeToString(typ)) continue v.typ = typ @@ -614,6 +625,7 @@ proc addForVarDecl(c: PContext, v: PSym) = proc symForVar(c: PContext, n: PNode): PSym = let m = if n.kind == nkPragmaExpr: n.sons[0] else: n result = newSymG(skForVar, m, c) + styleCheckDef(result) proc semForVars(c: PContext, n: PNode): PNode = result = n @@ -1021,7 +1033,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = sameType(s.typ.sons[1], s.typ.sons[0]): # Note: we store the deepCopy in the base of the pointer to mitigate # the problem that pointers are structural types: - let t = s.typ.sons[1].skipTypes(abstractInst).lastSon.skipTypes(abstractInst) + 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] + else: break if t.kind in {tyObject, tyDistinct, tyEnum}: if t.deepCopy.isNil: t.deepCopy = s else: @@ -1036,6 +1052,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = of "=": discard else: localError(n.info, errGenerated, "'destroy' or 'deepCopy' expected for 'override'") + incl(s.flags, sfUsed) type TProcCompilationSteps = enum @@ -1292,9 +1309,14 @@ proc semPragmaBlock(c: PContext, n: PNode): PNode = let pragmaList = n.sons[0] pragma(c, nil, pragmaList, exprPragmas) result = semExpr(c, n.sons[1]) + n.sons[1] = result for i in 0 .. <pragmaList.len: - if whichPragma(pragmaList.sons[i]) == wLine: - setLine(result, pragmaList.sons[i].info) + case whichPragma(pragmaList.sons[i]) + of wLine: setLine(result, pragmaList.sons[i].info) + of wLocks: + result = n + result.typ = n.sons[1].typ + else: discard proc semStaticStmt(c: PContext, n: PNode): PNode = let a = semStmt(c, n.sons[0]) @@ -1393,6 +1415,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = else: discard if result.len == 1: result = result.sons[0] + when defined(nimfix): + if result.kind == nkCommentStmt and not result.comment.isNil and + not (result.comment[0] == '#' and result.comment[1] == '#'): + # it is an old-style comment statement: we replace it with 'discard ""': + prettybase.replaceComment(result.info) when false: # a statement list (s; e) has the type 'e': if result.kind == nkStmtList and result.len > 0: diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index ee8b1ccb8..0a647a65d 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -71,7 +71,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode = addSon(result, newSymNode(a, n.info)) a = nextOverloadIter(o, c, n) -proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode = +proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode = for i in 0 .. < n.len: var a = n.sons[i] # If 'a' is an overloaded symbol, we used to use the first symbol @@ -91,7 +91,7 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode = illFormedAst(a) result = newNodeI(nkEmpty, n.info) -proc semMixinStmt(c: PContext, n: PNode, toMixin: var TIntSet): PNode = +proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode = for i in 0 .. < n.len: toMixin.incl(considerQuotedIdent(n.sons[i]).id) result = newNodeI(nkEmpty, n.info) @@ -106,7 +106,7 @@ proc replaceIdentBySym(n: var PNode, s: PNode) = type TemplCtx {.pure, final.} = object c: PContext - toBind, toMixin, toInject: TIntSet + toBind, toMixin, toInject: IntSet owner: PSym proc getIdentNode(c: var TemplCtx, n: PNode): PNode = @@ -146,6 +146,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and s.kind == skParam: incl(s.flags, sfUsed) result = newSymNode(s, n.info) + styleCheckUse(n.info, s) else: for i in 0 .. <n.safeLen: result.sons[i] = onlyReplaceParams(c, n.sons[i]) @@ -183,12 +184,15 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) = if not isTemplParam(c, ident): let local = newGenSym(k, ident, c) addPrelimDecl(c.c, local) + styleCheckDef(n.info, local) replaceIdentBySym(n, newSymNode(local, n.info)) else: replaceIdentBySym(n, ident) proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode = incl(s.flags, sfUsed) + # we do not call styleCheckUse here, as the identifier is not really + # resolved here. We will fixup the used identifiers later. case s.kind of skUnknown: # Introduced in this pass! Leave it as an identifier. @@ -204,7 +208,8 @@ proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode = result = newSymNodeTypeDesc(s, n.info) else: result = n - else: result = newSymNode(s, n.info) + else: + result = newSymNode(s, n.info) proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = result = n @@ -214,6 +219,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and (s.kind == skParam or sfGenSym in s.flags): incl(s.flags, sfUsed) result = newSymNode(s, n.info) + styleCheckUse(n.info, s) else: for i in countup(0, safeLen(n) - 1): result.sons[i] = semRoutineInTemplName(c, n.sons[i]) @@ -228,6 +234,7 @@ proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode = var s = newGenSym(k, ident, c) s.ast = n addPrelimDecl(c.c, s) + styleCheckDef(n.info, s) n.sons[namePos] = newSymNode(s, n.sons[namePos].info) else: n.sons[namePos] = ident @@ -261,6 +268,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = if s.owner == c.owner and s.kind == skParam: incl(s.flags, sfUsed) result = newSymNode(s, n.info) + styleCheckUse(n.info, s) elif contains(c.toBind, s.id): result = symChoice(c.c, n, s, scClosed) elif contains(c.toMixin, s.name.id): @@ -270,6 +278,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = # var yz: T incl(s.flags, sfUsed) result = newSymNode(s, n.info) + styleCheckUse(n.info, s) else: result = semTemplSymbol(c.c, n, s) of nkBind: @@ -322,6 +331,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode = # labels are always 'gensym'ed: let s = newGenSym(skLabel, n.sons[0], c) addPrelimDecl(c.c, s) + styleCheckDef(s) n.sons[0] = newSymNode(s, n.sons[0].info) n.sons[1] = semTemplBody(c, n.sons[1]) closeScope(c) @@ -456,6 +466,7 @@ proc semTemplateDef(c: PContext, n: PNode): PNode = incl(s.flags, sfGlobal) else: s = semIdentVis(c, skTemplate, n.sons[0], {}) + styleCheckDef(s) # check parameter list: s.scope = c.currentScope pushOwner(s) @@ -527,6 +538,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode = # semtypes.addParamOrResult). Within the pattern we have to ensure # to use the param with the proper type though: incl(s.flags, sfUsed) + styleCheckUse(n.info, s) let x = c.owner.typ.n.sons[s.position+1].sym assert x.name == s.name result = newSymNode(x, n.info) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 53fe4e266..b3ff6c82a 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -82,6 +82,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType = incl(e.flags, sfExported) if not isPure: strTableAdd(c.module.tab, e) addSon(result.n, newSymNode(e)) + styleCheckDef(e) if sfGenSym notin e.flags and not isPure: addDecl(c, e) inc(counter) if not hasNull: incl(result.flags, tfNeedsInit) @@ -92,7 +93,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType = var base = semTypeNode(c, n.sons[1], nil) addSonSkipIntLit(result, base) if base.kind == tyGenericInst: base = lastSon(base) - if base.kind != tyGenericParam: + if base.kind != tyGenericParam: if not isOrdinalType(base): localError(n.info, errOrdinalTypeExpected) elif lengthOrd(base) > MaxSetElements: @@ -279,9 +280,15 @@ proc semTypeIdent(c: PContext, n: PNode): PSym = if n.kind == nkSym: result = n.sym else: - result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) + when defined(nimfix): + result = pickSym(c, n, skType) + if result.isNil: + result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) + else: + result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared}) if result != nil: markUsed(n.info, result) + styleCheckUse(n.info, result) if result.kind == skParam and result.typ.kind == tyTypeDesc: # This is a typedesc param. is it already bound? # it's not bound when it's used multiple times in the @@ -358,7 +365,7 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType = else: addSon(result.n, newSymNode(field)) addSonSkipIntLit(result, typ) - if gCmd == cmdPretty: checkDef(a.sons[j], field) + if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field) proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym = @@ -394,7 +401,7 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, else: discard else: result = semIdentVis(c, kind, n, allowed) - if gCmd == cmdPretty: checkDef(n, result) + if gCmd == cmdPretty: styleCheckDef(n.info, result) proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) = let ex = t[branchIndex][currentEx].skipConv @@ -461,9 +468,9 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int, swap(branch.sons[L-2], branch.sons[L-1]) checkForOverlap(c, t, i, branchIndex) -proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, +proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, father: PNode, rectype: PType) -proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int, +proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int, father: PNode, rectype: PType) = var a = copyNode(n) checkMinSonsLen(n, 2) @@ -498,7 +505,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var TIntSet, pos: var int, localError(a.info, errNotAllCasesCovered) addSon(father, a) -proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, 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 @@ -524,7 +531,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, else: illFormedAst(n) if c.inGenericContext > 0: # use a new check intset here for each branch: - var newCheck: TIntSet + var newCheck: IntSet assign(newCheck, check) var newPos = pos var newf = newNodeI(nkRecList, n.info) @@ -574,11 +581,12 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var TIntSet, pos: var int, localError(n.sons[i].info, errAttemptToRedefine, f.name.s) if a.kind == nkEmpty: addSon(father, newSymNode(f)) else: addSon(a, newSymNode(f)) + styleCheckDef(f) if a.kind != nkEmpty: addSon(father, a) of nkEmpty: discard else: illFormedAst(n) -proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int, +proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int, n: PNode) = case n.kind of nkRecCase: @@ -597,7 +605,7 @@ proc addInheritedFieldsAux(c: PContext, check: var TIntSet, pos: var int, inc(pos) else: internalError(n.info, "addInheritedFieldsAux()") -proc addInheritedFields(c: PContext, check: var TIntSet, pos: var int, +proc addInheritedFields(c: PContext, check: var IntSet, pos: var int, obj: PType) = if (sonsLen(obj) > 0) and (obj.sons[0] != nil): addInheritedFields(c, check, pos, obj.sons[0]) @@ -814,10 +822,10 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, for i in 1 .. <paramType.sonsLen: let lifted = liftingWalk(paramType.sons[i]) if lifted != nil: paramType.sons[i] = lifted - - let expanded = instGenericContainer(c, info, paramType, - allowMetaTypes = true) - result = liftingWalk(expanded, true) + when false: + let expanded = instGenericContainer(c, info, paramType, + allowMetaTypes = true) + result = liftingWalk(expanded, true) of tyUserTypeClass, tyBuiltInTypeClass, tyAnd, tyOr, tyNot: result = addImplicitGeneric(copyType(paramType, getCurrOwner(), true)) @@ -828,6 +836,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode, of tyGenericParam: markUsed(info, paramType.sym) + styleCheckUse(info, paramType.sym) if tfWildcard in paramType.flags: paramType.flags.excl tfWildcard paramType.sym.kind = skType @@ -847,7 +856,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, prev: PType, kind: TSymKind): PType = var res: PNode - cl: TIntSet + cl: IntSet checkMinSonsLen(n, 1) result = newOrPrevType(tyProc, prev, c) result.callConv = lastOptionEntry(c).defaultCC @@ -913,7 +922,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, addSon(result.n, newSymNode(arg)) rawAddSon(result, finalType) addParamOrResult(c, arg, kind) - if gCmd == cmdPretty: checkDef(a.sons[j], arg) + if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, arg) var r: PType if n.sons[0].kind != nkEmpty: @@ -1188,6 +1197,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = assignType(prev, t) result = prev markUsed(n.info, n.sym) + styleCheckUse(n.info, n.sym) else: if n.sym.kind != skError: localError(n.info, errTypeExpected) result = newOrPrevType(tyError, prev, c) @@ -1234,7 +1244,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = proc setMagicType(m: PSym, kind: TTypeKind, size: int) = m.typ.kind = kind - m.typ.align = size + m.typ.align = size.int16 m.typ.size = size proc processMagicType(c: PContext, m: PSym) = @@ -1332,6 +1342,9 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode = if def.typ.kind != tyTypeDesc: typ = newTypeWithSons(c, tyStatic, @[def.typ]) else: + # the following line fixes ``TV2*[T:SomeNumber=TR] = array[0..1, T]`` + # from manyloc/named_argument_bug/triengine: + def.typ = def.typ.skipTypes({tyTypeDesc}) if not containsGenericType(def.typ): def = fitNode(c, typ, def) diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index 9f0a4100d..9c15be635 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -216,7 +216,7 @@ proc replaceTypeVarsS(cl: var TReplTypeVars, s: PSym): PSym = result.typ = replaceTypeVarsT(cl, s.typ) result.ast = replaceTypeVarsN(cl, s.ast) -proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = +proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType = result = PType(idTableGet(cl.typeMap, t)) if result == nil: if cl.allowMetaTypes or tfRetType in t.flags: return @@ -299,6 +299,11 @@ proc handleGenericInvokation(cl: var TReplTypeVars, t: PType): PType = if newbody.isGenericAlias: newbody = newbody.skipGenericAlias rawAddSon(result, newbody) checkPartialConstructedType(cl.info, newbody) + let dc = newbody.deepCopy + if dc != nil and sfFromGeneric notin newbody.deepCopy.flags: + # 'deepCopy' needs to be instantiated for + # generics *when the type is constructed*: + newbody.deepCopy = cl.c.instDeepCopy(cl.c, dc, result, cl.info) proc eraseVoidParams*(t: PType) = if t.sons[0] != nil and t.sons[0].kind == tyEmpty: diff --git a/compiler/service.nim b/compiler/service.nim index 22f5c6e33..4a1b296cd 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -25,39 +25,17 @@ var lastCaasCmd* = "" # in caas mode, the list of defines and options will be given at start-up? # it's enough to check that the previous compilation command is the same? - arguments* = "" - # the arguments to be passed to the program that - # should be run proc processCmdLine*(pass: TCmdLinePass, cmd: string) = var p = parseopt.initOptParser(cmd) var argsCount = 0 - while true: + while true: parseopt.next(p) case p.kind - of cmdEnd: break - of cmdLongoption, cmdShortOption: - # hint[X]:off is parsed as (p.key = "hint[X]", p.val = "off") - # we fix this here - var bracketLe = strutils.find(p.key, '[') - if bracketLe >= 0: - var key = substr(p.key, 0, bracketLe - 1) - var val = substr(p.key, bracketLe + 1) & ':' & p.val - processSwitch(key, val, pass, gCmdLineInfo) - else: - processSwitch(p.key, p.val, pass, gCmdLineInfo) + of cmdEnd: break + of cmdLongoption, cmdShortOption: processSwitch(pass, p) of cmdArgument: - if argsCount == 0: - options.command = p.key - else: - if pass == passCmd1: options.commandArgs.add p.key - if argsCount == 1: - # support UNIX style filenames anywhere for portable build scripts: - options.gProjectName = unixToNativePath(p.key) - arguments = cmdLineRest(p) - break - inc argsCount - + if processArgument(pass, p, argsCount): break if pass == passCmd2: if optRun notin gGlobalOptions and arguments != "" and options.command.normalize != "run": rawMessage(errArgsNeedRunOption, []) @@ -84,9 +62,9 @@ proc serve*(action: proc (){.nimcall.}) = of "tcp", "": when useCaas: var server = socket() - if server == invalidSocket: osError(osLastError()) + if server == invalidSocket: raiseOSError(osLastError()) let p = getConfigVar("server.port") - let port = if p.len > 0: parseInt(p).TPort else: 6000.TPort + let port = if p.len > 0: parseInt(p).Port else: 6000.Port server.bindAddr(port, getConfigVar("server.address")) var inp = "".TaintedString server.listen() diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e5bf08097..59f954ff0 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,7 +12,8 @@ import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, - magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees + magicsys, condsyms, idents, lexer, options, parampatterns, strutils, trees, + pretty when not defined(noDocgen): import docgen @@ -1272,6 +1273,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType, else: # only one valid interpretation found: markUsed(arg.info, arg.sons[best].sym) + styleCheckUse(arg.info, arg.sons[best].sym) result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best], argOrig) @@ -1319,7 +1321,7 @@ proc incrIndexType(t: PType) = inc t.sons[0].n.sons[1].intVal proc matchesAux(c: PContext, n, nOrig: PNode, - m: var TCandidate, marker: var TIntSet) = + m: var TCandidate, marker: var IntSet) = template checkConstraint(n: expr) {.immediate, dirty.} = if not formal.constraint.isNil: if matchNodeKinds(formal.constraint, n): @@ -1480,8 +1482,23 @@ proc argtypeMatches*(c: PContext, f, a: PType): bool = # instantiate generic converters for that result = res != nil +proc instDeepCopy*(c: PContext; dc: PSym; t: PType; info: TLineInfo): PSym {. + procvar.} = + var m: TCandidate + initCandidate(c, m, dc.typ) + var f = dc.typ.sons[1] + if f.kind in {tyRef, tyPtr}: f = f.lastSon + if typeRel(m, f, t) == isNone: + localError(info, errGenerated, "cannot instantiate 'deepCopy'") + else: + result = c.semGenerateInstance(c, dc, m.bindings, info) + assert sfFromGeneric in result.flags + include suggest +when not declared(tests): + template tests(s: stmt) {.immediate.} = discard + tests: var dummyOwner = newSym(skModule, getIdent("test_module"), nil, UnknownLineInfo()) diff --git a/compiler/suggest.nim b/compiler/suggest.nim index c2bdfc5c3..c700db323 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ # included from sigmatch.nim -import algorithm, sequtils, pretty +import algorithm, sequtils const sep = '\t' @@ -331,7 +331,6 @@ proc markUsed(info: TLineInfo; s: PSym) = if sfDeprecated in s.flags: message(info, warnDeprecated, s.name.s) if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s) suggestSym(info, s) - if gCmd == cmdPretty: checkUse(info, s) proc useSym*(sym: PSym): PNode = result = newSymNode(sym) diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index d5062544f..61677a641 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -44,7 +44,7 @@ proc parseTopLevelStmt*(p: var TParsers): PNode proc parseFile(fileIdx: int32): PNode = var p: TParsers - f: TFile + f: File let filename = fileIdx.toFullPath if not open(f, filename): rawMessage(errCannotOpenFile, filename) diff --git a/compiler/tccgen.nim b/compiler/tccgen.nim index a571d416e..0082dfcbb 100644 --- a/compiler/tccgen.nim +++ b/compiler/tccgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/transf.nim b/compiler/transf.nim index b9b06675e..bab719ba1 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -782,8 +782,8 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode = # result = lambdalifting.liftIterator(prc, result) incl(result.flags, nfTransf) when useEffectSystem: trackProc(prc, result) - if prc.name.s == "testbody": - echo renderTree(result) + #if prc.name.s == "testbody": + # echo renderTree(result) proc transformStmt*(module: PSym, n: PNode): PNode = if nfTransf in n.flags: diff --git a/compiler/trees.nim b/compiler/trees.nim index 35e9334cc..b1edd21f3 100644 --- a/compiler/trees.nim +++ b/compiler/trees.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/treetab.nim b/compiler/treetab.nim index ecb8fb083..63f3fc6e2 100644 --- a/compiler/treetab.nim +++ b/compiler/treetab.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/compiler/types.nim b/compiler/types.nim index c04413857..07a0cf941 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -24,13 +24,13 @@ proc getProcHeader*(sym: PSym): string proc base*(t: PType): PType # ------------------- type iterator: ---------------------------------------- type - TTypeIter* = proc (t: PType, closure: PObject): bool {.nimcall.} # true if iteration should stop - TTypeMutator* = proc (t: PType, closure: PObject): PType {.nimcall.} # copy t and mutate it + TTypeIter* = proc (t: PType, closure: RootRef): bool {.nimcall.} # true if iteration should stop + TTypeMutator* = proc (t: PType, closure: RootRef): PType {.nimcall.} # copy t and mutate it TTypePredicate* = proc (t: PType): bool {.nimcall.} -proc iterOverType*(t: PType, iter: TTypeIter, closure: PObject): bool +proc iterOverType*(t: PType, iter: TTypeIter, closure: RootRef): bool # Returns result of `iter`. -proc mutateType*(t: PType, iter: TTypeMutator, closure: PObject): PType +proc mutateType*(t: PType, iter: TTypeMutator, closure: RootRef): PType # Returns result of `iter`. type @@ -160,10 +160,10 @@ proc enumHasHoles(t: PType): bool = while b.kind in {tyConst, tyMutable, tyRange, tyGenericInst}: b = b.sons[0] result = b.kind == tyEnum and tfEnumHasHoles in b.flags -proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter, - closure: PObject): bool -proc iterOverNode(marker: var TIntSet, n: PNode, iter: TTypeIter, - closure: PObject): bool = +proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, + closure: RootRef): bool +proc iterOverNode(marker: var IntSet, n: PNode, iter: TTypeIter, + closure: RootRef): bool = if n != nil: case n.kind of nkNone..nkNilLit: @@ -174,8 +174,8 @@ proc iterOverNode(marker: var TIntSet, n: PNode, iter: TTypeIter, result = iterOverNode(marker, n.sons[i], iter, closure) if result: return -proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter, - closure: PObject): bool = +proc iterOverTypeAux(marker: var IntSet, t: PType, iter: TTypeIter, + closure: RootRef): bool = result = false if t == nil: return result = iter(t, closure) @@ -190,15 +190,15 @@ proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter, if result: return if t.n != nil: result = iterOverNode(marker, t.n, iter, closure) -proc iterOverType(t: PType, iter: TTypeIter, closure: PObject): bool = +proc iterOverType(t: PType, iter: TTypeIter, closure: RootRef): bool = var marker = initIntSet() result = iterOverTypeAux(marker, t, iter, closure) proc searchTypeForAux(t: PType, predicate: TTypePredicate, - marker: var TIntSet): bool + marker: var IntSet): bool proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, - marker: var TIntSet): bool = + marker: var IntSet): bool = result = false case n.kind of nkRecList: @@ -220,7 +220,7 @@ proc searchTypeNodeForAux(n: PNode, p: TTypePredicate, else: internalError(n.info, "searchTypeNodeForAux()") proc searchTypeForAux(t: PType, predicate: TTypePredicate, - marker: var TIntSet): bool = + marker: var IntSet): bool = # iterates over VALUE types! result = false if t == nil: return @@ -256,7 +256,7 @@ proc isObjectWithTypeFieldPredicate(t: PType): bool = tfFinal notin t.flags proc analyseObjectWithTypeFieldAux(t: PType, - marker: var TIntSet): TTypeFieldResult = + marker: var IntSet): TTypeFieldResult = var res: TTypeFieldResult result = frNone if t == nil: return @@ -310,8 +310,8 @@ proc containsHiddenPointer(typ: PType): bool = # that need to be copied deeply) result = searchTypeFor(typ, isHiddenPointer) -proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool -proc canFormAcycleNode(marker: var TIntSet, n: PNode, startId: int): bool = +proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool +proc canFormAcycleNode(marker: var IntSet, n: PNode, startId: int): bool = result = false if n != nil: result = canFormAcycleAux(marker, n.typ, startId) @@ -324,7 +324,7 @@ proc canFormAcycleNode(marker: var TIntSet, n: PNode, startId: int): bool = result = canFormAcycleNode(marker, n.sons[i], startId) if result: return -proc canFormAcycleAux(marker: var TIntSet, typ: PType, startId: int): bool = +proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool = result = false if typ == nil: return if tfAcyclic in typ.flags: return @@ -353,10 +353,10 @@ proc canFormAcycle(typ: PType): bool = var marker = initIntSet() result = canFormAcycleAux(marker, typ, typ.id) -proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator, - closure: PObject): PType -proc mutateNode(marker: var TIntSet, n: PNode, iter: TTypeMutator, - closure: PObject): PNode = +proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, + closure: RootRef): PType +proc mutateNode(marker: var IntSet, n: PNode, iter: TTypeMutator, + closure: RootRef): PNode = result = nil if n != nil: result = copyNode(n) @@ -369,8 +369,8 @@ proc mutateNode(marker: var TIntSet, n: PNode, iter: TTypeMutator, for i in countup(0, sonsLen(n) - 1): addSon(result, mutateNode(marker, n.sons[i], iter, closure)) -proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator, - closure: PObject): PType = +proc mutateTypeAux(marker: var IntSet, t: PType, iter: TTypeMutator, + closure: RootRef): PType = result = nil if t == nil: return result = iter(t, closure) @@ -380,7 +380,7 @@ proc mutateTypeAux(marker: var TIntSet, t: PType, iter: TTypeMutator, if t.n != nil: result.n = mutateNode(marker, t.n, iter, closure) assert(result != nil) -proc mutateType(t: PType, iter: TTypeMutator, closure: PObject): PType = +proc mutateType(t: PType, iter: TTypeMutator, closure: RootRef): PType = var marker = initIntSet() result = mutateTypeAux(marker, t, iter, closure) @@ -530,15 +530,16 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string = if i < sonsLen(t) - 1: add(result, ", ") add(result, ')') if t.sons[0] != nil: add(result, ": " & typeToString(t.sons[0])) - var prag: string - if t.callConv != ccDefault: prag = CallingConvToStr[t.callConv] - else: prag = "" - if tfNoSideEffect in t.flags: + var prag = if t.callConv == ccDefault: "" else: CallingConvToStr[t.callConv] + if tfNoSideEffect in t.flags: addSep(prag) add(prag, "noSideEffect") if tfThread in t.flags: addSep(prag) add(prag, "gcsafe") + if t.lockLevel.ord != UnspecifiedLockLevel.ord: + addSep(prag) + add(prag, "locks: " & $t.lockLevel) if len(prag) != 0: add(result, "{." & prag & ".}") of tyVarargs, tyIter: result = typeToStr[t.kind] % typeToString(t.sons[0]) @@ -579,8 +580,7 @@ proc firstOrd(t: PType): BiggestInt = else: assert(t.n.sons[0].kind == nkSym) result = t.n.sons[0].sym.position - of tyGenericInst, tyDistinct, tyConst, tyMutable, - tyTypeDesc, tyFieldAccessor: + of tyGenericInst, tyDistinct, tyConst, tyMutable, tyTypeDesc, tyFieldAccessor: result = firstOrd(lastSon(t)) of tyOrdinal: if t.len > 0: result = firstOrd(lastSon(t)) @@ -969,6 +969,7 @@ proc inheritanceDiff*(a, b: PType): int = # | returns: -x iff `a` is the x'th direct superclass of `b` # | returns: +x iff `a` is the x'th direct subclass of `b` # | returns: `maxint` iff `a` and `b` are not compatible at all + if a == b or a.kind == tyError or b.kind == tyError: return 0 assert a.kind == tyObject assert b.kind == tyObject var x = a @@ -1014,10 +1015,10 @@ type TTypeAllowedFlags = set[TTypeAllowedFlag] -proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, +proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, flags: TTypeAllowedFlags = {}): bool -proc typeAllowedNode(marker: var TIntSet, n: PNode, kind: TSymKind, +proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind, flags: TTypeAllowedFlags = {}): bool = result = true if n != nil: @@ -1041,7 +1042,7 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]], a = a.sons[i] result = a.kind == last -proc typeAllowedAux(marker: var TIntSet, typ: PType, kind: TSymKind, +proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind, flags: TTypeAllowedFlags = {}): bool = assert(kind in {skVar, skLet, skConst, skParam, skResult}) # if we have already checked the type, return true, because we stop the @@ -1207,8 +1208,11 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = else: result = ptrSize a = ptrSize of tyNil, tyCString, tyString, tySequence, tyPtr, tyRef, tyVar, tyOpenArray, - tyBigNum: - result = ptrSize + tyBigNum: + let base = typ.lastSon + if base == typ or (base.kind == tyTuple and base.size==szIllegalRecursion): + result = szIllegalRecursion + else: result = ptrSize a = result of tyArray, tyArrayConstr: let elemSize = computeSizeAux(typ.sons[1], a) @@ -1270,7 +1274,7 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt = #internalError("computeSizeAux()") result = szUnknownSize typ.size = result - typ.align = int(a) + typ.align = int16(a) proc computeSize(typ: PType): BiggestInt = var a: BiggestInt = 1 @@ -1285,7 +1289,7 @@ proc getSize(typ: PType): BiggestInt = result = computeSize(typ) if result < 0: internalError("getSize: " & $typ.kind) -proc containsGenericTypeIter(t: PType, closure: PObject): bool = +proc containsGenericTypeIter(t: PType, closure: RootRef): bool = if t.kind == tyStatic: return t.n == nil @@ -1359,7 +1363,8 @@ proc compatibleEffects*(formal, actual: PType): bool = if real.len == 0: return false result = compatibleEffectsAux(st, real.sons[tagEffects]) if not result: return - result = true + result = formal.lockLevel.ord < 0 or + actual.lockLevel.ord <= formal.lockLevel.ord proc isCompileTimeOnly*(t: PType): bool {.inline.} = result = t.kind in {tyTypeDesc, tyStatic} diff --git a/compiler/vm.nim b/compiler/vm.nim index e40acca6c..e5b357a11 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -133,6 +133,8 @@ proc createStrKeepNode(x: var TFullReg) = # cause of bugs like these is that the VM does not properly distinguish # between variable defintions (var foo = e) and variable updates (foo = e). +include vmhooks + template createStr(x) = x.node = newNode(nkStrLit) @@ -256,8 +258,16 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame): c.currentExceptionB = c.currentExceptionA c.currentExceptionA = nil # execute the corresponding handler: + while c.code[pc2].opcode == opcExcept: inc pc2 return (pc2, f) inc pc2 + if c.code[pc2].opcode != opcExcept and nextExceptOrFinally >= 0: + # we're at the end of the *except list*, but maybe there is another + # *except branch*? + pc2 = nextExceptOrFinally+1 + if c.code[pc2].opcode == opcExcept: + nextExceptOrFinally = pc2 + c.code[pc2].regBx - wordExcess + if nextExceptOrFinally >= 0: pc2 = nextExceptOrFinally if c.code[pc2].opcode == opcFinally: @@ -801,7 +811,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = let bb = regs[rb].node let isClosure = bb.kind == nkPar let prc = if not isClosure: bb.sym else: bb.sons[0].sym - if sfImportc in prc.flags: + if prc.offset < -1: + # it's a callback: + c.callbacks[-prc.offset-2].value( + VmArgs(ra: ra, rb: rb, rc: rc, slots: cast[pointer](regs))) + elif sfImportc in prc.flags: if allowFFI notin c.features: globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI") # we pass 'tos.slots' instead of 'regs' so that the compiler can keep @@ -832,9 +846,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = if isClosure: newFrame.slots[rc].kind = rkNode newFrame.slots[rc].node = regs[rb].node.sons[1] - # allocate the temporaries: - #for i in rc+ord(isClosure) .. <prc.offset: - # newFrame.slots[i] = newNode(nkEmpty) tos = newFrame move(regs, newFrame.slots) # -1 for the following 'inc pc' @@ -888,10 +899,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcTry: let rbx = instr.regBx - wordExcess tos.pushSafePoint(pc + rbx) + assert c.code[pc+rbx].opcode in {opcExcept, opcFinally} of opcExcept: # just skip it; it's followed by a jump; # we'll execute in the 'raise' handler - discard + let rbx = instr.regBx - wordExcess - 1 # -1 for the following 'inc pc' + inc pc, rbx + assert c.code[pc+1].opcode in {opcExcept, opcFinally} of opcFinally: # just skip it; it's followed by the code we need to execute anyway tos.popSafePoint() @@ -1033,8 +1047,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = internalError(c.debug[pc], "too implement") of opcNarrowS: decodeB(rkInt) - let min = -(1 shl (rb-1)) - let max = (1 shl (rb-1))-1 + let min = -(1.BiggestInt shl (rb-1)) + let max = (1.BiggestInt shl (rb-1))-1 if regs[ra].intVal < min or regs[ra].intVal > max: stackTrace(c, tos, pc, errGenerated, msgKindToString(errUnhandledExceptionX) % "value out of range") @@ -1132,14 +1146,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = of opcParseExprToAst: decodeB(rkNode) # c.debug[pc].line.int - countLines(regs[rb].strVal) ? - let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename, + let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath, c.debug[pc].line.int) if sonsLen(ast) != 1: globalError(c.debug[pc], errExprExpected, "multiple statements") regs[ra].node = ast.sons[0] of opcParseStmtToAst: decodeB(rkNode) - let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFilename, + let ast = parseString(regs[rb].node.strVal, c.debug[pc].toFullPath, c.debug[pc].line.int) regs[ra].node = ast of opcCallSite: @@ -1316,6 +1330,8 @@ proc evalExpr*(c: PCtx, n: PNode): PNode = assert c.code[start].opcode != opcEof result = execute(c, start) +include vmops + # for now we share the 'globals' environment. XXX Coming soon: An API for # storing&loading the 'globals' environment to get what a component system # requires. @@ -1325,6 +1341,7 @@ var proc setupGlobalCtx(module: PSym) = if globalCtx.isNil: globalCtx = newCtx(module) else: refresh(globalCtx, module) + registerAdditionalOps(globalCtx) proc myOpen(module: PSym): PPassContext = #var c = newEvalContext(module, emRepl) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index cad48abea..d7cdafb69 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -170,7 +170,12 @@ type sym*: PSym slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]] maxSlots*: int - + + VmArgs* = object + ra*, rb*, rc*: Natural + slots*: pointer + VmCallback* = proc (args: VmArgs) {.closure.} + PCtx* = ref TCtx TCtx* = object of passes.TPassContext # code gen context code*: seq[TInstr] @@ -189,6 +194,7 @@ type traceActive*: bool loopIterations*: int comesFromHeuristic*: TLineInfo # Heuristic for better macro stack traces + callbacks*: seq[tuple[key: string, value: VmCallback]] TPosition* = distinct int @@ -198,12 +204,15 @@ proc newCtx*(module: PSym): PCtx = PCtx(code: @[], debug: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, - comesFromHeuristic: unknownLineInfo()) + comesFromHeuristic: unknownLineInfo(), callbacks: @[]) proc refresh*(c: PCtx, module: PSym) = c.module = module c.prc = PProc(blocks: @[]) +proc registerCallback*(c: PCtx; name: string; callback: VmCallback) = + c.callbacks.add((name, callback)) + const firstABxInstr* = opcTJmp largeInstrs* = { # instructions which use 2 int32s instead of 1: diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index fdd8276cc..6673d0bd2 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -9,7 +9,7 @@ import ast, types, msgs, osproc, streams, options -proc readOutput(p: PProcess): string = +proc readOutput(p: Process): string = result = "" var output = p.outputStream while not output.atEnd: @@ -33,6 +33,6 @@ proc opSlurp*(file: string, info: TLineInfo, module: PSym): string = # the module dependencies are accurate: appendToModule(module, newNode(nkIncludeStmt, info, @[ newStrNode(nkStrLit, filename)])) - except EIO: + except IOError: localError(info, errCannotOpenFile, file) result = "" diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index a4ddc2e15..fac3cf1bf 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -46,7 +46,6 @@ proc debugInfo(info: TLineInfo): string = proc codeListing(c: PCtx, result: var string, start=0; last = -1) = # first iteration: compute all necessary labels: var jumpTargets = initIntSet() - let last = if last < 0: c.code.len-1 else: min(last, c.code.len-1) for i in start..last: let x = c.code[i] @@ -83,7 +82,7 @@ proc codeListing(c: PCtx, result: var string, start=0; last = -1) = result.add("\n") inc i -proc echoCode*(c: PCtx, start=0; last = -1) {.deprecated.} = +proc echoCode*(c: PCtx; start=0; last = -1) {.deprecated.} = var buf = "" codeListing(c, buf, start, last) echo buf @@ -1068,6 +1067,9 @@ proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode; c.gABC(n, opcNodeToReg, dest, dest) elif c.prc.slots[tmp].kind >= slotTempUnknown: gABC(c, n, opcAddrNode, dest, tmp) + # XXX this can still be wrong sometimes; hopefully it's only generated + # in call contexts, where it is safe + #message(n.info, warnUser, "suspicious opcode used") else: gABC(c, n, opcAddrReg, dest, tmp) c.freeTemp(tmp) @@ -1134,6 +1136,9 @@ proc isTemp(c: PCtx; dest: TDest): bool = template needsAdditionalCopy(n): expr = not c.isTemp(dest) and not fitsRegister(n.typ) +proc skipDeref(n: PNode): PNode = + result = if n.kind in {nkDerefExpr, nkHiddenDeref}: n.sons[0] else: n + proc preventFalseAlias(c: PCtx; n: PNode; opc: TOpcode; dest, idx, value: TRegister) = # opcLdObj et al really means "load address". We sometimes have to create a @@ -1497,6 +1502,26 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) = proc genProc*(c: PCtx; s: PSym): int +proc matches(s: PSym; x: string): bool = + let y = x.split('.') + var s = s + var L = y.len-1 + while L >= 0: + if s == nil or y[L].cmpIgnoreStyle(s.name.s) != 0: return false + s = s.owner + dec L + result = true + +proc procIsCallback(c: PCtx; s: PSym): bool = + if s.offset < -1: return true + var i = -2 + for key, value in items(c.callbacks): + if s.matches(key): + doAssert s.offset == -1 + s.offset = i + return true + dec i + proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = case n.kind of nkSym: @@ -1507,7 +1532,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = genRdVar(c, n, dest, flags) of skProc, skConverter, skMacro, skTemplate, skMethod, skIterators: # 'skTemplate' is only allowed for 'getAst' support: - if sfImportc in s.flags: c.importcSym(n.info, s) + if procIsCallback(c, s): discard + elif sfImportc in s.flags: c.importcSym(n.info, s) genLit(c, n, dest) of skConst: gen(c, s.ast, dest) @@ -1569,6 +1595,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) = let L = n.len-1 for i in 0 .. <L: gen(c, n.sons[i]) gen(c, n.sons[L], dest, flags) + of nkPragmaBlock: + gen(c, n.lastSon, dest, flags) of nkDiscardStmt: unused(n, dest) gen(c, n.sons[0]) diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim new file mode 100644 index 000000000..cce87d433 --- /dev/null +++ b/compiler/vmhooks.nim @@ -0,0 +1,45 @@ +# +# +# The Nim Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +template setX(k, field) {.immediate, dirty.} = + var s: seq[TFullReg] + move(s, cast[seq[TFullReg]](a.slots)) + if s[a.ra].kind != k: + myreset(s[a.ra]) + s[a.ra].kind = k + s[a.ra].field = v + +proc setResult*(a: VmArgs; v: BiggestInt) = setX(rkInt, intVal) +proc setResult*(a: VmArgs; v: BiggestFloat) = setX(rkFloat, floatVal) +proc setResult*(a: VmArgs; v: bool) = + let v = v.ord + setX(rkInt, intVal) + +proc setResult*(a: VmArgs; v: string) = + var s: seq[TFullReg] + move(s, cast[seq[TFullReg]](a.slots)) + if s[a.ra].kind != rkNode: + myreset(s[a.ra]) + s[a.ra].kind = rkNode + s[a.ra].node = newNode(nkStrLit) + s[a.ra].node.strVal = v + +template getX(k, field) {.immediate, dirty.} = + doAssert i < a.rc-1 + let s = cast[seq[TFullReg]](a.slots) + doAssert s[i+a.rb+1].kind == k + result = s[i+a.rb+1].field + +proc getInt*(a: VmArgs; i: Natural): BiggestInt = getX(rkInt, intVal) +proc getFloat*(a: VmArgs; i: Natural): BiggestFloat = getX(rkFloat, floatVal) +proc getString*(a: VmArgs; i: Natural): string = + doAssert i < a.rc-1 + let s = cast[seq[TFullReg]](a.slots) + doAssert s[i+a.rb+1].kind == rkNode + result = s[i+a.rb+1].node.strVal diff --git a/compiler/vmops.nim b/compiler/vmops.nim new file mode 100644 index 000000000..aa25d208a --- /dev/null +++ b/compiler/vmops.nim @@ -0,0 +1,75 @@ +# +# +# The Nim Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Unforunately this cannot be a module yet: +#import vmdeps, vm +from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin, + arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc, + floor, ceil, fmod + +from os import getEnv, existsEnv, dirExists, fileExists + +template mathop(op) {.immediate, dirty.} = + registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`) + +template osop(op) {.immediate, dirty.} = + registerCallback(c, "stdlib.os." & astToStr(op), `op Wrapper`) + +template systemop(op) {.immediate, dirty.} = + registerCallback(c, "stdlib.system." & astToStr(op), `op Wrapper`) + +template wrap1f(op) {.immediate, dirty.} = + proc `op Wrapper`(a: VmArgs) {.nimcall.} = + setResult(a, op(getFloat(a, 0))) + mathop op + +template wrap2f(op) {.immediate, dirty.} = + proc `op Wrapper`(a: VmArgs) {.nimcall.} = + setResult(a, op(getFloat(a, 0), getFloat(a, 1))) + mathop op + +template wrap1s(op) {.immediate, dirty.} = + proc `op Wrapper`(a: VmArgs) {.nimcall.} = + setResult(a, op(getString(a, 0))) + osop op + +template wrap2svoid(op) {.immediate, dirty.} = + proc `op Wrapper`(a: VmArgs) {.nimcall.} = + op(getString(a, 0), getString(a, 1)) + systemop op + +proc registerAdditionalOps*(c: PCtx) = + wrap1f(sqrt) + wrap1f(ln) + wrap1f(log10) + wrap1f(log2) + wrap1f(exp) + wrap1f(round) + wrap1f(arccos) + wrap1f(arcsin) + wrap1f(arctan) + wrap2f(arctan2) + wrap1f(cos) + wrap1f(cosh) + wrap2f(hypot) + wrap1f(sinh) + wrap1f(sin) + wrap1f(tan) + wrap1f(tanh) + wrap2f(pow) + wrap1f(trunc) + wrap1f(floor) + wrap1f(ceil) + wrap2f(fmod) + + wrap1s(getEnv) + wrap1s(existsEnv) + wrap1s(dirExists) + wrap1s(fileExists) + wrap2svoid(writeFile) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 96056eb6f..068f59c71 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -64,7 +64,7 @@ type wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto, wInjectStmt, wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, wAsmNoStackFrame, - wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wUses, + wImplicitStatic, wGlobal, wCodegenDecl, wUnchecked, wGuard, wLocks, wAuto, wBool, wCatch, wChar, wClass, wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast, @@ -147,7 +147,7 @@ const "computedgoto", "injectstmt", "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit", "asmnostackframe", "implicitstatic", "global", "codegendecl", "unchecked", - "guard", "uses", + "guard", "locks", "auto", "bool", "catch", "char", "class", "const_cast", "default", "delete", "double", diff --git a/config/nim.cfg b/config/nim.cfg index df3835ace..b0a1ff81b 100644 --- a/config/nim.cfg +++ b/config/nim.cfg @@ -1,5 +1,5 @@ -# Configuration file for the Nimrod Compiler. -# (c) 2013 Andreas Rumpf +# Configuration file for the Nim Compiler. +# (c) 2014 Andreas Rumpf # Feel free to edit the default values as you need. @@ -13,6 +13,10 @@ cc = gcc arm.linux.gcc.exe = "arm-linux-gcc" arm.linux.gcc.linkerexe = "arm-linux-gcc" +@if not nimfix: + cs:partial +@end + path="$lib/core" path="$lib/pure" path="$lib/pure/collections" diff --git a/config/nimrod.cfg b/config/nimrod.cfg index df3835ace..6d56bba2c 100644 --- a/config/nimrod.cfg +++ b/config/nimrod.cfg @@ -1,5 +1,5 @@ -# Configuration file for the Nimrod Compiler. -# (c) 2013 Andreas Rumpf +# Configuration file for the Nim Compiler. +# (c) 2014 Andreas Rumpf # Feel free to edit the default values as you need. @@ -13,6 +13,8 @@ cc = gcc 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" diff --git a/doc/advopt.txt b/doc/advopt.txt index 7a11e9041..2ddba12e8 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -12,7 +12,6 @@ Advanced commands: module dependency graph //dump dump all defined conditionals and search paths //check checks the project for syntax and semantic - //pretty homogenizes source code style //idetools compiler support for IDEs: possible options: --track:FILE,LINE,COL track a file/cursor position --trackDirty:DIRTY_FILE,ORIG_FILE,LINE,COL @@ -28,7 +27,6 @@ Advanced commands: --server.address:HOST binds to that address, by default "" Advanced options: - -m, --mainmodule:FILE set the project main module -o, --out:FILE set the output filename --stdout output to stdout --listFullPaths list full paths in messages @@ -50,7 +48,7 @@ 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 Nimrod Debugger on|off + --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 @@ -58,7 +56,7 @@ Advanced options: --clib:LIBNAME link an additional C library (you should omit platform-specific extensions) --genMapping generate a mapping file containing - (Nimrod, mangled) identifier pairs + (Nim, mangled) identifier pairs --project document the whole project (doc2) --docSeeSrcUrl:url activate 'see source' for doc and doc2 commands (see doc.item.seesrc in config/nimdoc.cfg) @@ -79,7 +77,8 @@ Advanced options: select the GC to use; default is 'refc' --index:on|off turn index file generation on|off --putenv:key=value set an environment variable - --babelPath:PATH add a path for Babel support + --NimblePath:PATH add a path for Nimble support + --noNimblePath deactivate the Nimble path --excludePath:PATH exclude a path from the list of search paths --dynlibOverride:SYMBOL marks SYMBOL so that dynlib:SYMBOL has no effect and can be statically linked instead; @@ -89,7 +88,7 @@ Advanced options: --listCmd list the commands used to execute external programs --parallelBuild=0|1|... perform a parallel build value = number of processors (0 for auto-detect) - --verbosity:0|1|2|3 set Nimrod's verbosity level (1 is default) + --verbosity:0|1|2|3 set Nim's verbosity level (1 is default) --cs:none|partial set case sensitivity level (default: none); do not use! this setting affects the whole language -v, --version show detailed version information diff --git a/doc/apis.txt b/doc/apis.txt index 9906f6bbc..e0510d85f 100644 --- a/doc/apis.txt +++ b/doc/apis.txt @@ -84,5 +84,5 @@ indentation indent Coding Guidelines ================= -For coding guidelines see the `Internals of the Nimrod Compiler +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 6b6242614..5c4274093 100644 --- a/doc/astspec.txt +++ b/doc/astspec.txt @@ -1,11 +1,11 @@ -The AST in Nimrod +The AST in Nim ================= -This section describes how the AST is modelled with Nimrod's type system. +This section describes how the AST is modelled with Nim's type system. The AST consists of nodes (``PNimrodNode``) with a variable number of children. Each node has a field named ``kind`` which describes what the node contains: -.. code-block:: nimrod +.. code-block:: nim type TNimrodNodeKind = enum ## kind of a node; only explanatory @@ -39,7 +39,7 @@ contains: For the ``PNimrodNode`` type, the ``[]`` operator has been overloaded: ``n[i]`` is ``n``'s ``i``-th child. -To specify the AST for the different Nimrod constructs, the notation +To specify the AST for the different Nim constructs, the notation ``nodekind(son1, son2, ...)`` or ``nodekind(value)`` or ``nodekind(field=value)`` is used. @@ -53,7 +53,7 @@ A leaf of the AST often corresponds to a terminal symbol in the concrete syntax. ----------------- --------------------------------------------- -Nimrod expression corresponding AST +Nim expression corresponding AST ----------------- --------------------------------------------- ``42`` ``nnkIntLit(intVal = 42)`` ``42'i8`` ``nnkInt8Lit(intVal = 42)`` @@ -87,12 +87,12 @@ Command call Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim echo "abc", "xyz" AST: -.. code-block:: nimrod +.. code-block:: nim nnkCommand(nnkIdent(!"echo"), nnkStrLit("abc"), nnkStrLit("xyz")) @@ -101,12 +101,12 @@ Call with ``()`` Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim echo("abc", "xyz") AST: -.. code-block:: nimrod +.. code-block:: nim nnkCall(nnkIdent(!"echo"), nnkStrLit("abc"), nnkStrLit("xyz")) @@ -115,12 +115,12 @@ Infix operator call Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim "abc" & "xyz" AST: -.. code-block:: nimrod +.. code-block:: nim nnkInfix(nnkIdent(!"&"), nnkStrLit("abc"), nnkStrLit("xyz")) @@ -129,29 +129,29 @@ Prefix operator call Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim ? "xyz" AST: -.. code-block:: nimrod +.. code-block:: nim nnkPrefix(nnkIdent(!"?"), nnkStrLit("abc")) Postfix operator call --------------------- -**Note:** There are no postfix operators in Nimrod. However, the +**Note:** There are no postfix operators in Nim. However, the ``nnkPostfix`` node is used for the *asterisk export marker* ``*``: Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim identifier* AST: -.. code-block:: nimrod +.. code-block:: nim nnkPostfix(nnkIdent(!"*"), nnkIdent(!"identifier")) @@ -160,12 +160,12 @@ Call with named arguments Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim writeln(file=stdout, "hallo") AST: -.. code-block:: nimrod +.. code-block:: nim nnkCall(nnkIdent(!"writeln"), nnkExprEqExpr(nnkIdent(!"file"), nnkIdent(!"stdout")), nnkStrLit("hallo")) @@ -176,12 +176,12 @@ Dereference operator ``^`` Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim x^ AST: -.. code-block:: nimrod +.. code-block:: nim nnkDerefExpr(nnkIdent(!"x")) @@ -190,12 +190,12 @@ Addr operator Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim addr(x) AST: -.. code-block:: nimrod +.. code-block:: nim nnkAddr(nnkIdent(!"x")) @@ -204,12 +204,12 @@ Cast operator Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim cast[T](x) AST: -.. code-block:: nimrod +.. code-block:: nim nnkCast(nnkIdent(!"T"), nnkIdent(!"x")) @@ -218,12 +218,12 @@ Object access operator ``.`` Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim x.y AST: -.. code-block:: nimrod +.. code-block:: nim nnkDotExpr(nnkIdent(!"x"), nnkIdent(!"y")) @@ -232,12 +232,12 @@ Array access operator ``[]`` Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim x[y] AST: -.. code-block:: nimrod +.. code-block:: nim nnkBracketExpr(nnkIdent(!"x"), nnkIdent(!"y")) @@ -249,12 +249,12 @@ are built with the ``nnkPar`` node. Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim (1, 2, (3)) AST: -.. code-block:: nimrod +.. code-block:: nim nnkPar(nnkIntLit(1), nnkIntLit(2), nnkPar(nnkIntLit(3))) @@ -265,12 +265,12 @@ Curly braces are used as the set constructor. Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim {1, 2, 3} AST: -.. code-block:: nimrod +.. code-block:: nim nnkCurly(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3)) @@ -281,12 +281,12 @@ Brackets are used as the array constructor. Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim [1, 2, 3] AST: -.. code-block:: nimrod +.. code-block:: nim nnkBracket(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3)) @@ -297,12 +297,12 @@ Ranges occur in set constructors, case statement branches or array slices. Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim 1..3 AST: -.. code-block:: nimrod +.. code-block:: nim nnkRange(nnkIntLit(1), nnkIntLit(3)) @@ -313,12 +313,12 @@ The representation of the if expression is subtle, but easy to traverse. Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim if cond1: expr1 elif cond2: expr2 else: expr3 AST: -.. code-block:: nimrod +.. code-block:: nim nnkIfExpr( nnkElifExpr(cond1, expr1), nnkElifExpr(cond2, expr2), @@ -337,7 +337,7 @@ there is no ``else`` branch, no ``nnkElse`` child exists. Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim if cond1: stmt1 elif cond2: @@ -349,7 +349,7 @@ Concrete syntax: AST: -.. code-block:: nimrod +.. code-block:: nim nnkIfStmt( nnkElifBranch(cond1, stmt1), nnkElifBranch(cond2, stmt2), @@ -369,12 +369,12 @@ Assignment Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim x = 42 AST: -.. code-block:: nimrod +.. code-block:: nim nnkAsgn(nnkIdent(!"x"), nnkIntLit(42)) @@ -383,14 +383,14 @@ Statement list Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim stmt1 stmt2 stmt3 AST: -.. code-block:: nimrod +.. code-block:: nim nnkStmtList(stmt1, stmt2, stmt3) @@ -399,7 +399,7 @@ Case statement Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim case expr1 of expr2, expr3..expr4: stmt1 @@ -412,7 +412,7 @@ Concrete syntax: AST: -.. code-block:: nimrod +.. code-block:: nim nnkCaseStmt( expr1, nnkOfBranch(expr2, nnkRange(expr3, expr4), stmt1), @@ -429,13 +429,13 @@ While statement Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim while expr1: stmt1 AST: -.. code-block:: nimrod +.. code-block:: nim nnkWhileStmt(expr1, stmt1) @@ -444,13 +444,13 @@ For statement Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim for ident1, ident2 in expr1: stmt1 AST: -.. code-block:: nimrod +.. code-block:: nim nnkForStmt(ident1, ident2, expr1, stmt1) @@ -459,7 +459,7 @@ Try statement Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim try: stmt1 except e1, e2: @@ -473,7 +473,7 @@ Concrete syntax: AST: -.. code-block:: nimrod +.. code-block:: nim nnkTryStmt( stmt1, nnkExceptBranch(e1, e2, stmt2), @@ -488,12 +488,12 @@ Return statement Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim return expr1 AST: -.. code-block:: nimrod +.. code-block:: nim nnkReturnStmt(expr1) @@ -514,12 +514,12 @@ Continue statement Concrete syntax: -.. code-block:: nimrod +.. code-block:: nim continue AST: -.. code-block:: nimrod +.. code-block:: nim nnkContinueStmt() Var section diff --git a/doc/backends.txt b/doc/backends.txt index c2dbb0af6..eb16217cd 100644 --- a/doc/backends.txt +++ b/doc/backends.txt @@ -1,9 +1,9 @@ ================================ - Nimrod Backend Integration + Nim Backend Integration ================================ :Author: Puppet Master -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: "Heresy grows from idleness." -- Unknown. @@ -12,20 +12,20 @@ Introduction ============ -The `Nimrod Compiler User Guide <nimrodc.html>`_ documents the typical +The `Nim Compiler User Guide <nimc.html>`_ documents the typical compiler invocation, using the ``compile`` or ``c`` command to transform a ``.nim`` file into one or more ``.c`` files which are then compiled with the platform's C compiler into a static binary. However there are other commands to compile to C++, Objective-C or JavaScript. This document tries to concentrate in a single place all the backend and interfacing options. -The Nimrod compiler supports mainly two backend families: the C, C++ and +The Nim compiler supports mainly two backend families: the C, C++ and Objective-C targets and the JavaScript target. `The C like targets`_ creates source files which can be compiled into a library or a final executable. `The JavaScript target`_ can generate a ``.js`` file which you reference from an HTML file or create a `standalone nodejs program <http://nodejs.org>`_. -On top of generating libraries or standalone applications, Nimrod offers +On top of generating libraries or standalone applications, Nim offers bidirectional interfacing with the backend targets through generic and specific pragmas. @@ -49,25 +49,25 @@ project. This allows you to take the generated code and place it directly into a project using any of these languages. Here are some typical command line invocations:: - $ nimrod c hallo.nim - $ nimrod cpp hallo.nim - $ nimrod objc hallo.nim + $ nim c hallo.nim + $ nim cpp hallo.nim + $ nim objc hallo.nim The compiler commands select the target backend, but if needed you can `specify additional switches for cross compilation -<nimrodc.html#cross-compilation>`_ to select the target CPU, operative system +<nimc.html#cross-compilation>`_ to select the target CPU, operative system or compiler/linker commands. The JavaScript target --------------------- -Nimrod can also generate `JavaScript`:idx: code through the ``js`` command. +Nim can also generate `JavaScript`:idx: code through the ``js`` command. However, the JavaScript code generator is experimental! -Nimrod targets JavaScript 1.5 which is supported by any widely used browser. +Nim targets JavaScript 1.5 which is supported by any widely used browser. Since JavaScript does not have a portable means to include another module, -Nimrod just generates a long ``.js`` file. +Nim just generates a long ``.js`` file. Features or modules that the JavaScript platform does not support are not available. This includes: @@ -83,35 +83,35 @@ However, the modules `strutils <strutils.html>`_, `math <math.html>`_, and `times <times.html>`_ are available! To access the DOM, use the `dom <dom.html>`_ module that is only available for the JavaScript platform. -To compile a Nimrod module into a ``.js`` file use the ``js`` command; the +To compile a Nim module into a ``.js`` file use the ``js`` command; the default is a ``.js`` file that is supposed to be referenced in an ``.html`` file. However, you can also run the code with `nodejs`:idx:, a `software platform for easily building fast, scalable network applications <http://nodejs.org>`_:: - nimrod js -d:nodejs -r examples/hallo.nim + nim js -d:nodejs -r examples/hallo.nim Interfacing =========== -Nimrod offers bidirectional interfacing with the target backend. This means -that you can call backend code from Nimrod and Nimrod code can be called by +Nim offers bidirectional interfacing with the target backend. This means +that you can call backend code from Nim and Nim code can be called by the backend code. Usually the direction of which calls which depends on your -software architecture (is Nimrod your main program or is Nimrod providing a +software architecture (is Nim your main program or is Nim providing a component?). -Nimrod code calling the backend --------------------------------- +Nim code calling the backend +---------------------------- -Nimrod code can interface with the backend through the `Foreign function +Nim code can interface with the backend through the `Foreign function interface <manual.html#foreign-function-interface>`_ mainly through the `importc pragma <manual.html#importc-pragma>`_. The ``importc`` pragma is the -*generic* way of making backend symbols available in Nimrod and is available +*generic* way of making backend symbols available in Nim and is available in all the target backends (JavaScript too). The C++ or Objective-C backends -have their respective `ImportCpp <nimrodc.html#importcpp-pragma>`_ and -`ImportObjC <nimrodc.html#importobjc-pragma>`_ pragmas to call methods from +have their respective `ImportCpp <nimc.html#importcpp-pragma>`_ and +`ImportObjC <nimc.html#importobjc-pragma>`_ pragmas to call methods from classes. Whenever you use any of these pragmas you need to integrate native code into @@ -121,22 +121,22 @@ JavaScript functions which you are importing with ``importc``. However, for the C like targets you need to link external code either statically or dynamically. The preferred way of integrating native code is to -use dynamic linking because it allows you to compile Nimrod programs without +use dynamic linking because it allows you to compile Nim programs without the need for having the related development libraries installed. This is done through the `dynlib pragma for import <manual.html#dynlib-pragma-for-import>`_, though more specific control can be gained using the `dynlib module <dynlib.html>`_. -The `dynlibOverride <nimrodc.html#dynliboverride>`_ command line switch allows +The `dynlibOverride <nimc.html#dynliboverride>`_ command line switch allows to avoid dynamic linking if you need to statically link something instead. -Nimrod wrappers designed to statically link source files can use the `compile -pragma <nimrodc.html#compile-pragma>`_ if there are few sources or providing -them along the Nimrod code is easier than using a system library. Libraries +Nim wrappers designed to statically link source files can use the `compile +pragma <nimc.html#compile-pragma>`_ if there are few sources or providing +them along the Nim code is easier than using a system library. Libraries installed on the host system can be linked in with the `PassL pragma -<nimrodc.html#passl-pragma>`_. +<nimc.html#passl-pragma>`_. To wrap native code, take a look at the `c2nim tool <c2nim.html>`_ which helps -with the process of scanning and transforming header files into a Nimrod +with the process of scanning and transforming header files into a Nim interface. C invocation example @@ -152,7 +152,7 @@ Create a ``logic.c`` file with the following content: Create a ``calculator.nim`` file with the following content: -.. code-block:: nimrod +.. code-block:: nim {.compile: "logic.c".} proc addTwoIntegers(a, b: cint): cint {.importc.} @@ -160,8 +160,8 @@ Create a ``calculator.nim`` file with the following content: when isMainModule: echo addTwoIntegers(3, 7) -With these two files in place, you can run ``nimrod c -r calculator.nim`` and -the Nimrod compiler will compile the ``logic.c`` file in addition to +With these two files in place, you can run ``nim c -r calculator.nim`` and +the Nim compiler will compile the ``logic.c`` file in addition to ``calculator.nim`` and link both into an executable, which outputs ``10`` when run. Another way to link the C file statically and get the same effect would be remove the line with the ``compile`` pragma and run the following typical @@ -169,7 +169,7 @@ Unix commands:: $ gcc -c logic.c $ ar rvs mylib.a logic.o - $ nimrod c --passL:mylib.a -r calculator.nim + $ nim c --passL:mylib.a -r calculator.nim Just like in this example we pass the path to the ``mylib.a`` library (and we could as well pass ``logic.o``) we could be passing switches to link any other @@ -196,50 +196,50 @@ Create a ``host.html`` file with the following content: Create a ``calculator.nim`` file with the following content (or reuse the one from the previous section): -.. code-block:: nimrod +.. code-block:: nim proc addTwoIntegers(a, b: int): int {.importc.} when isMainModule: echo addTwoIntegers(3, 7) -Compile the Nimrod code to JavaScript with ``nimrod js -o:calculator.js +Compile the Nim code to JavaScript with ``nim js -o:calculator.js calculator.nim`` and open ``host.html`` in a browser. If the browser supports javascript, you should see the value ``10``. In JavaScript the `echo proc <system.html#echo>`_ will modify the HTML DOM and append the string. Use the `dom module <dom.html>`_ for specific DOM querying and modification procs. -Backend code calling Nimrod ---------------------------- +Backend code calling Nim +------------------------ -Backend code can interface with Nimrod code exposed through the `exportc +Backend code can interface with Nim code exposed through the `exportc pragma <manual.html#exportc-pragma>`_. The ``exportc`` pragma is the *generic* -way of making Nimrod symbols available to the backends. By default the Nimrod -compiler will mangle all the Nimrod symbols to avoid any name collision, so -the most significant thing the ``exportc`` pragma does is maintain the Nimrod +way of making Nim symbols available to the backends. By default the Nim +compiler will mangle all the Nim symbols to avoid any name collision, so +the most significant thing the ``exportc`` pragma does is maintain the Nim symbol name, or if specified, use an alternative symbol for the backend in case the symbol rules don't match. The JavaScript target doesn't have any further interfacing considerations since it also has garbage collection, but the C targets require you to -initialize Nimrod's internals, which is done calling a ``NimMain`` function. +initialize Nim's internals, which is done calling a ``NimMain`` function. Also, C code requires you to specify a forward declaration for functions or the compiler will asume certain types for the return value and parameters which will likely make your program crash at runtime. -The Nimrod compiler can generate a C interface header through the ``--header`` +The Nim compiler can generate a C interface header through the ``--header`` command line switch. The generated header will contain all the exported symbols and the ``NimMain`` proc which you need to call before any other -Nimrod code. +Nim code. -Nimrod invocation example from C -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Nim invocation example from C +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Create a ``fib.nim`` file with the following content: -.. code-block:: nimrod +.. code-block:: nim proc fib(a: cint): cint {.exportc.} = if a <= 2: @@ -263,35 +263,35 @@ Create a ``maths.c`` file with the following content: } Now you can run the following Unix like commands to first generate C sources -form the Nimrod code, then link them into a static binary along your main C +form the Nim code, then link them into a static binary along your main C program:: - $ nimrod c --noMain --noLinking --header:fib.h fib.nim - $ gcc -o m -Inimcache -Ipath/to/nimrod/lib nimcache/*.c maths.c + $ nim c --noMain --noLinking --header:fib.h fib.nim + $ gcc -o m -Inimcache -Ipath/to/nim/lib nimcache/*.c maths.c -The first command runs the Nimrod compiler with three special options to avoid +The first command runs the Nim compiler with three special options to avoid generating a ``main()`` function in the generated files, avoid linking the object files into a final binary, and explicitly generate a header file for C integration. All the generated files are placed into the ``nimcache`` directory. That's why the next command compiles the ``maths.c`` source plus all the ``.c`` files form ``nimcache``. In addition to this path, you also -have to tell the C compiler where to find Nimrod's ``nimbase.h`` header file. +have to tell the C compiler where to find Nim's ``nimbase.h`` header file. Instead of depending on the generation of the individual ``.c`` files you can -also ask the Nimrod compiler to generate a statically linked library:: +also ask the Nim compiler to generate a statically linked library:: - $ nimrod c --app:staticLib --noMain --header fib.nim - $ gcc -o m -Inimcache -Ipath/to/nimrod/lib libfib.nim.a maths.c + $ nim c --app:staticLib --noMain --header fib.nim + $ gcc -o m -Inimcache -Ipath/to/nim/lib libfib.nim.a maths.c -The Nimrod compiler will handle linking the source files generated in the +The Nim compiler will handle linking the source files generated in the ``nimcache`` directory into the ``libfib.nim.a`` static library, which you can then link into your C program. Note that these commands are generic and will vary for each system. For instance, on Linux systems you will likely need to use ``-ldl`` too to link in required dlopen functionality. -Nimrod invocation example from JavaScript -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Nim invocation example from JavaScript +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Create a ``mhost.html`` file with the following content: @@ -307,7 +307,7 @@ Create a ``mhost.html`` file with the following content: Create a ``fib.nim`` file with the following content (or reuse the one from the previous section): -.. code-block:: nimrod +.. code-block:: nim proc fib(a: cint): cint {.exportc.} = if a <= 2: @@ -315,11 +315,11 @@ from the previous section): else: result = fib(a - 1) + fib(a - 2) -Compile the Nimrod code to JavaScript with ``nimrod js -o:fib.js fib.nim`` and +Compile the Nim code to JavaScript with ``nim js -o:fib.js fib.nim`` and open ``mhost.html`` in a browser. If the browser supports javascript, you should see an alert box displaying the text ``Fib for 9 is 34``. As mentioned earlier, JavaScript doesn't require an initialisation call to ``NimMain`` or -similar function and you can call the exported Nimrod proc directly. +similar function and you can call the exported Nim proc directly. Nimcache naming logic @@ -328,17 +328,17 @@ Nimcache naming logic The `nimcache`:idx: directory is generated during compilation and will hold either temporary or final files depending on your backend target. The default name for the directory is ``nimcache`` but you can use the ``--nimcache`` -`compiler switch <nimrodc.html#command-line-switches>`_ to change it. +`compiler switch <nimc.html#command-line-switches>`_ to change it. Nimcache and C like targets ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The C like backends will place their temporary ``.c``, ``.cpp`` or ``.m`` files in the ``nimcache`` directory. The naming of these files follows the pattern -``babelPackageName_`` + ``nimrodSource``: +``babelPackageName_`` + ``nimSource``: * Filenames for modules imported from `Babel packages - <https://github.com/nimrod-code/babel>`_ will end up with + <https://github.com/nim-code/babel>`_ will end up with ``babelPackageName_module.c``. For example, if you import the ``argument_parser`` module from the same name Babel package you will end up with a ``argument_parser_argument_parser.c`` file @@ -375,7 +375,7 @@ Nimcache and the Javascript target Unless you explicitly use the ``-o:filename.js`` switch as mentioned in the previous examples, the compiler will create a ``filename.js`` file in the -``nimcache`` directory using the name of your input nimrod file. There are no +``nimcache`` directory using the name of your input nim file. There are no other temporary files generated, the output is always a single self contained ``.js`` file. @@ -387,38 +387,38 @@ In the previous sections the ``NimMain()`` function reared its head. Since JavaScript already provides automatic memory management, you can freely pass objects between the two language without problems. In C and derivate languages you need to be careful about what you do and how you share memory. The -previous examples only dealt with simple scalar values, but passing a Nimrod -string to C, or reading back a C string in Nimrod already requires you to be +previous examples only dealt with simple scalar values, but passing a Nim +string to C, or reading back a C string in Nim already requires you to be aware of who controls what to avoid crashing. Strings and C strings --------------------- -The manual mentions that `Nimrod strings are implicitly convertible to +The manual mentions that `Nim strings are implicitly convertible to cstrings <manual.html#cstring-type>`_ which makes interaction usually -painless. Most C functions accepting a Nimrod string converted to a +painless. Most C functions accepting a Nim string converted to a ``cstring`` will likely not need to keep this string around and by the time they return the string won't be needed any more. However, for the rare cases -where a Nimrod string has to be preserved and made available to the C backend +where a Nim string has to be preserved and made available to the C backend as a ``cstring``, you will need to manually prevent the string data from being freed with `GC_ref <system.html#GC_ref>`_ and `GC_unref <system.html#GC_unref>`_. -A similar thing happens with C code invoking Nimrod code which returns a +A similar thing happens with C code invoking Nim code which returns a ``cstring``. Consider the following proc: -.. code-block:: nimrod +.. code-block:: nim proc gimme(): cstring {.exportc.} = result = "Hey there C code! " & $random(100) -Since Nimrod's garbage collector is not aware of the C code, once the +Since Nim's garbage collector is not aware of the C code, once the ``gimme`` proc has finished it can reclaim the memory of the ``cstring``. However, from a practical standpoint, the C code invoking the ``gimme`` -function directly will be able to use it since Nimrod's garbage collector has +function directly will be able to use it since Nim's garbage collector has not had a chance to run *yet*. This gives you enough time to make a copy for -the C side of the program, as calling any further Nimrod procs *might* trigger +the C side of the program, as calling any further Nim procs *might* trigger garbage collection making the previously returned string garbage. Or maybe you are `triggering yourself the collection <gc.html>`_. @@ -426,35 +426,35 @@ are `triggering yourself the collection <gc.html>`_. Custom data types ----------------- -Just like strings, custom data types that are to be shared between Nimrod and +Just like strings, custom data types that are to be shared between Nim and the backend will need careful consideration of who controlls who. If you want -to hand a Nimrod reference to C code, you will need to use `GC_ref +to hand a Nim reference to C code, you will need to use `GC_ref <system.html#GC_ref>`_ to mark the reference as used, so it does not get freed. And for the C backend you will need to expose the `GC_unref <system.html#GC_unref>`_ proc to clean up this memory when it is not required any more. Again, if you are wrapping a library which *mallocs* and *frees* data -structures, you need to expose the appropriate *free* function to Nimrod so +structures, you need to expose the appropriate *free* function to Nim so you can clean it up. And of course, once cleaned you should avoid accessing it -from Nimrod (or C for that matter). Typically C data structures have their own +from Nim (or C for that matter). Typically C data structures have their own ``malloc_structure`` and ``free_structure`` specific functions, so wrapping -these for the Nimrod side should be enough. +these for the Nim side should be enough. Thread coordination ------------------- -When the ``NimMain()`` function is called Nimrod initializes the garbage +When the ``NimMain()`` function is called Nim initializes the garbage collector to the current thread, which is usually the main thread of your -application. If your C code later spawns a different thread and calls Nimrod +application. If your C code later spawns a different thread and calls Nim code, the garbage collector will fail to work properly and you will crash. -As long as you don't use the threadvar emulation Nimrod uses native thread +As long as you don't use the threadvar emulation Nim uses native thread variables, of which you get a fresh version whenever you create a thread. You can then attach a GC to this thread via -.. code-block:: nimrod +.. code-block:: nim setStackBottom(addr(someLocal)) initGC() diff --git a/doc/basicopt.txt b/doc/basicopt.txt index fdb0e36e1..e8aaa2e4c 100644 --- a/doc/basicopt.txt +++ b/doc/basicopt.txt @@ -1,11 +1,11 @@ Usage:: - nimrod command [options] [projectfile] [arguments] + nim command [options] [projectfile] [arguments] 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 Nimrod in interactive mode (limited) + //i start Nim in interactive mode (limited) Arguments: arguments are passed to the program being run (if --run option is selected) @@ -35,3 +35,5 @@ Options: -r, --run run the compiled program with given arguments --advanced show advanced command line switches -h, --help show this help + +Note: Even single letter options require the colon: -p:PATH. diff --git a/doc/docgen.txt b/doc/docgen.txt index 30d0c6ff2..554f69838 100644 --- a/doc/docgen.txt +++ b/doc/docgen.txt @@ -1,9 +1,9 @@ =================================== - Nimrod DocGen Tools Guide + Nim DocGen Tools Guide =================================== :Author: Erik O'Leary -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: @@ -12,7 +12,7 @@ Introduction ============ This document describes the `documentation generation tools`:idx: built into -the `Nimrod compiler <nimrodc.html>`_, which can generate HTML and JSON output +the `Nim compiler <nimc.html>`_, which can generate HTML and JSON output from input .nim files and projects, as well as HTML and LaTeX from input RST (reStructuredText) files. The output documentation will include module dependencies (``import``), any top-level documentation comments (##), and @@ -25,12 +25,12 @@ Documentation Comments Any comments which are preceded by a double-hash (##), are interpreted as documentation. Comments are parsed as RST (see `reference <http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_), providing -Nimrod module authors the ability to easily generate richly formatted +Nim module authors the ability to easily generate richly formatted documentation with only their well-documented code. Example: -.. code-block:: nimrod +.. code-block:: nim type TPerson* = object ## This type contains a description of a person name: string @@ -45,7 +45,7 @@ This type contains a description of a person Field documentation comments can be added to fields like so: -.. code-block:: nimrod +.. code-block:: nim var numValues: int ## \ ## `numValues` stores the number of values @@ -54,15 +54,15 @@ this type would not be generated. Documentation will only be generated for *exported* types/procedures/etc. -Nimrod file input +Nim file input ----------------- The following examples will generate documentation for the below contrived -*Nimrod* module, aptly named 'sample.nim' +*Nim* module, aptly named 'sample.nim' sample.nim: -.. code-block:: nimrod +.. code-block:: nim ## This module is a sample. import strutils @@ -90,7 +90,7 @@ commands. These command take either a single .nim file, outputting a single multiple .html files and, optionally, an index file. The ``doc`` command:: - nimrod doc sample + nim doc sample Partial Output:: ... @@ -99,11 +99,11 @@ Partial Output:: Output can be viewed in full here: `docgen_sample.html <docgen_sample.html>`_. The next command, called ``doc2``, is very similar to the ``doc`` command, but -will be run after the compiler performs semantic checking on the input nimrod +will be run after the compiler performs semantic checking on the input nim module(s), which allows it to process macros. The ``doc2`` command:: - nimrod doc2 sample + nim doc2 sample Partial Output:: ... @@ -127,7 +127,7 @@ Note that this tool is built off of the ``doc`` command, and therefore is performed before semantic checking. The ``jsondoc`` command:: - nimrod jsondoc sample + nim jsondoc sample Output:: [ @@ -150,9 +150,9 @@ Project switch -------------- :: - nimrod doc2 --project filename.nim + nim doc2 --project filename.nim -This will recursively generate documentation of all nimrod modules imported +This will recursively generate documentation of all nim modules imported into the input module, including system modules. Be careful with this command, as it may end up sprinkling html files all over your filesystem! @@ -161,15 +161,15 @@ Index switch ------------ :: - nimrod doc2 --index:on filename.nim + nim doc2 --index:on filename.nim -This will generate an index of all the exported symbols in the input Nimrod +This will generate an index of all the exported symbols in the input Nim module, and put it into a neighboring file with the extension of ``.idx``. The index file is line oriented (newlines have to be escaped). Each line represents a tab separated record of several columns, the first two mandatory, the rest optional. See the `Index (idx) file format`_ section for details. -Once index files have been generated for one or more modules, the Nimrod +Once index files have been generated for one or more modules, the Nim compiler command ``buildIndex directory`` can be run to go over all the index files in the specified directory to generate a `theindex.html <theindex.html>`_ file. @@ -178,7 +178,7 @@ See source switch ----------------- :: - nimrod doc2 --docSeeSrcUrl:txt filename.nim + nim doc2 --docSeeSrcUrl:txt filename.nim When you pass the ``docSeeSrcUrl`` switch to docgen, after each documented item in your source code the hyper link *See source* will appear pointing to the @@ -191,25 +191,25 @@ hyper link to your own code repository. As you will see by the comments in that file, the value ``txt`` passed on the command line will be used in the HTML template along others like ``$path`` and ``$line``. -In the case of Nimrod's own documentation, the ``txt`` value is just a commit -hash to append to a formatted URL to https://github.com/Araq/Nimrod. The +In the case of Nim's own documentation, the ``txt`` value is just a commit +hash to append to a formatted URL to https://github.com/Araq/Nim. The ``tools/nimweb.nim`` helper queries the current git commit hash during doc generation, but since you might be working on an unpublished repository, it -also allows specifying a ``githash`` value in ``web/nimrod.ini`` to force a +also allows specifying a ``githash`` value in ``web/nim.ini`` to force a specific commit in the output. Other Input Formats =================== -The *Nimrod compiler* also has support for RST (reStructuredText) files with +The *Nim compiler* also has support for RST (reStructuredText) files with the ``rst2html`` and ``rst2tex`` commands. Documents like this one are -initially written in a dialect of RST which adds support for nimrod sourcecode -highlighting with the ``.. code-block:: nimrod`` prefix. ``code-block`` also +initially written in a dialect of RST which adds support for nim sourcecode +highlighting with the ``.. code-block:: nim`` prefix. ``code-block`` also supports highlighting of C++ and some other c-like languages. Usage:: - nimrod rst2html docgen.txt + nim rst2html docgen.txt Output:: You're reading it! @@ -272,8 +272,8 @@ symbols in the `system module <system.html>`_. `#TSignedInt <system.html#TSignedInt>`_ * ``var globalRaiseHook: proc (e: ref E_Base): bool {.nimcall.}`` **=>** `#globalRaiseHook <system.html#globalRaiseHook>`_ -* ``const NimrodVersion = "0.0.0"`` **=>** - `#NimrodVersion <system.html#NimrodVersion>`_ +* ``const NimVersion = "0.0.0"`` **=>** + `#NimVersion <system.html#NimVersion>`_ * ``proc getTotalMem(): int {.rtl, raises: [], tags: [].}`` **=>** `#getTotalMem, <system.html#getTotalMem,>`_ * ``proc len[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}`` **=>** @@ -304,7 +304,7 @@ but can have up to four (additional columns are ignored). The content of these columns is: 1. Mandatory term being indexed. Terms can include quoting according to - Nimrod's rules (eg. \`^\` like in `the actors module + Nim's rules (eg. \`^\` like in `the actors module <actors.html#^,ptr.TChannel[T]>`_). 2. Base filename plus anchor hyper link (eg. ``algorithm.html#*,int,TSortOrder``). @@ -342,7 +342,7 @@ final index, and TOC entries found in ``.nim`` files are discarded. Additional resources ==================== -`Nimrod Compiler User Guide <nimrodc.html#command-line-switches>`_ +`Nim Compiler User Guide <nimc.html#command-line-switches>`_ `RST Quick Reference <http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_ diff --git a/doc/docs.txt b/doc/docs.txt index 8126da86c..ecf0cc268 100644 --- a/doc/docs.txt +++ b/doc/docs.txt @@ -1,18 +1,18 @@ The documentation consists of several documents: - | `Tutorial (part I) <tut1.html>`_ - | The Nimrod tutorial part one deals with the basics. + | The Nim tutorial part one deals with the basics. - | `Tutorial (part II) <tut2.html>`_ - | The Nimrod tutorial part two deals with the advanced language constructs. + | The Nim tutorial part two deals with the advanced language constructs. - | `Language Manual <manual.html>`_ - | The Nimrod manual is a draft that will evolve into a proper specification. + | The Nim manual is a draft that will evolve into a proper specification. - | `Library documentation <lib.html>`_ - | This document describes Nimrod's standard library. + | This document describes Nim's standard library. -- | `Compiler user guide <nimrodc.html>`_ +- | `Compiler user guide <nimc.html>`_ | The user guide lists command line arguments, special features of the compiler, etc. @@ -20,11 +20,11 @@ The documentation consists of several documents: | Description of some tools that come with the standard distribution. - | `GC <gc.html>`_ - | Additional documentation about Nimrod's GC and how to operate it in a + | Additional documentation about Nim's GC and how to operate it in a | realtime setting. - | `Source code filters <filters.html>`_ - | The Nimrod compiler supports source code filters as a simple yet powerful + | The Nim compiler supports source code filters as a simple yet powerful builtin templating system. - | `Term rewriting macros <trmacros.html>`_ diff --git a/doc/effects.txt b/doc/effects.txt index 8084ae17a..4ed1d09f1 100644 --- a/doc/effects.txt +++ b/doc/effects.txt @@ -1,5 +1,5 @@ ===================================================================== - Side effects in Nimrod + Side effects in Nim ===================================================================== Note: Side effects are implicit produced values! Maybe they should be @@ -13,7 +13,7 @@ difficult is the ``newString`` proc: If it is simply wrapped, it should not be evaluated at compile time! On other occasions it can and should be evaluted: -.. code-block:: nimrod +.. code-block:: nim proc toUpper(s: string): string = result = newString(len(s)) for i in 0..len(s) - 1: diff --git a/doc/endb.txt b/doc/endb.txt index e9a01b583..049f9d40d 100644 --- a/doc/endb.txt +++ b/doc/endb.txt @@ -1,15 +1,17 @@ ============================================== - Embedded Nimrod Debugger (ENDB) User Guide + Embedded Nim Debugger (ENDB) User Guide ============================================== :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: +**WARNING**: ENDB is not maintained anymore! Please help if you're interested +in this tool. -Nimrod comes with a platform independent debugger - -the Embedded Nimrod Debugger (ENDB). The debugger is +Nim comes with a platform independent debugger - +the Embedded Nim Debugger (ENDB). The debugger is *embedded* into your executable if it has been compiled with the ``--debugger:on`` command line option. This also defines the conditional symbol ``ENDB`` for you. @@ -20,7 +22,7 @@ available for the debugger. If you start your program the debugger will immediately show a prompt on the console. You can now enter a command. The next sections -deal with the possible commands. As usual in Nimrod in all commands +deal with the possible commands. As usual in Nim in all commands underscores and case do not matter. Optional components of a command are listed in brackets ``[...]`` here. @@ -105,7 +107,7 @@ The ``breakpoint`` pragma The ``breakpoint`` pragma is syntactically a statement. It can be used to mark the *following line* as a breakpoint: -.. code-block:: Nimrod +.. code-block:: Nim write("1") {.breakpoint: "before_write_2".} write("2") @@ -125,7 +127,7 @@ The ``watchpoint`` pragma The ``watchpoint`` pragma is syntactically a statement. It can be used to mark a location as a watchpoint: -.. code-block:: Nimrod +.. code-block:: Nim var a: array [0..20, int] {.watchpoint: a[3].} @@ -141,7 +143,7 @@ is turned on, so you don't need to remove it from your source code after debugging. Due to the primitive implementation watchpoints are even slower than -breakpoints: After *every* executed Nimrod code line it is checked whether the +breakpoints: After *every* executed Nim code line it is checked whether the location changed. @@ -159,7 +161,7 @@ Data Display Commands in the current stack frame, use the ``up`` or ``down`` command. Unfortunately, only inspecting variables is possible at the moment. Maybe - a future version will implement a full-blown Nimrod expression evaluator, + a future version will implement a full-blown Nim expression evaluator, but this is not easy to do and would bloat the debugger's code. Since displaying the whole data structures is often not needed and diff --git a/doc/estp.txt b/doc/estp.txt index 704bc33f2..500ee52a5 100644 --- a/doc/estp.txt +++ b/doc/estp.txt @@ -3,10 +3,10 @@ =================================================== :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| -Nimrod comes with a platform independent profiler - +Nim comes with a platform independent profiler - the Embedded Stack Trace Profiler (ESTP). The profiler is *embedded* into your executable. To activate the profiler you need to do: @@ -49,7 +49,7 @@ Example results file The results file lists stack traces ordered by significance. -The following example file has been generated by profiling the Nimrod compiler +The following example file has been generated by profiling the Nim compiler itself: It shows that in total 5.4% of the runtime has been spent in ``crcFromRope`` or its children. @@ -74,7 +74,7 @@ often remains mysterious. CommandCompileToC MainCommand HandleCmdLine - nimrod + nim Entry: 1/3391 Calls: 46/4160 = 1.1% [sum: 130; 130/4160 = 3.1%] updateCrc32 newCrcFromRopeAux @@ -90,7 +90,7 @@ often remains mysterious. CommandCompileToC MainCommand HandleCmdLine - nimrod + nim Entry: 2/3391 Calls: 41/4160 = 0.99% [sum: 171; 171/4160 = 4.1%] updateCrc32 updateCrc32 @@ -107,7 +107,7 @@ often remains mysterious. CommandCompileToC MainCommand HandleCmdLine - nimrod + nim Entry: 3/3391 Calls: 41/4160 = 0.99% [sum: 212; 212/4160 = 5.1%] crcFromFile writeRopeIfNotEqual @@ -121,7 +121,7 @@ often remains mysterious. CommandCompileToC MainCommand HandleCmdLine - nimrod + nim Entry: 4/3391 Calls: 41/4160 = 0.99% [sum: 253; 253/4160 = 6.1%] updateCrc32 crcFromFile @@ -136,7 +136,7 @@ often remains mysterious. CommandCompileToC MainCommand HandleCmdLine - nimrod + nim Entry: 5/3391 Calls: 32/4160 = 0.77% [sum: 285; 285/4160 = 6.9%] pop newCrcFromRopeAux @@ -152,7 +152,7 @@ often remains mysterious. CommandCompileToC MainCommand HandleCmdLine - nimrod + nim Entry: 6/3391 Calls: 17/4160 = 0.41% [sum: 302; 302/4160 = 7.3%] doOperation forAllChildrenAux @@ -171,7 +171,7 @@ often remains mysterious. MainCommand HandleCmdLine ... - nimrod + nim Entry: 7/3391 Calls: 14/4160 = 0.34% [sum: 316; 316/4160 = 7.6%] Contains isAccessible diff --git a/doc/exception_hierarchy_fragment.txt b/doc/exception_hierarchy_fragment.txt index 6ca68921f..f4a419fc4 100644 --- a/doc/exception_hierarchy_fragment.txt +++ b/doc/exception_hierarchy_fragment.txt @@ -1,31 +1,28 @@ -* `E_Base <system.html#E_Base>`_ - * `EAccessViolation <system.html#EAccessViolation>`_ - * `EArithmetic <system.html#EArithmetic>`_ - * `EDivByZero <system.html#EDivByZero>`_ - * `EOverflow <system.html#EOverflow>`_ - * `EAssertionFailed <system.html#EAssertionFailed>`_ - * `EAsynch <system.html#EAsynch>`_ - * `EControlC <system.html#EControlC>`_ - * `EDeadThread <system.html#EDeadThread>`_ - * `EFloatingPoint <system.html#EFloatingPoint>`_ - * `EFloatDivByZero <system.html#EFloatDivByZero>`_ - * `EFloatInexact <system.html#EFloatInexact>`_ - * `EFloatInvalidOp <system.html#EFloatInvalidOp>`_ - * `EFloatOverflow <system.html#EFloatOverflow>`_ - * `EFloatUnderflow <system.html#EFloatUnderflow>`_ - * `EInvalidField <system.html#EInvalidField>`_ - * `EInvalidIndex <system.html#EInvalidIndex>`_ - * `EInvalidObjectAssignment <system.html#EInvalidObjectAssignment>`_ - * `EInvalidObjectConversion <system.html#EInvalidObjectConversion>`_ - * `EInvalidValue <system.html#EInvalidValue>`_ - * `EInvalidKey <system.html#EInvalidKey>`_ - * `ENoExceptionToReraise <system.html#ENoExceptionToReraise>`_ - * `EOutOfRange <system.html#EOutOfRange>`_ - * `ESynch <system.html#ESynch>`_ - * `EOutOfMemory <system.html#EOutOfMemory>`_ - * `EResourceExhausted <system.html#EResourceExhausted>`_ - * `EStackOverflow <system.html#EStackOverflow>`_ - * `ESystem <system.html#ESystem>`_ - * `EIO <system.html#EIO>`_ - * `EOS <system.html#EOS>`_ - * `EInvalidLibrary <system.html#EInvalidLibrary>`_ +* `Exception <system.html#Exception>`_ + * `AccessViolationError <system.html#AccessViolationError>`_ + * `ArithmeticError <system.html#ArithmeticError>`_ + * `DivByZeroError <system.html#DivByZeroError>`_ + * `OverflowError <system.html#OverflowError>`_ + * `AssertionError <system.html#AssertionError>`_ + * `DeadThreadError <system.html#DeadThreadError>`_ + * `FloatingPointError <system.html#FloatingPointError>`_ + * `FloatDivByZeroError <system.html#FloatDivByZeroError>`_ + * `FloatInexactError <system.html#FloatInexactError>`_ + * `FloatInvalidOpError <system.html#FloatInvalidOpError>`_ + * `FloatOverflowError <system.html#FloatOverflowError>`_ + * `FloatUnderflowError <system.html#FloatUnderflowError>`_ + * `FieldError <system.html#InvalidFieldError>`_ + * `IndexError <system.html#InvalidIndexError>`_ + * `ObjectAssignmentError <system.html#ObjectAssignmentError>`_ + * `ObjectConversionError <system.html#ObjectConversionError>`_ + * `ValueError <system.html#ValueError>`_ + * `KeyError <system.html#KeyError>`_ + * `ReraiseError <system.html#ReraiseError>`_ + * `RangeError <system.html#RangeError>`_ + * `OutOfMemoryError <system.html#OutOfMemoryError>`_ + * `ResourceExhaustedError <system.html#ResourceExhaustedError>`_ + * `StackOverflowError <system.html#StackOverflowError>`_ + * `SystemError <system.html#SystemError>`_ + * `IOError <system.html#IOError>`_ + * `OSError <system.html#OSError>`_ + * `LibraryError <system.html#LibraryError>`_ diff --git a/doc/filelist.txt b/doc/filelist.txt index f71547f86..beff8f6c8 100644 --- a/doc/filelist.txt +++ b/doc/filelist.txt @@ -1,10 +1,10 @@ -Short description of Nimrod's modules +Short description of Nim's modules ------------------------------------- ============== ========================================================== Module Description ============== ========================================================== -nimrod main module: parses the command line and calls +nim main module: parses the command line and calls ``main.MainCommand`` main implements the top-level command dispatching nimconf implements the config file reader @@ -12,8 +12,8 @@ syntaxes dispatcher for the different parsers and filters filter_tmpl standard template filter (``#! stdtempl``) lexbase buffer handling of the lexical analyser lexer lexical analyser -parser Nimrod's parser -renderer Nimrod code renderer (AST back to its textual form) +parser Nim's parser +renderer Nim code renderer (AST back to its textual form) options contains global and local compiler options ast type definitions of the abstract syntax tree (AST) and node constructors @@ -37,7 +37,7 @@ pragmas semantic checking of pragmas idents implements a general mapping from identifiers to an internal representation (``PIdent``) that is used so that a simple - id-comparison suffices to say whether two Nimrod identifiers + id-comparison suffices to say whether two Nim identifiers are equivalent ropes implements long strings represented as trees for lazy evaluation; used mainly by the code generators diff --git a/doc/filters.txt b/doc/filters.txt index 961a0ea49..22df63490 100644 --- a/doc/filters.txt +++ b/doc/filters.txt @@ -40,7 +40,7 @@ Filters can be combined with the ``|`` pipe operator:: Available filters ================= -**Hint:** With ``--verbosity:2`` (or higher) Nimrod lists the processed code +**Hint:** With ``--verbosity:2`` (or higher) Nim lists the processed code after each filter application. Replace filter @@ -79,19 +79,19 @@ Parameters and their defaults: StdTmpl filter -------------- -The stdtmpl filter provides a simple templating engine for Nimrod. The +The stdtmpl filter provides a simple templating engine for Nim. The filter uses a line based parser: Lines prefixed with a *meta character* -(default: ``#``) contain Nimrod code, other lines are verbatim. Because +(default: ``#``) contain Nim code, other lines are verbatim. Because indentation-based parsing is not suited for a templating engine, control flow statements need ``end X`` delimiters. Parameters and their defaults: ``metaChar: char = '#'`` - prefix for a line that contains Nimrod code + prefix for a line that contains Nim code ``subsChar: char = '$'`` - prefix for a Nimrod expression within a template line + prefix for a Nim expression within a template line ``conc: string = " & "`` the operation for concatenation @@ -130,7 +130,7 @@ Example:: The filter transforms this into: -.. code-block:: nimrod +.. code-block:: nim proc generateHTMLPage(title, currentTab, content: string, tabs: openArray[string]): string = result = "" @@ -158,7 +158,7 @@ The filter transforms this into: Each line that does not start with the meta character (ignoring leading whitespace) is converted to a string literal that is added to ``result``. -The substitution character introduces a Nimrod expression *e* within the +The substitution character introduces a Nim expression *e* within the string literal. *e* is converted to a string with the *toString* operation which defaults to ``$``. For strong type checking, set ``toString`` to the empty string. *e* must match this PEG pattern:: diff --git a/doc/gc.txt b/doc/gc.txt index 18fb03b6d..fdb1d1b6c 100644 --- a/doc/gc.txt +++ b/doc/gc.txt @@ -1,9 +1,9 @@ ========================== -Nimrod's Garbage Collector +Nim's Garbage Collector ========================== :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| "The road to hell is paved with good intentions." @@ -37,7 +37,7 @@ it is necessary to help this analysis with the ``acyclic`` pragma (see You can also use the ``acyclic`` pragma for data that is cyclic in reality and then break up the cycles explicitly with ``GC_addCycleRoot``. This can be a -very valuable optimization; the Nimrod compiler itself relies on this +very valuable optimization; the Nim compiler itself relies on this optimization trick to improve performance. Note that ``GC_addCycleRoot`` is a quick operation; the root is only registered for the next run of the cycle collector. @@ -49,7 +49,7 @@ Realtime support To enable realtime support, the symbol `useRealtimeGC`:idx: needs to be defined. With this switch the GC supports the following operations: -.. code-block:: nimrod +.. code-block:: nim proc GC_setMaxPause*(MaxPauseInUs: int) proc GC_step*(us: int, strongAdvice = false) @@ -111,7 +111,7 @@ highly specialized environments or for older hardware. Keeping track of memory ----------------------- -If you need to pass around memory allocated by Nimrod to C, you can use the +If you need to pass around memory allocated by Nim to C, you can use the procs ``GC_ref`` and ``GC_unref`` to mark objects as referenced to avoid them being freed by the GC. Other useful procs from `system <system.html>`_ you can use to keep track of memory are: diff --git a/doc/idetools.txt b/doc/idetools.txt index 97e110b1d..5429d0c07 100644 --- a/doc/idetools.txt +++ b/doc/idetools.txt @@ -1,9 +1,9 @@ ================================ - Nimrod IDE Integration Guide + Nim IDE Integration Guide ================================ :Author: Britney Spears -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: @@ -13,17 +13,17 @@ "yes, I'm the creator" -- Araq, 2013-07-26 19:28:32. </p></blockquote> -Nimrod differs from many other compilers in that it is really fast, +Nim differs from many other compilers in that it is really fast, and being so fast makes it suited to provide external queries for text editors about the source code being written. Through the -``idetools`` command of `the compiler <nimrodc.html>`_, any IDE +``idetools`` command of `the compiler <nimc.html>`_, any IDE can query a ``.nim`` source file and obtain useful information like definition of symbols or suggestions for completion. This document will guide you through the available options. If you want to look at practical examples of idetools support you can look at the test files found in the `Test suite`_ or `various editor -integrations <https://github.com/Araq/Nimrod/wiki/Editor-Support>`_ +integrations <https://github.com/Araq/Nim/wiki/Editor-Support>`_ already available. @@ -37,11 +37,11 @@ All of the available idetools commands require you to specify a query location through the ``--track`` or ``--trackDirty`` switches. The general idetools invokations are:: - nimrod idetools --track:FILE,LINE,COL <switches> proj.nim + nim idetools --track:FILE,LINE,COL <switches> proj.nim Or:: - nimrod idetools --trackDirty:DIRTY_FILE,FILE,LINE,COL <switches> proj.nim + nim idetools --trackDirty:DIRTY_FILE,FILE,LINE,COL <switches> proj.nim ``proj.nim`` This is the main *project* filename. Most of the time you will @@ -97,7 +97,7 @@ provide the typical *Jump to definition* where a user puts the cursor on a symbol or uses the mouse to select it and is redirected to the place where the symbol is located. -Since Nimrod is implemented in Nimrod, one of the nice things of +Since Nim is implemented in Nim, one of the nice things of this feature is that any user with an IDE supporting it can quickly jump around the standard library implementation and see exactly what a proc does, learning about the language and seeing real life @@ -118,7 +118,7 @@ includes/imports) and when the user starts typing something a completion box with different options appears. However such features are not context sensitive and work simply on -string matching, which can be problematic in Nimrod especially due +string matching, which can be problematic in Nim especially due to the case insensitiveness of the language (plus underscores as separators!). @@ -179,16 +179,16 @@ in the millisecond range, thus being responsive enough for IDEs. If you want to start the server using stdin/stdout as communication you need to type:: - nimrod serve --server.type:stdin proj.nim + nim serve --server.type:stdin proj.nim If you want to start the server using tcp and a port, you need to type:: - nimrod serve --server.type:tcp --server.port:6000 \ + nim serve --server.type:tcp --server.port:6000 \ --server.address:hostname proj.nim In both cases the server will start up and await further commands. The syntax of the commands you can now send to the server is -practically the same as running the nimrod compiler on the commandline, +practically the same as running the nim compiler on the commandline, you only need to remove the name of the compiler since you are already talking to it. The server will answer with as many lines of text it thinks necessary plus an empty line to indicate the end @@ -242,7 +242,7 @@ skConst | **Fourth column**: the type of the const value. | **Docstring**: always the empty string. -.. code-block:: nimrod +.. code-block:: nim const SOME_SEQUENCE = @[1, 2] --> col 2: $MODULE.SOME_SEQUENCE col 3: seq[int] @@ -256,7 +256,7 @@ skEnumField | **Fourth column**: enum type grouping other enum fields. | **Docstring**: always the empty string. -.. code-block:: nimrod +.. code-block:: nim Open(filename, fmWrite) --> col 2: system.TFileMode.fmWrite col 3: TFileMode @@ -270,7 +270,7 @@ skForVar | **Fourth column**: type of the var. | **Docstring**: always the empty string. -.. code-block:: nimrod +.. code-block:: nim proc looper(filename = "tests.nim") = for letter in filename: echo letter @@ -291,7 +291,7 @@ posterior instances of the iterator. | **Fourth column**: signature of the iterator including return type. | **Docstring**: docstring if available. -.. code-block:: nimrod +.. code-block:: nim let text = "some text" letters = toSeq(runes(text)) @@ -307,7 +307,7 @@ skLabel | **Fourth column**: always the empty string. | **Docstring**: always the empty string. -.. code-block:: nimrod +.. code-block:: nim proc test(text: string) = var found = -1 block loops: @@ -323,7 +323,7 @@ skLet | **Fourth column**: the type of the let variable. | **Docstring**: always the empty string. -.. code-block:: nimrod +.. code-block:: nim let text = "some text" --> col 2: $MODULE.text @@ -343,7 +343,7 @@ posterior instances of the macro. | **Fourth column**: signature of the macro including return type. | **Docstring**: docstring if available. -.. code-block:: nimrod +.. code-block:: nim proc testMacro() = expect(EArithmetic): --> col 2: idetools_api.expect @@ -379,7 +379,7 @@ This may change in the future. | **Fourth column**: signature of the method including return type. | **Docstring**: docstring if available. -.. code-block:: nimrod +.. code-block:: nim method eval(e: PExpr): int = quit "to override!" method eval(e: PLiteral): int = e.x method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b) @@ -396,7 +396,7 @@ skParam | **Fourth column**: the type of the parameter. | **Docstring**: always the empty string. -.. code-block:: nimrod +.. code-block:: nim proc reader(filename = "tests.nim") = let text = readFile(filename) --> col 2: $MODULE.reader.filename @@ -420,7 +420,7 @@ returned by idetools returns also the pragmas for the proc. | **Fourth column**: signature of the proc including return type. | **Docstring**: docstring if available. -.. code-block:: nimrod +.. code-block:: nim Open(filename, fmWrite) --> col 2: system.Open col 3: proc (var TFile, string, TFileMode, int): bool @@ -438,7 +438,7 @@ skResult | **Fourth column**: the type of the result. | **Docstring**: always the empty string. -.. code-block:: nimrod +.. code-block:: nim proc getRandomValue() : int = return 4 --> col 2: $MODULE.getRandomValue.result @@ -458,7 +458,7 @@ posterior instances of the template. | **Fourth column**: signature of the template including return type. | **Docstring**: docstring if available. -.. code-block:: nimrod +.. code-block:: nim let text = "some text" letters = toSeq(runes(text)) @@ -469,7 +469,7 @@ posterior instances of the template. Example: - .. code-block:: nimrod + .. code-block:: nim let numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] odd_numbers = toSeq(filter(numeric) do (x: int) -> bool: @@ -485,7 +485,7 @@ skType | **Fourth column**: the type. | **Docstring**: always the empty string. -.. code-block:: nimrod +.. code-block:: nim proc writeTempFile() = var output: TFile --> col 2: system.TFile @@ -500,7 +500,7 @@ skVar | **Fourth column**: the type of the var. | **Docstring**: always the empty string. -.. code-block:: nimrod +.. code-block:: nim proc writeTempFile() = var output: TFile output.open("/tmp/somefile", fmWrite) @@ -527,8 +527,8 @@ At the moment idetools support is still in development so the test suite is not integrated with the main test suite and you have to run it manually. First you have to compile the tester:: - $ cd my/nimrod/checkout/tests - $ nimrod c testament/caasdriver.nim + $ cd my/nim/checkout/tests + $ nim c testament/caasdriver.nim Running the ``caasdriver`` without parameters will attempt to process all the test cases in all three operation modes. If a test succeeds @@ -540,7 +540,7 @@ parameter ``verbose`` to force all output even on successfull tests. The normal operation mode is called ``ProcRun`` and it involves starting a process for each command or query, similar to running -manually the Nimrod compiler from the commandline. The ``CaasRun`` +manually the Nim compiler from the commandline. The ``CaasRun`` mode starts a server process to answer all queries. The ``SymbolProcRun`` mode is used by compiler developers. This means that running all tests involves processing all ``*.txt`` files three times, which diff --git a/doc/intern.txt b/doc/intern.txt index 1dcf27774..6cd1987aa 100644 --- a/doc/intern.txt +++ b/doc/intern.txt @@ -1,10 +1,10 @@ ========================================= - Internals of the Nimrod Compiler + Internals of the Nim Compiler ========================================= :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: @@ -14,23 +14,23 @@ Directory structure =================== -The Nimrod project's directory structure is: +The Nim project's directory structure is: ============ ============================================== Path Purpose ============ ============================================== ``bin`` generated binary files ``build`` generated C code for the installation -``compiler`` the Nimrod compiler itself; note that this +``compiler`` the Nim compiler itself; note that this code has been translated from a bootstrapping version written in Pascal, so the code is **not** - a poster child of good Nimrod code -``config`` configuration files for Nimrod + a poster child of good Nim code +``config`` configuration files for Nim ``dist`` additional packages for the distribution ``doc`` the documentation; it is a bunch of reStructuredText files -``lib`` the Nimrod library -``web`` website of Nimrod; generated by ``nimweb`` +``lib`` the Nim library +``web`` website of Nim; generated by ``nimweb`` from the ``*.txt`` and ``*.tmpl`` files ============ ============================================== @@ -38,26 +38,26 @@ Path Purpose Bootstrapping the compiler ========================== -As of version 0.8.5 the compiler is maintained in Nimrod. (The first versions +As of version 0.8.5 the compiler is maintained in Nim. (The first versions have been implemented in Object Pascal.) The Python-based build system has -been rewritten in Nimrod too. +been rewritten in Nim too. Compiling the compiler is a simple matter of running:: - nimrod c koch.nim + nim c koch.nim ./koch boot For a release version use:: - nimrod c koch.nim + nim c koch.nim ./koch boot -d:release And for a debug version compatible with GDB:: - nimrod c koch.nim + nim c koch.nim ./koch boot --debuginfo --linedir:on -The ``koch`` program is Nimrod's maintenance script. It is a replacement for +The ``koch`` program is Nim's maintenance script. It is a replacement for make and shell scripting with the advantage that it is much more portable. More information about its options can be found in the `koch <koch.html>`_ documentation. @@ -80,13 +80,13 @@ See also the `API naming design <apis.html>`_ document. Porting to new platforms ======================== -Porting Nimrod to a new architecture is pretty easy, since C is the most -portable programming language (within certain limits) and Nimrod generates +Porting Nim to a new architecture is pretty easy, since C is the most +portable programming language (within certain limits) and Nim generates C code, porting the code generator is not necessary. POSIX-compliant systems on conventional hardware are usually pretty easy to port: Add the platform to ``platform`` (if it is not already listed there), -check that the OS, System modules work and recompile Nimrod. +check that the OS, System modules work and recompile Nim. The only case where things aren't as easy is when the garbage collector needs some assembler tweaking to work. The standard @@ -98,7 +98,7 @@ replace this generic code by some assembler code. Runtime type information ======================== -*Runtime type information* (RTTI) is needed for several aspects of the Nimrod +*Runtime type information* (RTTI) is needed for several aspects of the Nim programming language: Garbage collection @@ -108,7 +108,7 @@ Garbage collection Complex assignments Sequences and strings are implemented as - pointers to resizeable buffers, but Nimrod requires copying for + pointers to resizeable buffers, but Nim requires copying for assignments. Apart from RTTI the compiler could generate copy procedures for any type that needs one. However, this would make the code bigger and the RTTI is likely already there for the GC. @@ -121,12 +121,12 @@ Look at the file ``lib/system/hti.nim`` for more information. The compiler's architecture =========================== -Nimrod uses the classic compiler architecture: A lexer/scanner feds tokens to a +Nim uses the classic compiler architecture: A lexer/scanner feds tokens to a parser. The parser builds a syntax tree that is used by the code generator. This syntax tree is the interface between the parser and the code generator. It is essential to understand most of the compiler's code. -In order to compile Nimrod correctly, type-checking has to be separated from +In order to compile Nim correctly, type-checking has to be separated from parsing. Otherwise generics cannot work. .. include:: filelist.txt @@ -172,7 +172,7 @@ Frontend issues Methods and type converters ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Nimrod contains language features that are *global*. The best example for that +Nim contains language features that are *global*. The best example for that are multi methods: Introducing a new method with the same name and some compatible object parameter means that the method's dispatcher needs to take the new method into account. So the dispatching logic is only completely known @@ -181,12 +181,12 @@ after the whole program has been translated! Other features that are *implicitly* triggered cause problems for modularity too. Type converters fall into this category: -.. code-block:: nimrod +.. code-block:: nim # module A converter toBool(x: int): bool = result = x != 0 -.. code-block:: nimrod +.. code-block:: nim # module B import A @@ -254,7 +254,7 @@ turned on". -Debugging Nimrod's memory management +Debugging Nim's memory management ==================================== The following paragraphs are mostly a reminder for myself. Things to keep @@ -262,7 +262,7 @@ in mind: * Segmentation faults can have multiple reasons: One that is frequently forgotten is that *stack overflow* can trigger one! -* If an assertion in Nimrod's memory manager or GC fails, the stack trace +* If an assertion in Nim's memory manager or GC fails, the stack trace keeps allocating memory! Thus a stack overflow may happen, hiding the real issue. * What seem to be C code generation problems is often a bug resulting from @@ -300,7 +300,7 @@ set of pointers - this is called a ``TCellSet`` in the source code. Inserting, deleting and searching are done in constant time. However, modifying a ``TCellSet`` during traversation leads to undefined behaviour. -.. code-block:: Nimrod +.. code-block:: Nim type TCellSet # hidden @@ -340,11 +340,11 @@ Complete traversal is done in this way:: Further complications --------------------- -In Nimrod the compiler cannot always know if a reference +In Nim the compiler cannot always know if a reference is stored on the stack or not. This is caused by var parameters. Consider this example: -.. code-block:: Nimrod +.. code-block:: Nim proc setRef(r: var ref TNode) = new(r) @@ -380,7 +380,7 @@ Code generation for closures is implemented by `lambda lifting`:idx:. Design ------ -A ``closure`` proc var can call ordinary procs of the default Nimrod calling +A ``closure`` proc var can call ordinary procs of the default Nim calling convention. But not the other way round! A closure is implemented as a ``tuple[prc, env]``. ``env`` can be nil implying a call without a closure. This means that a call through a closure generates an ``if`` but the @@ -393,7 +393,7 @@ Tests with GCC on Amd64 showed that it's really beneficical if the Proper thunk generation is harder because the proc that is to wrap could stem from a complex expression: -.. code-block:: nimrod +.. code-block:: nim receivesClosure(returnsDefaultCC[i]) A thunk would need to call 'returnsDefaultCC[i]' somehow and that would require @@ -405,7 +405,7 @@ to pass a proc pointer around via a generic ``ref`` type. Example code: -.. code-block:: nimrod +.. code-block:: nim proc add(x: int): proc (y: int): int {.closure.} = return proc (y: int): int = return x + y @@ -415,7 +415,7 @@ Example code: This should produce roughly this code: -.. code-block:: nimrod +.. code-block:: nim type PEnv = ref object x: int # data @@ -436,7 +436,7 @@ This should produce roughly this code: Beware of nesting: -.. code-block:: nimrod +.. code-block:: nim proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} = return lamba (y: int): proc (z: int): int {.closure.} = return lambda (z: int): int = @@ -447,7 +447,7 @@ Beware of nesting: This should produce roughly this code: -.. code-block:: nimrod +.. code-block:: nim type PEnvX = ref object x: int # data @@ -492,7 +492,7 @@ environments. This is however not always possible. Accumulator ----------- -.. code-block:: nimrod +.. code-block:: nim proc GetAccumulator(start: int): proc (): int {.closure} = var i = start return lambda: int = diff --git a/doc/koch.txt b/doc/koch.txt index 7be2be6d4..7da137458 100644 --- a/doc/koch.txt +++ b/doc/koch.txt @@ -1,8 +1,8 @@ =============================== - Nimrod maintenance script + Nim maintenance script =============================== -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: @@ -15,10 +15,10 @@ Introduction ============ -The `koch`:idx: program is Nimrod's maintenance script. It is a replacement +The `koch`:idx: program is Nim's maintenance script. It is a replacement for make and shell scripting with the advantage that it is much more portable. The word *koch* means *cook* in German. ``koch`` is used mainly to build the -Nimrod compiler, but it can also be used for other tasks. This document +Nim compiler, but it can also be used for other tasks. This document describes the supported commands and their options. @@ -40,21 +40,21 @@ options: option is not supported on Windows. -d:useGnuReadline Includes the `rdstdin module <rdstdin.html>`_ for `interactive - mode <nimrodc.html#nimrod-interactive-mode>`_ (aka ``nimrod i``). + mode <nimc.html#nim-interactive-mode>`_ (aka ``nim i``). This is not needed on Windows. On other platforms this may incorporate the GNU readline library. -d:nativeStacktrace Use native stack traces (only for Mac OS X or Linux). -d:noCaas - Builds Nimrod without compiler as a service (CAAS) support. CAAS - support is required for functionality like Nimrod's `idetool + Builds Nim without compiler as a service (CAAS) support. CAAS + support is required for functionality like Nim's `idetool <idetools.html>`_ command used to integrate the compiler with - `external IDEs <https://github.com/Araq/Nimrod/wiki/Editor-Support>`_. + `external IDEs <https://github.com/Araq/Nim/wiki/Editor-Support>`_. -d:avoidTimeMachine Only for Mac OS X, activating this switch will force excluding the generated ``nimcache`` directories from Time Machine backups. By default ``nimcache`` directories will be included in backups, - and just for the Nimrod compiler itself it means backing up 20MB + and just for the Nim compiler itself it means backing up 20MB of generated files each time you update the compiler. Using this option will make the compiler invoke the `tmutil <https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man8/tmutil.8.html>`_ @@ -66,18 +66,18 @@ options: $ find . -type d -name nimcache -exec tmutil isexcluded \{\} \; -d:useFFI - Nimrod code can use the `foreign function interface (FFI) + Nim code can use the `foreign function interface (FFI) <manual.html#foreign-function-interface>`_ at runtime, but macros - are limited to pure Nimrod code at compilation time. Enabling - this switch will allow macros to execute non-nimrod code at + are limited to pure Nim code at compilation time. Enabling + this switch will allow macros to execute non-nim code at compilation time (eg. open a file and write to it). --gc:refc|v2|markAndSweep|boehm|none Selects which garbage collection strategy to use for the compiler - and generated code. See the `Nimrod's Garbage Collector <gc.html>`_ + and generated code. See the `Nim's Garbage Collector <gc.html>`_ documentation for more information. -After compilation is finished you will hopefully end up with the nimrod -compiler in the ``bin`` directory. You can add Nimrod's ``bin`` directory to +After compilation is finished you will hopefully end up with the nim +compiler in the ``bin`` directory. You can add Nim's ``bin`` directory to your ``$PATH`` or use the `install command`_ to place it where it will be found. @@ -101,7 +101,7 @@ The `inno`:idx: command builds the `Inno Setup installer for Windows install command --------------- -The `install`:idx: command installs Nimrod to the specified directory, which +The `install`:idx: command installs Nim to the specified directory, which is required as a parameter. For example, on Unix platforms you could run:: $ ./koch install /usr/local/bin @@ -109,8 +109,8 @@ is required as a parameter. For example, on Unix platforms you could run:: temp command ------------ -The temp command builds the Nimrod compiler but with a different final name -(``nimrod_temp``), so it doesn't overwrite your normal compiler. You can use +The temp command builds the Nim compiler but with a different final name +(``nim_temp``), so it doesn't overwrite your normal compiler. You can use this command to test different options, the same you would issue for the `boot command`_. @@ -119,14 +119,14 @@ test command The `test`:idx: command can also be invoked with the alias ``tests``. This command will compile and run ``tests/testament/tester.nim``, which is the main -driver of Nimrod's test suite. You can pass options to the ``test`` command, +driver of Nim's test suite. You can pass options to the ``test`` command, they will be forwarded to the tester. See its source code for available options. update command -------------- -The `update`:idx: command updates nimrod to the latest version from github. +The `update`:idx: command updates nim to the latest version from github. For this command to work you need to have compiled ``koch`` itself with the ``-d:withUpdate`` switch. @@ -136,7 +136,7 @@ web command The `web`:idx: command converts the documentation in the ``doc`` directory from rst to HTML. It also repeats the same operation but places the result in the ``web/upload`` which can be used to update the website at -http://nimrod-lang.org. +http://nim-lang.org. By default the documentation will be built in parallel using the number of available CPU cores. If any documentation build sub commands fail, they will diff --git a/doc/lib.txt b/doc/lib.txt index 26ea1b735..a29e32429 100644 --- a/doc/lib.txt +++ b/doc/lib.txt @@ -1,15 +1,15 @@ -======================= -Nimrod Standard Library -======================= +==================== +Nim Standard Library +==================== :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: "The good thing about reinventing the wheel is that you can get a round one." -Though the Nimrod Standard Library is still evolving, it is already quite +Though the Nim Standard Library is still evolving, it is already quite usable. It is divided into *pure libraries*, *impure libraries* and *wrappers*. Pure libraries do not depend on any external ``*.dll`` or ``lib*.so`` binary @@ -19,7 +19,7 @@ low-level interface to a C library. Read this `document <apis.html>`_ for a quick overview of the API design. The `bottom <#babel>`_ of this page includes a list of 3rd party packages -created by the Nimrod community. These packages are a useful addition to the +created by the Nim community. These packages are a useful addition to the modules in the standard library. @@ -41,27 +41,27 @@ Core of ``system``, but an extra import. * `threads <threads.html>`_ - Nimrod thread support. **Note**: This is part of the system module. Do not + Nim thread support. **Note**: This is part of the system module. Do not import it explicitly. * `channels <channels.html>`_ - Nimrod message passing support for threads. **Note**: This is part of the + Nim message passing support for threads. **Note**: This is part of the system module. Do not import it explicitly. * `locks <locks.html>`_ - Locks and condition variables for Nimrod. + Locks and condition variables for Nim. * `macros <macros.html>`_ - Contains the AST API and documentation of Nimrod for writing macros. + Contains the AST API and documentation of Nim for writing macros. * `typeinfo <typeinfo.html>`_ - Provides (unsafe) access to Nimrod's run time type information. + Provides (unsafe) access to Nim's run time type information. * `typetraits <typetraits.html>`_ This module defines compile-time reflection procs for working with types. * `actors <actors.html>`_ - Actor support for Nimrod; implemented as a layer on top of the threads and + Actor support for Nim; implemented as a layer on top of the threads and channels modules. @@ -71,11 +71,11 @@ Collections and algorithms * `algorithm <algorithm.html>`_ Implements some common generic algorithms like sort or binary search. * `tables <tables.html>`_ - Nimrod hash table support. Contains tables, ordered tables and count tables. + Nim hash table support. Contains tables, ordered tables and count tables. * `sets <sets.html>`_ - Nimrod hash and bit set support. + Nim hash and bit set support. * `lists <lists.html>`_ - Nimrod linked list support. Contains singly and doubly linked lists and + Nim linked list support. Contains singly and doubly linked lists and circular lists ("rings"). * `queues <queues.html>`_ Implementation of a queue. The underlying implementation uses a ``seq``. @@ -153,11 +153,11 @@ Generic Operating System Services * `streams <streams.html>`_ This module provides a stream interface and two implementations thereof: the `PFileStream` and the `PStringStream` which implement the stream - interface for Nimrod file objects (`TFile`) and strings. Other modules + interface for Nim file objects (`TFile`) and strings. Other modules may provide other implementations for this standard stream interface. * `marshal <marshal.html>`_ - Contains procs for serialization and deseralization of arbitrary Nimrod + Contains procs for serialization and deseralization of arbitrary Nim data structures. * `terminal <terminal.html>`_ @@ -273,7 +273,7 @@ Parsers parser. The configuration file's syntax is similar to the Windows ``.ini`` format, but much more powerful, as it is not a line based parser. String literals, raw string literals and triple quote string literals are supported - as in the Nimrod programming language. + as in the Nim programming language. * `parsexml <parsexml.html>`_ The ``parsexml`` module implements a simple high performance XML/HTML parser. @@ -340,7 +340,7 @@ Cryptography and Hashing * `hashes <hashes.html>`_ This module implements efficient computations of hash values for diverse - Nimrod types. + Nim types. * `md5 <md5.html>`_ This module implements the MD5 checksum algorithm. @@ -353,7 +353,7 @@ Multimedia support ------------------ * `colors <colors.html>`_ - This module implements color handling for Nimrod. It is used by + This module implements color handling for Nim. It is used by the ``graphics`` module. @@ -426,12 +426,12 @@ Other ----- * `graphics <graphics.html>`_ - This module implements graphical output for Nimrod; the current + This module implements graphical output for Nim; the current implementation uses SDL but the interface is meant to support multiple backends some day. * `dialogs <dialogs.html>`_ - This module implements portable dialogs for Nimrod; the implementation + This module implements portable dialogs for Nim; the implementation builds on the GTK interface. On Windows, native dialogs are shown if appropriate. @@ -444,7 +444,7 @@ Other * `ssl <ssl.html>`_ This module provides an easy to use sockets-style - Nimrod interface to the OpenSSL library. + Nim interface to the OpenSSL library. * `rdstdin <rdstdin.html>`_ This module contains code for reading from `stdin`:idx:. On UNIX the GNU @@ -532,7 +532,7 @@ Database support * `odbcsql <odbcsql.html>`_ interface to the ODBC driver. * `sphinx <sphinx.html>`_ - Nimrod wrapper for ``sphinx``. + Nim wrapper for ``sphinx``. XML Processing @@ -578,15 +578,15 @@ Scientific computing Babel ==================== -Babel is a package manager for the Nimrod programming language. +Babel is a package manager for the Nim programming language. For instructions on how to install Babel packages see -`its README <https://github.com/nimrod-code/babel#readme>`_. +`its README <https://github.com/nim-code/babel#readme>`_. Official packages ----------------- These packages are officially supported and will therefore be continually -maintained to ensure that they work with the latest versions of the Nimrod +maintained to ensure that they work with the latest versions of the Nim compiler. .. raw:: html @@ -597,9 +597,9 @@ compiler. Unofficial packages ------------------- -These packages have been developed by independent Nimrod developers and as +These packages have been developed by independent Nim developers and as such may not always be up to date with the latest developments in the -Nimrod programming language. +Nim programming language. .. raw:: html @@ -607,4 +607,4 @@ Nimrod programming language. babelpkglist.js or have javascript disabled in your browser.</b></div> <script type="text/javascript" src="babelpkglist.js"></script> - <script type="text/javascript" src="http://build.nimrod-lang.org/packages?callback=gotPackageList"></script> + <script type="text/javascript" src="http://build.nim-lang.org/packages?callback=gotPackageList"></script> diff --git a/doc/manual.txt b/doc/manual.txt index 7b713bf93..5c6f64344 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -1,9 +1,9 @@ -============= -Nimrod Manual -============= +========== +Nim Manual +========== :Authors: Andreas Rumpf, Zahary Karadjov -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: @@ -12,5837 +12,27 @@ Nimrod Manual user to one/some of the other players, but the total amount seems to remain pretty much constant for a given task. -- Ran - - -About this document -=================== - -**Note**: This document is a draft! Several of Nimrod's features need more -precise wording. This manual will evolve into a proper specification some -day. - -This document describes the lexis, the syntax, and the semantics of Nimrod. - -The language constructs are explained using an extended BNF, in -which ``(a)*`` means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and -``(a)?`` means an optional *a*. Parentheses may be used to group elements. - -``&`` is the lookahead operator; ``&a`` means that an ``a`` is expected but -not consumed. It will be consumed in the following rule. - -The ``|``, ``/`` symbols are used to mark alternatives and have the lowest -precedence. ``/`` is the ordered choice that requires the parser to try the -alternatives in the given order. ``/`` is often used to ensure the grammar -is not ambiguous. - -Non-terminals start with a lowercase letter, abstract terminal symbols are in -UPPERCASE. Verbatim terminal symbols (including keywords) are quoted -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 -separated by its second argument; likewise ``^+`` means 1 or more -occurances: ``a ^+ b`` is short for ``a (b a)*`` -and ``a ^* b`` is short for ``(a (b a)*)?``. Example:: - - arrayConstructor = '[' expr ^* ',' ']' - -Other parts of Nimrod - like scoping rules or runtime semantics are only -described in an informal manner for now. - - -Definitions -=========== - -A Nimrod program specifies a computation that acts on a memory consisting of -components called `locations`:idx:. A variable is basically a name for a -location. Each variable and location is of a certain `type`:idx:. The -variable's type is called `static type`:idx:, the location's type is called -`dynamic type`:idx:. If the static type is not the same as the dynamic type, -it is a super-type or subtype of the dynamic type. - -An `identifier`:idx: is a symbol declared as a name for a variable, type, -procedure, etc. The region of the program over which a declaration applies is -called the `scope`:idx: of the declaration. Scopes can be nested. The meaning -of an identifier is determined by the smallest enclosing scope in which the -identifier is declared unless overloading resolution rules suggest otherwise. - -An expression specifies a computation that produces a value or location. -Expressions that produce locations are called `l-values`:idx:. An l-value -can denote either a location or the value the location contains, depending on -the context. Expressions whose values can be determined statically are called -`constant expressions`:idx:; they are never l-values. - -A `static error`:idx: is an error that the implementation detects before -program execution. Unless explicitly classified, an error is a static error. - -A `checked runtime error`:idx: is an error that the implementation detects -and reports at runtime. The method for reporting such errors is via *raising -exceptions* or *dying with a fatal error*. However, the implementation -provides a means to disable these runtime checks. See the section pragmas_ -for details. - -Wether a checked runtime error results in an exception or in a fatal error at -runtime is implementation specific. Thus the following program is always -invalid: - -.. code-block:: nimrod - var a: array[0..1, char] - let i = 5 - try: - a[i] = 'N' - except EInvalidIndex: - echo "invalid index" - -An `unchecked runtime error`:idx: is an error that is not guaranteed to be -detected, and can cause the subsequent behavior of the computation to -be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx: -language features are used. - - -Lexical Analysis -================ - -Encoding --------- - -All Nimrod source files are in the UTF-8 encoding (or its ASCII subset). Other -encodings are not supported. Any of the standard platform line termination -sequences can be used - the Unix form using ASCII LF (linefeed), the Windows -form using the ASCII sequence CR LF (return followed by linefeed), or the old -Macintosh form using the ASCII CR (return) character. All of these forms can be -used equally, regardless of platform. - - -Indentation ------------ - -Nimrod's standard grammar describes an `indentation sensitive`:idx: language. -This means that all the control structures are recognized by indentation. -Indentation consists only of spaces; tabulators are not allowed. - -The indentation handling is implemented as follows: The lexer annotates the -following token with the preceding number of spaces; indentation is not -a separate token. This trick allows parsing of Nimrod with only 1 token of -lookahead. - -The parser uses a stack of indentation levels: the stack consists of integers -counting the spaces. The indentation information is queried at strategic -places in the parser but ignored otherwise: The pseudo terminal ``IND{>}`` -denotes an indentation that consists of more spaces than the entry at the top -of the stack; IND{=} an indentation that has the same number of spaces. ``DED`` -is another pseudo terminal that describes the *action* of popping a value -from the stack, ``IND{>}`` then implies to push onto the stack. - -With this notation we can now easily define the core of the grammar: A block of -statements (simplified example):: - - ifStmt = 'if' expr ':' stmt - (IND{=} 'elif' expr ':' stmt)* - (IND{=} 'else' ':' stmt)? - - simpleStmt = ifStmt / ... - - stmt = IND{>} stmt ^+ IND{=} DED # list of statements - / simpleStmt # or a simple statement - - - -Comments --------- - -Comments start anywhere outside a string or character literal with the -hash character ``#``. -Comments consist of a concatenation of `comment pieces`:idx:. A comment piece -starts with ``#`` and runs until the end of the line. The end of line characters -belong to the piece. If the next line only consists of a comment piece which is -aligned to the preceding one, it does not start a new comment: - -.. code-block:: nimrod - - i = 0 # This is a single comment over multiple lines belonging to the - # assignment statement. The scanner merges these two pieces. - # This is a new comment belonging to the current block, but to no particular - # statement. - i = i + 1 # This a new comment that is NOT - echo(i) # continued here, because this comment refers to the echo statement - - -The alignment requirement does not hold if the preceding comment piece ends in -a backslash (followed by optional whitespace): - -.. code-block:: nimrod - type - TMyObject {.final, pure, acyclic.} = object # comment continues: \ - # we have lots of space here to comment 'TMyObject'. - # This line belongs to the comment as it's properly aligned. - -Comments are tokens; they are only allowed at certain places in the input file -as they belong to the syntax tree! This feature enables perfect source-to-source -transformations (such as pretty-printing) and superior documentation generators. -A nice side-effect is that the human reader of the code always knows exactly -which code snippet the comment refers to. - - -Identifiers & Keywords ----------------------- - -Identifiers in Nimrod can be any string of letters, digits -and underscores, beginning with a letter. Two immediate following -underscores ``__`` are not allowed:: - - letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff' - digit ::= '0'..'9' - IDENTIFIER ::= letter ( ['_'] (letter | digit) )* - -Currently any unicode character with an ordinal value > 127 (non ASCII) is -classified as a ``letter`` and may thus be part of an identifier but later -versions of the language may assign some Unicode characters to belong to the -operator characters instead. - -The following keywords are reserved and cannot be used as identifiers: - -.. code-block:: nimrod - :file: keywords.txt - -Some keywords are unused; they are reserved for future developments of the -language. - -Nimrod is a `style-insensitive`:idx: language. This means that it is not -case-sensitive and even underscores are ignored: -**type** is a reserved word, and so is **TYPE** or **T_Y_P_E**. The idea behind -this is that this allows programmers to use their own preferred spelling style -and libraries written by different programmers cannot use incompatible -conventions. A Nimrod-aware editor or IDE can show the identifiers as -preferred. Another advantage is that it frees the programmer from remembering -the exact spelling of an identifier. - - -String literals ---------------- - -Terminal symbol in the grammar: ``STR_LIT``. - -String literals can be delimited by matching double quotes, and can -contain the following `escape sequences`:idx:\ : - -================== =================================================== - Escape sequence Meaning -================== =================================================== - ``\n`` `newline`:idx: - ``\r``, ``\c`` `carriage return`:idx: - ``\l`` `line feed`:idx: - ``\f`` `form feed`:idx: - ``\t`` `tabulator`:idx: - ``\v`` `vertical tabulator`:idx: - ``\\`` `backslash`:idx: - ``\"`` `quotation mark`:idx: - ``\'`` `apostrophe`:idx: - ``\`` '0'..'9'+ `character with decimal value d`:idx:; - all decimal digits directly - following are used for the character - ``\a`` `alert`:idx: - ``\b`` `backspace`:idx: - ``\e`` `escape`:idx: `[ESC]`:idx: - ``\x`` HH `character with hex value HH`:idx:; - exactly two hex digits are allowed -================== =================================================== - - -Strings in Nimrod may contain any 8-bit value, even embedded zeros. However -some operations may interpret the first binary zero as a terminator. - - -Triple quoted string literals ------------------------------ - -Terminal symbol in the grammar: ``TRIPLESTR_LIT``. - -String literals can also be delimited by three double quotes -``"""`` ... ``"""``. -Literals in this form may run for several lines, may contain ``"`` and do not -interpret any escape sequences. -For convenience, when the opening ``"""`` is followed by a newline (there may -be whitespace between the opening ``"""`` and the newline), -the newline (and the preceding whitespace) is not included in the string. The -ending of the string literal is defined by the pattern ``"""[^"]``, so this: - -.. code-block:: nimrod - """"long string within quotes"""" - -Produces:: - - "long string within quotes" - - -Raw string literals -------------------- - -Terminal symbol in the grammar: ``RSTR_LIT``. - -There are also raw string literals that are preceded with the -letter ``r`` (or ``R``) and are delimited by matching double quotes (just -like ordinary string literals) and do not interpret the escape sequences. -This is especially convenient for regular expressions or Windows paths: - -.. code-block:: nimrod - - var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab - -To produce a single ``"`` within a raw string literal, it has to be doubled: - -.. code-block:: nimrod - - r"a""b" - -Produces:: - - a"b - -``r""""`` is not possible with this notation, because the three leading -quotes introduce a triple quoted string literal. ``r"""`` is the same -as ``"""`` since triple quoted string literals do not interpret escape -sequences either. - - -Generalized raw string literals -------------------------------- - -Terminal symbols in the grammar: ``GENERALIZED_STR_LIT``, -``GENERALIZED_TRIPLESTR_LIT``. - -The construct ``identifier"string literal"`` (without whitespace between the -identifier and the opening quotation mark) is a -generalized raw string literal. It is a shortcut for the construct -``identifier(r"string literal")``, so it denotes a procedure call with a -raw string literal as its only argument. Generalized raw string literals -are especially convenient for embedding mini languages directly into Nimrod -(for example regular expressions). - -The construct ``identifier"""string literal"""`` exists too. It is a shortcut -for ``identifier("""string literal""")``. - - -Character literals ------------------- - -Character literals are enclosed in single quotes ``''`` and can contain the -same escape sequences as strings - with one exception: `newline`:idx: (``\n``) -is not allowed as it may be wider than one character (often it is the pair -CR/LF for example). Here are the valid `escape sequences`:idx: for character -literals: - -================== =================================================== - Escape sequence Meaning -================== =================================================== - ``\r``, ``\c`` `carriage return`:idx: - ``\l`` `line feed`:idx: - ``\f`` `form feed`:idx: - ``\t`` `tabulator`:idx: - ``\v`` `vertical tabulator`:idx: - ``\\`` `backslash`:idx: - ``\"`` `quotation mark`:idx: - ``\'`` `apostrophe`:idx: - ``\`` '0'..'9'+ `character with decimal value d`:idx:; - all decimal digits directly - following are used for the character - ``\a`` `alert`:idx: - ``\b`` `backspace`:idx: - ``\e`` `escape`:idx: `[ESC]`:idx: - ``\x`` HH `character with hex value HH`:idx:; - exactly two hex digits are allowed -================== =================================================== - -A character is not an Unicode character but a single byte. The reason for this -is efficiency: for the overwhelming majority of use-cases, the resulting -programs will still handle UTF-8 properly as UTF-8 was specially designed for -this. Another reason is that Nimrod can thus support ``array[char, int]`` or -``set[char]`` efficiently as many algorithms rely on this feature. The `TRune` -type is used for Unicode characters, it can represent any Unicode character. -``TRune`` is declared in the `unicode module <unicode.html>`_. - - -Numerical constants -------------------- - -Numerical constants are of a single type and have the form:: - - hexdigit = digit | 'A'..'F' | 'a'..'f' - octdigit = '0'..'7' - bindigit = '0'..'1' - HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )* - DEC_LIT = digit ( ['_'] digit )* - OCT_LIT = '0o' octdigit ( ['_'] octdigit )* - BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )* - - INT_LIT = HEX_LIT - | DEC_LIT - | OCT_LIT - | BIN_LIT - - INT8_LIT = INT_LIT ['\''] ('i' | 'I') '8' - INT16_LIT = INT_LIT ['\''] ('i' | 'I') '16' - INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32' - INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64' - - UINT8_LIT = INT_LIT ['\''] ('u' | 'U') - UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8' - UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16' - UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32' - UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64' - - exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )* - FLOAT_LIT = digit (['_'] digit)* (('.' (['_'] digit)* [exponent]) |exponent) - FLOAT32_LIT = HEX_LIT '\'' ('f'|'F') '32' - | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32' - FLOAT64_LIT = HEX_LIT '\'' ('f'|'F') '64' - | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64' - - -As can be seen in the productions, numerical constants can contain underscores -for readability. Integer and floating point literals may be given in decimal (no -prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal -(prefix ``0x``) notation. - -There exists a literal for each numerical type that is -defined. The suffix starting with an apostrophe ('\'') is called a -`type suffix`:idx:. Literals without a type suffix are of the type ``int``, -unless the literal contains a dot or ``E|e`` in which case it is of -type ``float``. For notational convenience the apostrophe of a type suffix -is optional if it is not ambiguous (only hexadecimal floating point literals -with a type suffix can be ambiguous). - - -The type suffixes are: - -================= ========================= - Type Suffix Resulting type of literal -================= ========================= - ``'i8`` int8 - ``'i16`` int16 - ``'i32`` int32 - ``'i64`` int64 - ``'u`` uint - ``'u8`` uint8 - ``'u16`` uint16 - ``'u32`` uint32 - ``'u64`` uint64 - ``'f32`` float32 - ``'f64`` float64 -================= ========================= - -Floating point literals may also be in binary, octal or hexadecimal -notation: -``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64`` -is approximately 1.72826e35 according to the IEEE floating point standard. - - -Operators ---------- - -In Nimrod one can define his own operators. An operator is any -combination of the following characters:: - - = + - * / < > - @ $ ~ & % | - ! ? ^ . : \ - -These keywords are also operators: -``and or not xor shl shr div mod in notin is isnot of``. - -`=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they -are used for other notational purposes. - -``*:`` is as a special case the two tokens `*`:tok: and `:`:tok: -(to support ``var v*: T``). - - -Other tokens ------------- - -The following strings denote other tokens:: - - ` ( ) { } [ ] , ; [. .] {. .} (. .) - - -The `slice`:idx: operator `..`:tok: takes precedence over other tokens that -contain a dot: `{..}`:tok: are the three tokens `{`:tok:, `..`:tok:, `}`:tok: -and not the two tokens `{.`:tok:, `.}`:tok:. - - -Syntax -====== - -This section lists Nimrod's standard syntax. How the parser handles -the indentation is already described in the `Lexical Analysis`_ section. - -Nimrod allows user-definable operators. -Binary operators have 10 different levels of precedence. - -Relevant character ------------------- - -An operator symbol's *relevant character* is its first -character unless the first character is ``\`` and its length is greater than 1 -then it is the second character. - -This rule allows to escape operator symbols with ``\`` and keeps the operator's -precedence and associativity; this is useful for meta programming. - - -Associativity -------------- - -Binary operators whose relevant character is ``^`` are right-associative, all -other binary operators are left-associative. - -Precedence ----------- - -Unary operators always bind stronger than any binary -operator: ``$a + b`` is ``($a) + b`` and not ``$(a + b)``. - -If an unary operator's relevant character is ``@`` it is a `sigil-like`:idx: -operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed -as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``. - - -For binary operators that are not keywords the precedence is determined by the -following rules: - -If the operator ends with ``=`` and its relevant character is none of -``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which -has the lowest precedence. - -Otherwise precedence is determined by the relevant character. - -================ =============================================== ================== =============== -Precedence level Operators Relevant character Terminal symbol -================ =============================================== ================== =============== - 9 (highest) ``$ ^`` OP9 - 8 ``* / div mod shl shr %`` ``* % \ /`` OP8 - 7 ``+ -`` ``+ ~ |`` OP7 - 6 ``&`` ``&`` OP6 - 5 ``..`` ``.`` OP5 - 4 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP4 - 3 ``and`` OP3 - 2 ``or xor`` OP2 - 1 ``@ : ?`` OP1 - 0 (lowest) *assignment operator* (like ``+=``, ``*=``) OP0 -================ =============================================== ================== =============== - - -Strong spaces -------------- - -The number of spaces preceeding 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`` -is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``: - -.. code-block:: nimrod - #! strongSpaces - if foo+4 * 4 == 8 and b&c | 9 ++ - bar: - echo "" - # is parsed as - if ((foo+4)*4 == 8) and (((b&c) | 9) ++ bar): echo "" - - -Furthermore whether an operator is used a prefix operator is affected by the -number of spaces: - -.. code-block:: nimrod - #! strongSpaces - echo $foo - # is parsed as - echo($foo) - -This also affects whether ``[]``, ``{}``, ``()`` are parsed as constructors -or as accessors: - -.. code-block:: nimrod - #! strongSpaces - echo (1,2) - # is parsed as - echo((1,2)) - -Only 0, 1, 2, 4 or 8 spaces are allowed to specify precedence and it is -enforced that infix operators have the same amount of spaces before and after -them. This rules does not apply when a newline follows after the operator, -then only the preceding spaces are considered. - - -Grammar -------- - -The grammar's start symbol is ``module``. - -.. include:: grammar.txt - :literal: - - - -Types -===== - -All expressions have a type which is known at compile time. Nimrod -is statically typed. One can declare new types, which is in essence defining -an identifier that can be used to denote this custom type. - -These are the major type classes: - -* ordinal types (consist of integer, bool, character, enumeration - (and subranges thereof) types) -* floating point types -* string type -* structured types -* reference (pointer) type -* procedural type -* generic type - - -Ordinal types -------------- -Ordinal types have the following characteristics: - -- Ordinal types are countable and ordered. This property allows - the operation of functions as ``Inc``, ``Ord``, ``Dec`` on ordinal types to - be defined. -- Ordinal values have a smallest possible value. Trying to count further - down than the smallest value gives a checked runtime or static error. -- Ordinal values have a largest possible value. Trying to count further - than the largest value gives a checked runtime or static error. - -Integers, bool, characters and enumeration types (and subranges of these -types) belong to ordinal types. For reasons of simplicity of implementation -the types ``uint`` and ``uint64`` are not ordinal types. - - -Pre-defined integer types -------------------------- -These integer types are pre-defined: - -``int`` - the generic signed integer type; its size is platform dependent and has the - same size as a pointer. This type should be used in general. An integer - literal that has no type suffix is of this type. - -intXX - additional signed integer types of XX bits use this naming scheme - (example: int16 is a 16 bit wide integer). - The current implementation supports ``int8``, ``int16``, ``int32``, ``int64``. - Literals of these types have the suffix 'iXX. - -``uint`` - the generic `unsigned integer`:idx: type; its size is platform dependent and - has the same size as a pointer. An integer literal with the type - suffix ``'u`` is of this type. - -uintXX - additional signed integer types of XX bits use this naming scheme - (example: uint16 is a 16 bit wide unsigned integer). - The current implementation supports ``uint8``, ``uint16``, ``uint32``, - ``uint64``. Literals of these types have the suffix 'uXX. - Unsigned operations all wrap around; they cannot lead to over- or - underflow errors. - - -In addition to the usual arithmetic operators for signed and unsigned integers -(``+ - *`` etc.) there are also operators that formally work on *signed* -integers but treat their arguments as *unsigned*: They are mostly provided -for backwards compatibility with older versions of the language that lacked -unsigned integer types. These unsigned operations for signed integers use -the ``%`` suffix as convention: - - -====================== ====================================================== -operation meaning -====================== ====================================================== -``a +% b`` unsigned integer addition -``a -% b`` unsigned integer subtraction -``a *% b`` unsigned integer multiplication -``a /% b`` unsigned integer division -``a %% b`` unsigned integer modulo operation -``a <% b`` treat ``a`` and ``b`` as unsigned and compare -``a <=% b`` treat ``a`` and ``b`` as unsigned and compare -``ze(a)`` extends the bits of ``a`` with zeros until it has the - width of the ``int`` type -``toU8(a)`` treats ``a`` as unsigned and converts it to an - unsigned integer of 8 bits (but still the - ``int8`` type) -``toU16(a)`` treats ``a`` as unsigned and converts it to an - unsigned integer of 16 bits (but still the - ``int16`` type) -``toU32(a)`` treats ``a`` as unsigned and converts it to an - unsigned integer of 32 bits (but still the - ``int32`` type) -====================== ====================================================== - -`Automatic type conversion`:idx: is performed in expressions where different -kinds of integer types are used: the smaller type is converted to the larger. - -A `narrowing type conversion`:idx: converts a larger to a smaller type (for -example ``int32 -> int16``. A `widening type conversion`:idx: converts a -smaller type to a larger type (for example ``int16 -> int32``). In Nimrod only -widening type conversions are *implicit*: - -.. code-block:: nimrod - var myInt16 = 5i16 - var myInt: int - myInt16 + 34 # of type ``int16`` - myInt16 + myInt # of type ``int`` - myInt16 + 2i32 # of type ``int32`` - -However, ``int`` literals are implicitly convertible to a smaller integer type -if the literal's value fits this smaller type and such a conversion is less -expensive than other implicit conversions, so ``myInt16 + 34`` produces -an ``int16`` result. - -For further details, see `Convertible relation`_. - - -Subrange types --------------- -A subrange type is a range of values from an ordinal type (the base -type). To define a subrange type, one must specify it's limiting values: the -lowest and highest value of the type: - -.. code-block:: nimrod - type - TSubrange = range[0..5] - - -``TSubrange`` is a subrange of an integer which can only hold the values 0 -to 5. Assigning any other value to a variable of type ``TSubrange`` is a -checked runtime error (or static error if it can be statically -determined). Assignments from the base type to one of its subrange types -(and vice versa) are allowed. - -A subrange type has the same size as its base type (``int`` in the example). - -Nimrod requires `interval arithmetic`:idx: for subrange types over a set -of built-in operators that involve constants: ``x %% 3`` is of -type ``range[0..2]``. The following built-in operators for integers are -affected by this rule: ``-``, ``+``, ``*``, ``min``, ``max``, ``succ``, -``pred``, ``mod``, ``div``, ``%%``, ``and`` (bitwise ``and``). - -Bitwise ``and`` only produces a ``range`` if one of its operands is a -constant *x* so that (x+1) is a number of two. -(Bitwise ``and`` is then a ``%%`` operation.) - -This means that the following code is accepted: - -.. code-block:: nimrod - case (x and 3) + 7 - of 7: echo "A" - of 8: echo "B" - of 9: echo "C" - of 10: echo "D" - # note: no ``else`` required as (x and 3) + 7 has the type: range[7..10] - - -Pre-defined floating point types --------------------------------- - -The following floating point types are pre-defined: - -``float`` - the generic floating point type; its size is platform dependent - (the compiler chooses the processor's fastest floating point type). - This type should be used in general. - -floatXX - an implementation may define additional floating point types of XX bits using - this naming scheme (example: float64 is a 64 bit wide float). The current - implementation supports ``float32`` and ``float64``. Literals of these types - have the suffix 'fXX. - - -Automatic type conversion in expressions with different kinds -of floating point types is performed: See `Convertible relation`_ for further -details. Arithmetic performed on floating point types follows the IEEE -standard. Integer types are not converted to floating point types automatically -and vice versa. - -The IEEE standard defines five types of floating-point exceptions: - -* Invalid: operations with mathematically invalid operands, - for example 0.0/0.0, sqrt(-1.0), and log(-37.8). -* Division by zero: divisor is zero and dividend is a finite nonzero number, - for example 1.0/0.0. -* Overflow: operation produces a result that exceeds the range of the exponent, - for example MAXDOUBLE+0.0000000000001e308. -* Underflow: operation produces a result that is too small to be represented - as a normal number, for example, MINDOUBLE * MINDOUBLE. -* Inexact: operation produces a result that cannot be represented with infinite - precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input. - -The IEEE exceptions are either ignored at runtime or mapped to the -Nimrod exceptions: `EFloatInvalidOp`:idx:, `EFloatDivByZero`:idx:, -`EFloatOverflow`:idx:, `EFloatUnderflow`:idx:, and `EFloatInexact`:idx:. -These exceptions inherit from the `EFloatingPoint`:idx: base class. - -Nimrod provides the pragmas `NaNChecks`:idx: and `InfChecks`:idx: to control -whether the IEEE exceptions are ignored or trap a Nimrod exception: - -.. code-block:: nimrod - {.NanChecks: on, InfChecks: on.} - var a = 1.0 - var b = 0.0 - echo b / b # raises EFloatInvalidOp - echo a / b # raises EFloatOverflow - -In the current implementation ``EFloatDivByZero`` and ``EFloatInexact`` are -never raised. ``EFloatOverflow`` is raised instead of ``EFloatDivByZero``. -There is also a `floatChecks`:idx: pragma that is a short-cut for the -combination of ``NaNChecks`` and ``InfChecks`` pragmas. ``floatChecks`` are -turned off as default. - -The only operations that are affected by the ``floatChecks`` pragma are -the ``+``, ``-``, ``*``, ``/`` operators for floating point types. - - -Boolean type ------------- -The boolean type is named `bool`:idx: in Nimrod and can be one of the two -pre-defined values ``true`` and ``false``. Conditions in while, -if, elif, when statements need to be of type bool. - -This condition holds:: - - ord(false) == 0 and ord(true) == 1 - -The operators ``not, and, or, xor, <, <=, >, >=, !=, ==`` are defined -for the bool type. The ``and`` and ``or`` operators perform short-cut -evaluation. Example: - -.. code-block:: nimrod - - while p != nil and p.name != "xyz": - # p.name is not evaluated if p == nil - p = p.next - - -The size of the bool type is one byte. - - -Character type --------------- -The character type is named ``char`` in Nimrod. Its size is one byte. -Thus it cannot represent an UTF-8 character, but a part of it. -The reason for this is efficiency: for the overwhelming majority of use-cases, -the resulting programs will still handle UTF-8 properly as UTF-8 was specially -designed for this. -Another reason is that Nimrod can support ``array[char, int]`` or -``set[char]`` efficiently as many algorithms rely on this feature. The -`TRune` type is used for Unicode characters, it can represent any Unicode -character. ``TRune`` is declared in the `unicode module <unicode.html>`_. - - - - -Enumeration types ------------------ -Enumeration types define a new type whose values consist of the ones -specified. The values are ordered. Example: - -.. code-block:: nimrod - - type - TDirection = enum - north, east, south, west - - -Now the following holds:: - - ord(north) == 0 - ord(east) == 1 - ord(south) == 2 - ord(west) == 3 - -Thus, north < east < south < west. The comparison operators can be used -with enumeration types. - -For better interfacing to other programming languages, the fields of enum -types can be assigned an explicit ordinal value. However, the ordinal values -have to be in ascending order. A field whose ordinal value is not -explicitly given is assigned the value of the previous field + 1. - -An explicit ordered enum can have *holes*: - -.. code-block:: nimrod - type - TTokenType = enum - a = 2, b = 4, c = 89 # holes are valid - -However, it is then not an ordinal anymore, so it is not possible to use these -enums as an index type for arrays. The procedures ``inc``, ``dec``, ``succ`` -and ``pred`` are not available for them either. - - -The compiler supports the built-in stringify operator ``$`` for enumerations. -The stringify's result can be controlled by explicitly giving the string -values to use: - -.. code-block:: nimrod - - type - TMyEnum = enum - valueA = (0, "my value A"), - valueB = "value B", - valueC = 2, - valueD = (3, "abc") - -As can be seen from the example, it is possible to both specify a field's -ordinal value and its string value by using a tuple. It is also -possible to only specify one of them. - -An enum can be marked with the ``pure`` pragma so that it's fields are not -added to the current scope, so they always need to be accessed -via ``TMyEnum.value``: - -.. code-block:: nimrod - - type - TMyEnum {.pure.} = enum - valueA, valueB, valueC, valueD - - echo valueA # error: Unknown identifier - echo TMyEnum.valueA # works - - -String type ------------ -All string literals are of the type ``string``. A string in Nimrod is very -similar to a sequence of characters. However, strings in Nimrod are both -zero-terminated and have a length field. One can retrieve the length with the -builtin ``len`` procedure; the length never counts the terminating zero. -The assignment operator for strings always copies the string. -The ``&`` operator concatenates strings. - -Strings are compared by their lexicographical order. All comparison operators -are available. Strings can be indexed like arrays (lower bound is 0). Unlike -arrays, they can be used in case statements: - -.. code-block:: nimrod - - case paramStr(i) - of "-v": incl(options, optVerbose) - of "-h", "-?": incl(options, optHelp) - else: write(stdout, "invalid command line option!\n") - -Per convention, all strings are UTF-8 strings, but this is not enforced. For -example, when reading strings from binary files, they are merely a sequence of -bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the -i-th *unichar*. The iterator ``runes`` from the `unicode module -<unicode.html>`_ can be used for iteration over all Unicode characters. - - -CString type ------------- -The ``cstring`` type represents a pointer to a zero-terminated char array -compatible to the type ``char*`` in Ansi C. Its primary purpose lies in easy -interfacing with C. The index operation ``s[i]`` means the i-th *char* of -``s``; however no bounds checking for ``cstring`` is performed making the -index operation unsafe. - -A Nimrod ``string`` is implicitly convertible -to ``cstring`` for convenience. If a Nimrod string is passed to a C-style -variadic proc, it is implicitly converted to ``cstring`` too: - -.. code-block:: nimrod - proc printf(formatstr: cstring) {.importc: "printf", varargs, - header: "<stdio.h>".} - - printf("This works %s", "as expected") - -Even though the conversion is implicit, it is not *safe*: The garbage collector -does not consider a ``cstring`` to be a root and may collect the underlying -memory. However in practice this almost never happens as the GC considers -stack roots conservatively. One can use the builtin procs ``GC_ref`` and -``GC_unref`` to keep the string data alive for the rare cases where it does -not work. - -A `$` proc is defined for cstrings that returns a string. Thus to get a nimrod -string from a cstring: - -.. code-block:: nimrod - var str: string = "Hello!" - var cstr: cstring = s - var newstr: string = $cstr - - -Structured types ----------------- -A variable of a structured type can hold multiple values at the same -time. Structured types can be nested to unlimited levels. Arrays, sequences, -tuples, objects and sets belong to the structured types. - -Array and sequence types ------------------------- -Arrays are a homogeneous type, meaning that each element in the array -has the same type. Arrays always have a fixed length which is specified at -compile time (except for open arrays). They can be indexed by any ordinal type. -A parameter ``A`` may be an *open array*, in which case it is indexed by -integers from 0 to ``len(A)-1``. An array expression may be constructed by the -array constructor ``[]``. - -Sequences are similar to arrays but of dynamic length which may change -during runtime (like strings). Sequences are implemented as growable arrays, -allocating pieces of memory as items are added. A sequence ``S`` is always -indexed by integers from 0 to ``len(S)-1`` and its bounds are checked. -Sequences can be constructed by the array constructor ``[]`` in conjunction -with the array to sequence operator ``@``. Another way to allocate space for a -sequence is to call the built-in ``newSeq`` procedure. - -A sequence may be passed to a parameter that is of type *open array*. - -Example: - -.. code-block:: nimrod - - type - TIntArray = array[0..5, int] # an array that is indexed with 0..5 - TIntSeq = seq[int] # a sequence of integers - var - x: TIntArray - y: TIntSeq - x = [1, 2, 3, 4, 5, 6] # [] is the array constructor - y = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence - -The lower bound of an array or sequence may be received by the built-in proc -``low()``, the higher bound by ``high()``. The length may be -received by ``len()``. ``low()`` for a sequence or an open array always returns -0, as this is the first valid index. -One can append elements to a sequence with the ``add()`` proc or the ``&`` -operator, and remove (and get) the last element of a sequence with the -``pop()`` proc. - -The notation ``x[i]`` can be used to access the i-th element of ``x``. - -Arrays are always bounds checked (at compile-time or at runtime). These -checks can be disabled via pragmas or invoking the compiler with the -``--boundChecks:off`` command line switch. - - -Open arrays ------------ - -Often fixed size arrays turn out to be too inflexible; procedures should -be able to deal with arrays of different sizes. The `openarray`:idx: type -allows this; it can only be used for parameters. Openarrays are always -indexed with an ``int`` starting at position 0. The ``len``, ``low`` -and ``high`` operations are available for open arrays too. Any array with -a compatible base type can be passed to an openarray parameter, the index -type does not matter. In addition to arrays sequences can also be passed -to an open array parameter. - -The openarray type cannot be nested: multidimensional openarrays are not -supported because this is seldom needed and cannot be done efficiently. - - -Varargs -------- - -A ``varargs`` parameter is an openarray parameter that additionally -allows to pass a variable number of arguments to a procedure. The compiler -converts the list of arguments to an array implicitly: - -.. code-block:: nimrod - proc myWriteln(f: TFile, a: varargs[string]) = - for s in items(a): - write(f, s) - write(f, "\n") - - myWriteln(stdout, "abc", "def", "xyz") - # is transformed to: - myWriteln(stdout, ["abc", "def", "xyz"]) - -This transformation is only done if the varargs parameter is the -last parameter in the procedure header. It is also possible to perform -type conversions in this context: - -.. code-block:: nimrod - proc myWriteln(f: TFile, a: varargs[string, `$`]) = - for s in items(a): - write(f, s) - write(f, "\n") - - myWriteln(stdout, 123, "abc", 4.0) - # is transformed to: - myWriteln(stdout, [$123, $"def", $4.0]) - -In this example ``$`` is applied to any argument that is passed to the -parameter ``a``. (Note that ``$`` applied to strings is a nop.) - - - -Tuples and object types ------------------------ -A variable of a tuple or object type is a heterogeneous storage -container. -A tuple or object defines various named *fields* of a type. A tuple also -defines an *order* of the fields. Tuples are meant for heterogeneous storage -types with no overhead and few abstraction possibilities. The constructor ``()`` -can be used to construct tuples. The order of the fields in the constructor -must match the order of the tuple's definition. Different tuple-types are -*equivalent* if they specify the same fields of the same type in the same -order. The *names* of the fields also have to be identical but this might -change in a future version of the language. - -The assignment operator for tuples copies each component. -The default assignment operator for objects copies each component. Overloading -of the assignment operator for objects is not possible, but this will change -in future versions of the compiler. - -.. code-block:: nimrod - - type - TPerson = tuple[name: string, age: int] # type representing a person: - # a person consists of a name - # and an age - var - person: TPerson - person = (name: "Peter", age: 30) - # the same, but less readable: - person = ("Peter", 30) - -The implementation aligns the fields for best access performance. The alignment -is compatible with the way the C compiler does it. - -For consistency with ``object`` declarations, tuples in a ``type`` section -can also be defined with indentation instead of ``[]``: - -.. code-block:: nimrod - type - TPerson = tuple # type representing a person - name: string # a person consists of a name - age: natural # and an age - -Objects provide many features that tuples do not. Object provide inheritance -and information hiding. Objects have access to their type at runtime, so that -the ``of`` operator can be used to determine the object's type. - -.. code-block:: nimrod - type - TPerson {.inheritable.} = object - name*: string # the * means that `name` is accessible from other modules - age: int # no * means that the field is hidden - - TStudent = object of TPerson # a student is a person - id: int # with an id field - - var - student: TStudent - person: TPerson - assert(student of TStudent) # is true - -Object fields that should be visible from outside the defining module, have to -be marked by ``*``. In contrast to tuples, different object types are -never *equivalent*. Objects that have no ancestor are implicitly ``final`` -and thus have no hidden type field. One can use the ``inheritable`` pragma to -introduce new object roots apart from ``system.TObject``. - - -Object construction -------------------- - -Objects can also be created with an `object construction expression`:idx: that -has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is -an ``object`` type or a ``ref object`` type: - -.. code-block:: nimrod - var student = TStudent(name: "Anton", age: 5, id: 3) - -For a ``ref object`` type ``system.new`` is invoked implicitly. - - -Object variants ---------------- -Often an object hierarchy is overkill in certain situations where simple -variant types are needed. - -An example: - -.. code-block:: nimrod - - # This is an example how an abstract syntax tree could be modelled in Nimrod - type - TNodeKind = enum # the different node types - nkInt, # a leaf with an integer value - nkFloat, # a leaf with a float value - nkString, # a leaf with a string value - nkAdd, # an addition - nkSub, # a subtraction - nkIf # an if statement - PNode = ref TNode - TNode = object - case kind: TNodeKind # the ``kind`` field is the discriminator - of nkInt: intVal: int - of nkFloat: floatVal: float - of nkString: strVal: string - of nkAdd, nkSub: - leftOp, rightOp: PNode - of nkIf: - condition, thenPart, elsePart: PNode - - # create a new case object: - var n = PNode(kind: nkIf, condition: nil) - # accessing n.thenPart is valid because the ``nkIf`` branch is active: - n.thenPart = PNode(kind: nkFloat, floatVal: 2.0) - - # the following statement raises an `EInvalidField` exception, because - # n.kind's value does not fit and the ``nkString`` branch is not active: - n.strVal = "" - - # invalid: would change the active object branch: - n.kind = nkInt - - var x = PNode(kind: nkAdd, leftOp: PNode(kind: nkInt, intVal: 4), - rightOp: PNode(kind: nkInt, intVal: 2)) - # valid: does not change the active object branch: - x.kind = nkSub - -As can been seen from the example, an advantage to an object hierarchy is that -no casting between different object types is needed. Yet, access to invalid -object fields raises an exception. - -The syntax of ``case`` in an object declaration follows closely the syntax of -the ``case`` statement: The branches in a ``case`` section may be indented too. - -In the example the ``kind`` field is called the `discriminator`:idx:\: For -safety its address cannot be taken and assignments to it are restricted: The -new value must not lead to a change of the active object branch. For an object -branch switch ``system.reset`` has to be used. - - -Set type --------- - -.. include:: sets_fragment.txt - -Reference and pointer types ---------------------------- -References (similar to pointers in other programming languages) are a -way to introduce many-to-one relationships. This means different references can -point to and modify the same location in memory (also called `aliasing`:idx:). - -Nimrod distinguishes between `traced`:idx: and `untraced`:idx: references. -Untraced references are also called *pointers*. Traced references point to -objects of a garbage collected heap, untraced references point to -manually allocated objects or to objects somewhere else in memory. Thus -untraced references are *unsafe*. However for certain low-level operations -(accessing the hardware) untraced references are unavoidable. - -Traced references are declared with the **ref** keyword, untraced references -are declared with the **ptr** keyword. - -An empty subscript ``[]`` notation can be used to derefer a reference, -the ``addr`` procedure returns the address of an item. An address is always -an untraced reference. -Thus the usage of ``addr`` is an *unsafe* feature. - -The ``.`` (access a tuple/object field operator) -and ``[]`` (array/string/sequence index operator) operators perform implicit -dereferencing operations for reference types: - -.. code-block:: nimrod - - type - PNode = ref TNode - TNode = object - le, ri: PNode - data: int - - var - n: PNode - new(n) - n.data = 9 - # no need to write n[].data; in fact n[].data is highly discouraged! - -As a syntactical extension ``object`` types can be anonymous if -declared in a type section via the ``ref object`` or ``ptr object`` notations. -This feature is useful if an object should only gain reference semantics: - -.. code-block:: nimrod - - type - Node = ref object - le, ri: Node - data: int - - -To allocate a new traced object, the built-in procedure ``new`` has to be used. -To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and -``realloc`` can be used. The documentation of the system module contains -further information. - -If a reference points to *nothing*, it has the value ``nil``. - -Special care has to be taken if an untraced object contains traced objects like -traced references, strings or sequences: in order to free everything properly, -the built-in procedure ``GCunref`` has to be called before freeing the untraced -memory manually: - -.. code-block:: nimrod - type - TData = tuple[x, y: int, s: string] - - # allocate memory for TData on the heap: - var d = cast[ptr TData](alloc0(sizeof(TData))) - - # create a new string on the garbage collected heap: - d.s = "abc" - - # tell the GC that the string is not needed anymore: - GCunref(d.s) - - # free the memory: - dealloc(d) - -Without the ``GCunref`` call the memory allocated for the ``d.s`` string would -never be freed. The example also demonstrates two important features for low -level programming: the ``sizeof`` proc returns the size of a type or value -in bytes. The ``cast`` operator can circumvent the type system: the compiler -is forced to treat the result of the ``alloc0`` call (which returns an untyped -pointer) as if it would have the type ``ptr TData``. Casting should only be -done if it is unavoidable: it breaks type safety and bugs can lead to -mysterious crashes. - -**Note**: The example only works because the memory is initialized to zero -(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to -``nil`` which the string assignment can handle. One needs to know low level -details like this when mixing garbage collected data with unmanaged memory. - -.. XXX finalizers for traced objects - - -Not nil annotation ------------------- - -All types for that ``nil`` is a valid value can be annotated to -exclude ``nil`` as a valid value with the ``not nil`` annotation: - -.. code-block:: nimrod - type - PObject = ref TObj not nil - TProc = (proc (x, y: int)) not nil - - proc p(x: PObject) = - echo "not nil" - - # compiler catches this: - p(nil) - - # and also this: - var x: PObject - p(x) - -The compiler ensures that every code path initializes variables which contain -not nilable pointers. The details of this analysis are still to be specified -here. - - -Memory regions --------------- - -The types ``ref`` and ``ptr`` can get an optional ``region`` annotation. -A region has to be an object type. - -Regions are very useful to separate user space and kernel memory in the -development of OS kernels: - -.. code-block:: nimrod - type - Kernel = object - Userspace = object - - var a: Kernel ptr Stat - var b: Userspace ptr Stat - - # the following does not compile as the pointer types are incompatible: - a = b - -As the example shows ``ptr`` can also be used as a binary -operator, ``region ptr T`` is a shortcut for ``ptr[region, T]``. - -In order to make generic code easier to write ``ptr T`` is a subtype -of ``ptr[R, T]`` for any ``R``. - -Furthermore the subtype relation of the region object types is lifted to -the pointer types: If ``A <: B`` then ``ptr[A, T] <: ptr[B, T]``. This can be -used to model subregions of memory. As a special typing rule ``ptr[R, T]`` is -not compatible to ``pointer`` to prevent the following from compiling: - -.. code-block:: nimrod - # from system - proc dealloc(p: pointer) - - # wrap some scripting language - type - PythonsHeap = object - PyObjectHeader = object - rc: int - typ: pointer - PyObject = ptr[PythonsHeap, PyObjectHeader] - - proc createPyObject(): PyObject {.importc: "...".} - proc destroyPyObject(x: PyObject) {.importc: "...".} - - var foo = createPyObject() - # type error here, how convenient: - dealloc(foo) - - -Future directions: - -* Memory regions might become available for ``string`` and ``seq`` too. -* Builtin regions like ``private``, ``global`` and ``local`` will - prove very useful for the upcoming OpenCL target. -* Builtin "regions" can model ``lent`` and ``unique`` pointers. - - - -Procedural type ---------------- -A procedural type is internally a pointer to a procedure. ``nil`` is -an allowed value for variables of a procedural type. Nimrod uses procedural -types to achieve `functional`:idx: programming techniques. - -Examples: - -.. code-block:: nimrod - - proc printItem(x: int) = ... - - proc forEach(c: proc (x: int) {.cdecl.}) = - ... - - forEach(printItem) # this will NOT compile because calling conventions differ - - -.. code-block:: nimrod - - type - TOnMouseMove = proc (x, y: int) {.closure.} - - proc onMouseMove(mouseX, mouseY: int) = - # has default calling convention - echo "x: ", mouseX, " y: ", mouseY - - proc setOnMouseMove(mouseMoveEvent: TOnMouseMove) = discard - - # ok, 'onMouseMove' has the default calling convention, which is compatible - # to 'closure': - setOnMouseMove(onMouseMove) - - -A subtle issue with procedural types is that the calling convention of the -procedure influences the type compatibility: procedural types are only -compatible if they have the same calling convention. As a special extension, -a procedure of the calling convention ``nimcall`` can be passed to a parameter -that expects a proc of the calling convention ``closure``. - -Nimrod supports these `calling conventions`:idx:\: - -`nimcall`:idx: - is the default convention used for a Nimrod **proc**. It is the - same as ``fastcall``, but only for C compilers that support ``fastcall``. - -`closure`:idx: - is the default calling convention for a **procedural type** that lacks - any pragma annotations. It indicates that the procedure has a hidden - implicit parameter (an *environment*). Proc vars that have the calling - convention ``closure`` take up two machine words: One for the proc pointer - and another one for the pointer to implicitly passed environment. - -`stdcall`:idx: - This the stdcall convention as specified by Microsoft. The generated C - procedure is declared with the ``__stdcall`` keyword. - -`cdecl`:idx: - The cdecl convention means that a procedure shall use the same convention - as the C compiler. Under windows the generated C procedure is declared with - the ``__cdecl`` keyword. - -`safecall`:idx: - This is the safecall convention as specified by Microsoft. The generated C - procedure is declared with the ``__safecall`` keyword. The word *safe* - refers to the fact that all hardware registers shall be pushed to the - hardware stack. - -`inline`:idx: - The inline convention means the the caller should not call the procedure, - but inline its code directly. Note that Nimrod does not inline, but leaves - this to the C compiler; it generates ``__inline`` procedures. This is - only a hint for the compiler: it may completely ignore it and - it may inline procedures that are not marked as ``inline``. - -`fastcall`:idx: - Fastcall means different things to different C compilers. One gets whatever - the C ``__fastcall`` means. - -`syscall`:idx: - The syscall convention is the same as ``__syscall`` in C. It is used for - interrupts. - -`noconv`:idx: - The generated C code will not have any explicit calling convention and thus - use the C compiler's default calling convention. This is needed because - Nimrod's default calling convention for procedures is ``fastcall`` to - improve speed. - -Most calling conventions exist only for the Windows 32-bit platform. - -Assigning/passing a procedure to a procedural variable is only allowed if one -of the following conditions hold: -1) The procedure that is accessed resides in the current module. -2) The procedure is marked with the ``procvar`` pragma (see `procvar pragma`_). -3) The procedure has a calling convention that differs from ``nimcall``. -4) The procedure is anonymous. - -The rules' purpose is to prevent the case that extending a non-``procvar`` -procedure with default parameters breaks client code. - -The default calling convention is ``nimcall``, unless it is an inner proc (a -proc inside of a proc). For an inner proc an analysis is performed whether it -accesses its environment. If it does so, it has the calling convention -``closure``, otherwise it has the calling convention ``nimcall``. - - -Distinct type -------------- - -A ``distinct`` type is new type derived from a `base type`:idx: that is -incompatible with its base type. In particular, it is an essential property -of a distinct type that it **does not** imply a subtype relation between it -and its base type. Explicit type conversions from a distinct type to its -base type and vice versa are allowed. - - -Modelling currencies -~~~~~~~~~~~~~~~~~~~~ - -A distinct type can be used to model different physical `units`:idx: with a -numerical base type, for example. The following example models currencies. - -Different currencies should not be mixed in monetary calculations. Distinct -types are a perfect tool to model different currencies: - -.. code-block:: nimrod - type - TDollar = distinct int - TEuro = distinct int - - var - d: TDollar - e: TEuro - - echo d + 12 - # Error: cannot add a number with no unit and a ``TDollar`` - -Unfortunately, ``d + 12.TDollar`` is not allowed either, -because ``+`` is defined for ``int`` (among others), not for ``TDollar``. So -a ``+`` for dollars needs to be defined: - -.. code-block:: - proc `+` (x, y: TDollar): TDollar = - result = TDollar(int(x) + int(y)) - -It does not make sense to multiply a dollar with a dollar, but with a -number without unit; and the same holds for division: - -.. code-block:: - proc `*` (x: TDollar, y: int): TDollar = - result = TDollar(int(x) * y) - - proc `*` (x: int, y: TDollar): TDollar = - result = TDollar(x * int(y)) - - proc `div` ... - -This quickly gets tedious. The implementations are trivial and the compiler -should not generate all this code only to optimize it away later - after all -``+`` for dollars should produce the same binary code as ``+`` for ints. -The pragma `borrow`:idx: has been designed to solve this problem; in principle -it generates the above trivial implementations: - -.. code-block:: nimrod - proc `*` (x: TDollar, y: int): TDollar {.borrow.} - proc `*` (x: int, y: TDollar): TDollar {.borrow.} - proc `div` (x: TDollar, y: int): TDollar {.borrow.} - -The ``borrow`` pragma makes the compiler use the same implementation as -the proc that deals with the distinct type's base type, so no code is -generated. - -But it seems all this boilerplate code needs to be repeated for the ``TEuro`` -currency. This can be solved with templates_. - -.. code-block:: nimrod - template additive(typ: typedesc): stmt = - proc `+` *(x, y: typ): typ {.borrow.} - proc `-` *(x, y: typ): typ {.borrow.} - - # unary operators: - proc `+` *(x: typ): typ {.borrow.} - proc `-` *(x: typ): typ {.borrow.} - - template multiplicative(typ, base: typedesc): stmt = - proc `*` *(x: typ, y: base): typ {.borrow.} - proc `*` *(x: base, y: typ): typ {.borrow.} - proc `div` *(x: typ, y: base): typ {.borrow.} - proc `mod` *(x: typ, y: base): typ {.borrow.} - - template comparable(typ: typedesc): stmt = - proc `<` * (x, y: typ): bool {.borrow.} - proc `<=` * (x, y: typ): bool {.borrow.} - proc `==` * (x, y: typ): bool {.borrow.} - - template defineCurrency(typ, base: expr): stmt = - type - typ* = distinct base - additive(typ) - multiplicative(typ, base) - comparable(typ) - - defineCurrency(TDollar, int) - defineCurrency(TEuro, int) - - -The borrow pragma can also be used to annotate the distinct type to allow -certain builtin operations to be lifted: - -.. code-block:: nimrod - type - Foo = object - a, b: int - s: string - - Bar {.borrow: `.`.} = distinct Foo - - var bb: ref Bar - new bb - # field access now valid - bb.a = 90 - bb.s = "abc" - -Currently only the dot accessor can be borrowed in this way. - - -Avoiding SQL injection attacks -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -An SQL statement that is passed from Nimrod to an SQL database might be -modelled as a string. However, using string templates and filling in the -values is vulnerable to the famous `SQL injection attack`:idx:\: - -.. code-block:: nimrod - import strutils - - proc query(db: TDbHandle, statement: string) = ... - - var - username: string - - db.query("SELECT FROM users WHERE name = '$1'" % username) - # Horrible security hole, but the compiler does not mind! - -This can be avoided by distinguishing strings that contain SQL from strings -that don't. Distinct types provide a means to introduce a new string type -``TSQL`` that is incompatible with ``string``: - -.. code-block:: nimrod - type - TSQL = distinct string - - proc query(db: TDbHandle, statement: TSQL) = ... - - var - username: string - - db.query("SELECT FROM users WHERE name = '$1'" % username) - # Error at compile time: `query` expects an SQL string! - - -It is an essential property of abstract types that they **do not** imply a -subtype relation between the abtract type and its base type. Explict type -conversions from ``string`` to ``TSQL`` are allowed: - -.. code-block:: nimrod - import strutils, sequtils - - proc properQuote(s: string): TSQL = - # quotes a string properly for an SQL statement - return TSQL(s) - - proc `%` (frmt: TSQL, values: openarray[string]): TSQL = - # quote each argument: - let v = values.mapIt(TSQL, properQuote(it)) - # we need a temporary type for the type conversion :-( - type TStrSeq = seq[string] - # call strutils.`%`: - result = TSQL(string(frmt) % TStrSeq(v)) - - db.query("SELECT FROM users WHERE name = '$1'".TSQL % [username]) - -Now we have compile-time checking against SQL injection attacks. Since -``"".TSQL`` is transformed to ``TSQL("")`` no new syntax is needed for nice -looking ``TSQL`` string literals. The hypothetical ``TSQL`` type actually -exists in the library as the `TSqlQuery type <db_sqlite.html#TSqlQuery>`_ of -modules like `db_sqlite <db_sqlite.html>`_. - - -Void type ---------- - -The ``void`` type denotes the absense 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: - -.. code-block:: nimrod - proc nothing(x, y: void): void = - echo "ha" - - nothing() # writes "ha" to stdout - -The ``void`` type is particularly useful for generic code: - -.. code-block:: nimrod - proc callProc[T](p: proc (x: T), x: T) = - when T is void: - p() - else: - p(x) - - proc intProc(x: int) = discard - proc emptyProc() = discard - - callProc[int](intProc, 12) - callProc[void](emptyProc) - -However, a ``void`` type cannot be inferred in generic code: - -.. code-block:: nimrod - callProc(emptyProc) - # Error: type mismatch: got (proc ()) - # but expected one of: - # callProc(p: proc (T), x: T) - -The ``void`` type is only valid for parameters and return types; other symbols -cannot have the type ``void``. - - -Type relations -============== - -The following section defines several relations on types that are needed to -describe the type checking done by the compiler. - - -Type equality -------------- -Nimrod uses structural type equivalence for most types. Only for objects, -enumerations and distinct types name equivalence is used. The following -algorithm (in pseudo-code) determines type equality: - -.. code-block:: nimrod - proc typeEqualsAux(a, b: PType, - s: var set[PType * PType]): bool = - if (a,b) in s: return true - incl(s, (a,b)) - if a.kind == b.kind: - case a.kind - of int, intXX, float, floatXX, char, string, cstring, pointer, - bool, nil, void: - # leaf type: kinds identical; nothing more to check - result = true - of ref, ptr, var, set, seq, openarray: - result = typeEqualsAux(a.baseType, b.baseType, s) - of range: - result = typeEqualsAux(a.baseType, b.baseType, s) and - (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB) - of array: - result = typeEqualsAux(a.baseType, b.baseType, s) and - typeEqualsAux(a.indexType, b.indexType, s) - of tuple: - if a.tupleLen == b.tupleLen: - for i in 0..a.tupleLen-1: - if not typeEqualsAux(a[i], b[i], s): return false - result = true - of object, enum, distinct: - result = a == b - of proc: - result = typeEqualsAux(a.parameterTuple, b.parameterTuple, s) and - typeEqualsAux(a.resultType, b.resultType, s) and - a.callingConvention == b.callingConvention - - proc typeEquals(a, b: PType): bool = - var s: set[PType * PType] = {} - result = typeEqualsAux(a, b, s) - -Since types are graphs which can have cycles, the above algorithm needs an -auxiliary set ``s`` to detect this case. - - -Type equality modulo type distinction -------------------------------------- - -The following algorithm (in pseudo-code) determines whether two types -are equal with no respect to ``distinct`` types. For brevity the cycle check -with an auxiliary set ``s`` is omitted: - -.. code-block:: nimrod - proc typeEqualsOrDistinct(a, b: PType): bool = - if a.kind == b.kind: - case a.kind - of int, intXX, float, floatXX, char, string, cstring, pointer, - bool, nil, void: - # leaf type: kinds identical; nothing more to check - result = true - of ref, ptr, var, set, seq, openarray: - result = typeEqualsOrDistinct(a.baseType, b.baseType) - of range: - result = typeEqualsOrDistinct(a.baseType, b.baseType) and - (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB) - of array: - result = typeEqualsOrDistinct(a.baseType, b.baseType) and - typeEqualsOrDistinct(a.indexType, b.indexType) - of tuple: - if a.tupleLen == b.tupleLen: - for i in 0..a.tupleLen-1: - if not typeEqualsOrDistinct(a[i], b[i]): return false - result = true - of distinct: - result = typeEqualsOrDistinct(a.baseType, b.baseType) - of object, enum: - result = a == b - of proc: - result = typeEqualsOrDistinct(a.parameterTuple, b.parameterTuple) and - typeEqualsOrDistinct(a.resultType, b.resultType) and - a.callingConvention == b.callingConvention - elif a.kind == distinct: - result = typeEqualsOrDistinct(a.baseType, b) - elif b.kind == distinct: - result = typeEqualsOrDistinct(a, b.baseType) - - -Subtype relation ----------------- -If object ``a`` inherits from ``b``, ``a`` is a subtype of ``b``. This subtype -relation is extended to the types ``var``, ``ref``, ``ptr``: - -.. code-block:: nimrod - proc isSubtype(a, b: PType): bool = - if a.kind == b.kind: - case a.kind - of object: - var aa = a.baseType - while aa != nil and aa != b: aa = aa.baseType - result = aa == b - of var, ref, ptr: - result = isSubtype(a.baseType, b.baseType) - -.. XXX nil is a special value! - - -Convertible relation --------------------- -A type ``a`` is **implicitly** convertible to type ``b`` iff the following -algorithm returns true: - -.. code-block:: nimrod - # XXX range types? - proc isImplicitlyConvertible(a, b: PType): bool = - case a.kind - of int: result = b in {int8, int16, int32, int64, uint, uint8, uint16, - uint32, uint64, float, float32, float64} - of int8: result = b in {int16, int32, int64, int} - of int16: result = b in {int32, int64, int} - of int32: result = b in {int64, int} - of uint: result = b in {uint32, uint64} - of uint8: result = b in {uint16, uint32, uint64} - of uint16: result = b in {uint32, uint64} - of uint32: result = b in {uint64} - of float: result = b in {float32, float64} - of float32: result = b in {float64, float} - of float64: result = b in {float32, float} - of seq: - result = b == openArray and typeEquals(a.baseType, b.baseType) - of array: - result = b == openArray and typeEquals(a.baseType, b.baseType) - if a.baseType == char and a.indexType.rangeA == 0: - result = b = cstring - of cstring, ptr: - result = b == pointer - of string: - result = b == cstring - -A type ``a`` is **explicitly** convertible to type ``b`` iff the following -algorithm returns true: - -.. code-block:: nimrod - proc isIntegralType(t: PType): bool = - result = isOrdinal(t) or t.kind in {float, float32, float64} - - proc isExplicitlyConvertible(a, b: PType): bool = - result = false - if isImplicitlyConvertible(a, b): return true - if typeEqualsOrDistinct(a, b): return true - if isIntegralType(a) and isIntegralType(b): return true - if isSubtype(a, b) or isSubtype(b, a): return true - -The convertible relation can be relaxed by a user-defined type -`converter`:idx:. - -.. code-block:: nimrod - converter toInt(x: char): int = result = ord(x) - - var - x: int - chr: char = 'a' - - # implicit conversion magic happens here - x = chr - echo x # => 97 - # you can use the explicit form too - x = chr.toInt - echo x # => 97 - -The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and -``typeEqualsOrDistinct(T, type(a))`` holds. - - -Assignment compatibility ------------------------- - -An expression ``b`` can be assigned to an expression ``a`` iff ``a`` is an -`l-value` and ``isImplicitlyConvertible(b.typ, a.typ)`` holds. - - -Overloading resolution ----------------------- - -To be written. - - -Statements and expressions -========================== - -Nimrod uses the common statement/expression paradigm: Statements do not -produce a value in contrast to expressions. However, some expressions are -statements. - -Statements are separated into `simple statements`:idx: and -`complex statements`:idx:. -Simple statements are statements that cannot contain other statements like -assignments, calls or the ``return`` statement; complex statements can -contain other statements. To avoid the `dangling else problem`:idx:, complex -statements always have to be intended. The details can be found in the grammar. - - -Statement list expression -------------------------- - -Statements can also occur in an expression context that looks -like ``(stmt1; stmt2; ...; ex)``. This is called -an statement list expression or ``(;)``. The type -of ``(stmt1; stmt2; ...; ex)`` is the type of ``ex``. All the other statements -must be of type ``void``. (One can use ``discard`` to produce a ``void`` type.) -``(;)`` does not introduce a new scope. - - -Discard statement ------------------ - -Example: - -.. code-block:: nimrod - proc p(x, y: int): int = - result = x + y - - discard p(3, 4) # discard the return value of `p` - -The ``discard`` statement evaluates its expression for side-effects and -throws the expression's resulting value away. - -Ignoring the return value of a procedure without using a discard statement is -a static error. - -The return value can be ignored implicitly if the called proc/iterator has -been declared with the `discardable`:idx: pragma: - -.. code-block:: nimrod - proc p(x, y: int): int {.discardable.} = - result = x + y - - p(3, 4) # now valid - -An empty ``discard`` statement is often used as a null statement: - -.. code-block:: nimrod - proc classify(s: string) = - case s[0] - of SymChars, '_': echo "an identifier" - of '0'..'9': echo "a number" - else: discard - - -Var statement -------------- - -Var statements declare new local and global variables and -initialize them. A comma separated list of variables can be used to specify -variables of the same type: - -.. code-block:: nimrod - - var - a: int = 0 - x, y, z: int - -If an initializer is given the type can be omitted: the variable is then of the -same type as the initializing expression. Variables are always initialized -with a default value if there is no initializing expression. The default -value depends on the type and is always a zero in binary. - -============================ ============================================== -Type default value -============================ ============================================== -any integer type 0 -any float 0.0 -char '\\0' -bool false -ref or pointer type nil -procedural type nil -sequence nil (*not* ``@[]``) -string nil (*not* "") -tuple[x: A, y: B, ...] (default(A), default(B), ...) - (analogous for objects) -array[0..., T] [default(T), ...] -range[T] default(T); this may be out of the valid range -T = enum cast[T](0); this may be an invalid value -============================ ============================================== - - -The implicit initialization can be avoided for optimization reasons with the -`noinit`:idx: pragma: - -.. code-block:: nimrod - var - a {.noInit.}: array [0..1023, char] - -If a proc is annotated with the ``noinit`` pragma this refers to its implicit -``result`` variable: - -.. code-block:: nimrod - proc returnUndefinedValue: int {.noinit.} = discard - - -The implicit initialization can be also prevented by the `requiresInit`:idx: -type pragma. The compiler requires an explicit initialization then. However -it does a `control flow analysis`:idx: to prove the variable has been -initialized and does not rely on syntactic properties: - -.. code-block:: nimrod - type - TMyObject = object {.requiresInit.} - - proc p() = - # the following is valid: - var x: TMyObject - if someCondition(): - x = a() - else: - x = a() - use x - -let statement -------------- - -A ``let`` statement declares new local and global `single assignment`:idx: -variables and binds a value to them. The syntax is the of the ``var`` -statement, except that the keyword ``var`` is replaced by the keyword ``let``. -Let variables are not l-values and can thus not be passed to ``var`` parameters -nor can their address be taken. They cannot be assigned new values. - -For let variables the same pragmas are available as for ordinary variables. - - -Const section -------------- - -`Constants`:idx: are symbols which are bound to a value. The constant's value -cannot change. The compiler must be able to evaluate the expression in a -constant declaration at compile time. - -Nimrod contains a sophisticated compile-time evaluator, so procedures which -have no side-effect can be used in constant expressions too: - -.. code-block:: nimrod - import strutils - const - constEval = contains("abc", 'b') # computed at compile time! - - -The rules for compile-time computability are: - -1. Literals are compile-time computable. -2. Type conversions are compile-time computable. -3. Procedure calls of the form ``p(X)`` are compile-time computable if - ``p`` is a proc without side-effects (see the `noSideEffect pragma`_ - for details) and if ``X`` is a (possibly empty) list of compile-time - computable arguments. - - -Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can -they contain such a type. - - -Static statement/expression ---------------------------- - -A static statement/expression can be used to enforce compile -time evaluation explicitly. Enforced compile time evaluation can even evaluate -code that has side effects: - -.. code-block:: - - static: - echo "echo at compile time" - -It's a static error if the compiler cannot perform the evaluation at compile -time. - -The current implementation poses some restrictions for compile time -evaluation: Code which contains ``cast`` or makes use of the foreign function -interface cannot be evaluated at compile time. Later versions of Nimrod will -support the FFI at compile time. - - -If statement ------------- - -Example: - -.. code-block:: nimrod - - var name = readLine(stdin) - - if name == "Andreas": - echo("What a nice name!") - elif name == "": - echo("Don't you have a name?") - else: - echo("Boring name...") - -The ``if`` statement is a simple way to make a branch in the control flow: -The expression after the keyword ``if`` is evaluated, if it is true -the corresponding statements after the ``:`` are executed. Otherwise -the expression after the ``elif`` is evaluated (if there is an -``elif`` branch), if it is true the corresponding statements after -the ``:`` are executed. This goes on until the last ``elif``. If all -conditions fail, the ``else`` part is executed. If there is no ``else`` -part, execution continues with the statement after the ``if`` statement. - -The scoping for an ``if`` statement is slightly subtle to support an important -use case. A new scope starts for the ``if``/``elif`` condition and ends after -the corresponding *then* block: - -.. code-block:: nimrod - if {| (let m = input =~ re"(\w+)=\w+"; m.isMatch): - echo "key ", m[0], " value ", m[1] |} - elif {| (let m = input =~ re""; m.isMatch): - echo "new m in this scope" |} - else: - # 'm' not declared here - -In the example the scopes have been enclosed in ``{| |}``. - - -Case statement --------------- - -Example: - -.. code-block:: nimrod - - case readline(stdin) - of "delete-everything", "restart-computer": - echo("permission denied") - of "go-for-a-walk": echo("please yourself") - else: echo("unknown command") - - # indentation of the branches is also allowed; and so is an optional colon - # after the selecting expression: - case readline(stdin): - of "delete-everything", "restart-computer": - echo("permission denied") - of "go-for-a-walk": echo("please yourself") - else: echo("unknown command") - - -The ``case`` statement is similar to the if statement, but it represents -a multi-branch selection. The expression after the keyword ``case`` is -evaluated and if its value is in a *slicelist* the corresponding statements -(after the ``of`` keyword) are executed. If the value is not in any -given *slicelist* the ``else`` part is executed. If there is no ``else`` -part and not all possible values that ``expr`` can hold occur in a -``slicelist``, a static error occurs. This holds only for expressions of -ordinal types. "All possible values" of ``expr`` are determined by ``expr``'s -type. - -If the expression is not of an ordinal type, and no ``else`` part is -given, control passes after the ``case`` statement. - -To suppress the static error in the ordinal case an ``else`` part with an -empty ``discard`` statement can be used. - -As a special semantic extension, an expression in an ``of`` branch of a case -statement may evaluate to a set or array constructor; the set or array is then -expanded into a list of its elements: - -.. code-block:: nimrod - const - SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} - - proc classify(s: string) = - case s[0] - of SymChars, '_': echo "an identifier" - of '0'..'9': echo "a number" - else: echo "other" - - # is equivalent to: - proc classify(s: string) = - case s[0] - of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_': echo "an identifier" - of '0'..'9': echo "a number" - else: echo "other" - - -When statement --------------- - -Example: - -.. code-block:: nimrod - - when sizeof(int) == 2: - echo("running on a 16 bit system!") - elif sizeof(int) == 4: - echo("running on a 32 bit system!") - elif sizeof(int) == 8: - echo("running on a 64 bit system!") - else: - echo("cannot happen!") - -The ``when`` statement is almost identical to the ``if`` statement with some -exceptions: - -* Each condition (``expr``) has to be a constant expression (of type ``bool``). -* The statements do not open a new scope. -* The statements that belong to the expression that evaluated to true are - translated by the compiler, the other statements are not checked for - semantics! However, each condition is checked for semantics. - -The ``when`` statement enables conditional compilation techniques. As -a special syntactic extension, the ``when`` construct is also available -within ``object`` definitions. - - -Return statement ----------------- - -Example: - -.. code-block:: nimrod - return 40+2 - -The ``return`` statement ends the execution of the current procedure. -It is only allowed in procedures. If there is an ``expr``, this is syntactic -sugar for: - -.. code-block:: nimrod - result = expr - return result - - -``return`` without an expression is a short notation for ``return result`` if -the proc has a return type. The `result`:idx: variable is always the return -value of the procedure. It is automatically declared by the compiler. As all -variables, ``result`` is initialized to (binary) zero: - -.. code-block:: nimrod - proc returnZero(): int = - # implicitly returns 0 - - -Yield statement ---------------- - -Example: - -.. code-block:: nimrod - yield (1, 2, 3) - -The ``yield`` statement is used instead of the ``return`` statement in -iterators. It is only valid in iterators. Execution is returned to the body -of the for loop that called the iterator. Yield does not end the iteration -process, but execution is passed back to the iterator if the next iteration -starts. See the section about iterators (`Iterators and the for statement`_) -for further information. - - -Block statement ---------------- - -Example: - -.. code-block:: nimrod - var found = false - block myblock: - for i in 0..3: - for j in 0..3: - if a[j][i] == 7: - found = true - break myblock # leave the block, in this case both for-loops - echo(found) - -The block statement is a means to group statements to a (named) ``block``. -Inside the block, the ``break`` statement is allowed to leave the block -immediately. A ``break`` statement can contain a name of a surrounding -block to specify which block is to leave. - - -Break statement ---------------- - -Example: - -.. code-block:: nimrod - break - -The ``break`` statement is used to leave a block immediately. If ``symbol`` -is given, it is the name of the enclosing block that is to leave. If it is -absent, the innermost block is left. - - -While statement ---------------- - -Example: - -.. code-block:: nimrod - echo("Please tell me your password: \n") - var pw = readLine(stdin) - while pw != "12345": - echo("Wrong password! Next try: \n") - pw = readLine(stdin) - - -The ``while`` statement is executed until the ``expr`` evaluates to false. -Endless loops are no error. ``while`` statements open an `implicit block`, -so that they can be left with a ``break`` statement. - - -Continue statement ------------------- - -A ``continue`` statement leads to the immediate next iteration of the -surrounding loop construct. It is only allowed within a loop. A continue -statement is syntactic sugar for a nested block: - -.. code-block:: nimrod - while expr1: - stmt1 - continue - stmt2 - -Is equivalent to: - -.. code-block:: nimrod - while expr1: - block myBlockName: - stmt1 - break myBlockName - stmt2 - - -Assembler statement -------------------- - -The direct embedding of assembler code into Nimrod code is supported -by the unsafe ``asm`` statement. Identifiers in the assembler code that refer to -Nimrod identifiers shall be enclosed in a special character which can be -specified in the statement's pragmas. The default special character is ``'`'``: - -.. code-block:: nimrod - {.push stackTrace:off.} - proc addInt(a, b: int): int = - # a in eax, and b in edx - asm """ - mov eax, `a` - add eax, `b` - jno theEnd - call `raiseOverflow` - theEnd: - """ - {.pop.} - -If the GNU assembler is used, quotes and newlines are inserted automatically: - -.. code-block:: nimrod - proc addInt(a, b: int): int = - asm """ - addl %%ecx, %%eax - jno 1 - call `raiseOverflow` - 1: - :"=a"(`result`) - :"a"(`a`), "c"(`b`) - """ - -Instead of: - -.. code-block:: nimrod - proc addInt(a, b: int): int = - asm """ - "addl %%ecx, %%eax\n" - "jno 1\n" - "call `raiseOverflow`\n" - "1: \n" - :"=a"(`result`) - :"a"(`a`), "c"(`b`) - """ - -Using statement ---------------- - -**Warning**: The ``using`` statement is highly experimental! - -The using statement provides syntactic convenience for procs that -heavily use a single contextual parameter. When applied to a variable or a -constant, it will instruct Nimrod to automatically consider the used symbol as -a hidden leading parameter for any procedure calls, following the using -statement in the current scope. Thus, it behaves much like the hidden `this` -parameter available in some object-oriented programming languages. - -.. code-block:: nimrod - - var s = socket() - using s - - connect(host, port) - send(data) - - while true: - let line = readLine(timeout) - ... - - -When applied to a callable symbol, it brings the designated symbol in the -current scope. Thus, it can be used to disambiguate between imported symbols -from different modules having the same name. - -.. code-block:: nimrod - import windows, sdl - using sdl.SetTimer - -Note that ``using`` only *adds* to the current context, it doesn't remove or -replace, **neither** does it create a new scope. What this means is that if one -applies this to multiple variables the compiler will find conflicts in what -variable to use: - -.. code-block:: nimrod - var a, b = "kill it" - using a - add(" with fire") - using b - add(" with water") - echo a - echo b - -When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could -be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or -is ambiguous)``. To solve this one would need to nest ``using`` with a -``block`` statement so as to control the reach of the ``using`` statement. - -If expression -------------- - -An `if expression` is almost like an if statement, but it is an expression. -Example: - -.. code-block:: nimrod - var y = if x > 8: 9 else: 10 - -An if expression always results in a value, so the ``else`` part is -required. ``Elif`` parts are also allowed. - -When expression ---------------- - -Just like an `if expression`, but corresponding to the when statement. - -Case expression ---------------- - -The `case expression` is again very similar to the case statement: - -.. code-block:: nimrod - var favoriteFood = case animal - of "dog": "bones" - of "cat": "mice" - elif animal.endsWith"whale": "plankton" - else: - echo "I'm not sure what to serve, but everybody loves ice cream" - "ice cream" - -As seen in the above example, the case expression can also introduce side -effects. When multiple statements are given for a branch, Nimrod will use -the last expression as the result value, much like in an `expr` template. - -Table constructor ------------------ - -A table constructor is syntactic sugar for an array constructor: - -.. code-block:: nimrod - {"key1": "value1", "key2", "key3": "value2"} - - # is the same as: - [("key1", "value1"), ("key2", "value2"), ("key3", "value2")] - - -The empty table can be written ``{:}`` (in contrast to the empty set -which is ``{}``) which is thus another way to write as the empty array -constructor ``[]``. This slightly unusal way of supporting tables -has lots of advantages: - -* The order of the (key,value)-pairs is preserved, thus it is easy to - support ordered dicts with for example ``{key: val}.newOrderedTable``. -* A table literal can be put into a ``const`` section and the compiler - can easily put it into the executable's data section just like it can - for arrays and the generated data section requires a minimal amount - of memory. -* Every table implementation is treated equal syntactically. -* Apart from the minimal syntactic sugar the language core does not need to - know about tables. - - -Type conversions ----------------- -Syntactically a `type conversion` is like a procedure call, but a -type name replaces the procedure name. A type conversion is always -safe in the sense that a failure to convert a type to another -results in an exception (if it cannot be determined statically). - - -Type casts ----------- -Example: - -.. code-block:: nimrod - cast[int](x) - -Type casts are a crude mechanism to interpret the bit pattern of -an expression as if it would be of another type. Type casts are -only needed for low-level programming and are inherently unsafe. - - -The addr operator ------------------ -The ``addr`` operator returns the address of an l-value. If the type of the -location is ``T``, the `addr` operator result is of the type ``ptr T``. An -address is always an untraced reference. Taking the address of an object that -resides on the stack is **unsafe**, as the pointer may live longer than the -object on the stack and can thus reference a non-existing object. One can get -the address of variables, but one can't use it on variables declared through -``let`` statements: - -.. code-block:: nimrod - - let t1 = "Hello" - var - t2 = t1 - t3 : pointer = addr(t2) - echo repr(addr(t2)) - # --> ref 0x7fff6b71b670 --> 0x10bb81050"Hello" - echo cast[ptr string](t3)[] - # --> Hello - # The following line doesn't compile: - echo repr(addr(t1)) - # Error: expression has no address - - -Procedures -========== - -What most programming languages call `methods`:idx: or `functions`:idx: are -called `procedures`:idx: in Nimrod (which is the correct terminology). A -procedure declaration defines an identifier and associates it with a block -of code. -A procedure may call itself recursively. A parameter may be given a default -value that is used if the caller does not provide a value for this parameter. - -If the proc declaration has no body, it is a `forward`:idx: declaration. If -the proc returns a value, the procedure body can access an implicitly declared -variable named `result`:idx: that represents the return value. Procs can be -overloaded. The overloading resolution algorithm tries to find the proc that is -the best match for the arguments. Example: - -.. code-block:: nimrod - - proc toLower(c: Char): Char = # toLower for characters - if c in {'A'..'Z'}: - result = chr(ord(c) + (ord('a') - ord('A'))) - else: - result = c - - proc toLower(s: string): string = # toLower for strings - result = newString(len(s)) - for i in 0..len(s) - 1: - result[i] = toLower(s[i]) # calls toLower for characters; no recursion! - -Calling a procedure can be done in many different ways: - -.. code-block:: nimrod - proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ... - - # call with positional arguments # parameter bindings: - callme(0, 1, "abc", '\t', true) # (x=0, y=1, s="abc", c='\t', b=true) - # call with named and positional arguments: - callme(y=1, x=0, "abd", '\t') # (x=0, y=1, s="abd", c='\t', b=false) - # call with named arguments (order is not relevant): - callme(c='\t', y=1, x=0) # (x=0, y=1, s="", c='\t', b=false) - # call as a command statement: no () needed: - callme 0, 1, "abc", '\t' - - -A procedure cannot modify its parameters (unless the parameters have the type -`var`). - -`Operators`:idx: are procedures with a special operator symbol as identifier: - -.. code-block:: nimrod - proc `$` (x: int): string = - # converts an integer to a string; this is a prefix operator. - result = intToStr(x) - -Operators with one parameter are prefix operators, operators with two -parameters are infix operators. (However, the parser distinguishes these from -the operator's position within an expression.) There is no way to declare -postfix operators: all postfix operators are built-in and handled by the -grammar explicitly. - -Any operator can be called like an ordinary proc with the '`opr`' -notation. (Thus an operator can have more than two parameters): - -.. code-block:: nimrod - proc `*+` (a, b, c: int): int = - # Multiply and add - result = a * b + c - - assert `*+`(3, 4, 6) == `*`(a, `+`(b, c)) - - -Method call syntax ------------------- - -For object oriented programming, the syntax ``obj.method(args)`` can be used -instead of ``method(obj, args)``. The parentheses can be omitted if there are no -remaining arguments: ``obj.len`` (instead of ``len(obj)``). - -This method call syntax is not restricted to objects, it can be used -to supply any type of first argument for procedures: - -.. code-block:: nimrod - - echo("abc".len) # is the same as echo(len("abc")) - echo("abc".toUpper()) - echo({'a', 'b', 'c'}.card) - stdout.writeln("Hallo") # the same as writeln(stdout, "Hallo") - -Another way to look at the method call syntax is that it provides the missing -postfix notation. - - -Properties ----------- -Nimrod has no need for *get-properties*: Ordinary get-procedures that are called -with the *method call syntax* achieve the same. But setting a value is -different; for this a special setter syntax is needed: - -.. code-block:: nimrod - - type - TSocket* = object of TObject - FHost: int # cannot be accessed from the outside of the module - # the `F` prefix is a convention to avoid clashes since - # the accessors are named `host` - - proc `host=`*(s: var TSocket, value: int) {.inline.} = - ## setter of hostAddr - s.FHost = value - - proc host*(s: TSocket): int {.inline.} = - ## getter of hostAddr - s.FHost - - var - s: TSocket - s.host = 34 # same as `host=`(s, 34) - - -Command invocation syntax -------------------------- - -Routines can be invoked without the ``()`` if the call is syntatically -a statement. This command invocation syntax also works for -expressions, but then only a single argument may follow. This restriction -means ``echo f 1, f 2`` is parsed as ``echo(f(1), f(2))`` and not as -``echo(f(1, f(2)))``. The method call syntax may be used to provide one -more argument in this case: - -.. code-block:: nimrod - proc optarg(x:int, y:int = 0):int = x + y - proc singlearg(x:int):int = 20*x - - echo optarg 1, " ", singlearg 2 # prints "1 40" - - let fail = optarg 1, optarg 8 # Wrong. Too many arguments for a command call - let x = optarg(1, optarg 8) # traditional procedure call with 2 arguments - let y = 1.optarg optarg 8 # same thing as above, w/o the parenthesis - assert x == y - -The command invocation syntax also can't have complex expressions as arguments. -For example: (`anonymous procs`_), ``if``, ``case`` or ``try``. The (`do -notation`_) is limited, but usable for a single proc (see the example in the -corresponding section). Function calls with no arguments still needs () to -distinguish between a call and the function itself as a first class value. - - -Closures --------- - -Procedures can appear at the top level in a module as well as inside other -scopes, in which case they are called nested procs. A nested proc can access -local variables from its enclosing scope and if it does so it becomes a -closure. Any captured variables are stored in a hidden additional argument -to the closure (its environment) and they are accessed by reference by both -the closure and its enclosing scope (i.e. any modifications made to them are -visible in both places). The closure environment may be allocated on the heap -or on the stack if the compiler determines that this would be safe. - - -Anonymous Procs ---------------- - -Procs can also be treated as expressions, in which case it's allowed to omit -the proc's name. - -.. code-block:: nimrod - var cities = @["Frankfurt", "Tokyo", "New York"] - - cities.sort(proc (x,y: string): int = - cmp(x.len, y.len)) - - -Procs as expressions can appear both as nested procs and inside top level -executable code. - - -Do notation ------------ - -As a special more convenient notation, proc expressions involved in procedure -calls can use the ``do`` keyword: - -.. code-block:: nimrod - sort(cities) do (x,y: string) -> int: - cmp(x.len, y.len) - # Less parenthesis using the method plus command syntax: - cities = cities.map do (x:string) -> string: - "City of " & x - -``do`` is written after the parentheses enclosing the regular proc params. -The proc expression represented by the do block is appended to them. - -More than one ``do`` block can appear in a single call: - -.. code-block:: nimrod - proc performWithUndo(task: proc(), undo: proc()) = ... - - performWithUndo do: - # multiple-line block of code - # to perform the task - do: - # code to undo it - -For compatibility with ``stmt`` templates and macros, the ``do`` keyword can be -omitted if the supplied proc doesn't have any parameters and return value. -The compatibility works in the other direction too as the ``do`` syntax can be -used with macros and templates expecting ``stmt`` blocks. - - -Nonoverloadable builtins ------------------------- - -The following builtin procs cannot be overloaded for reasons of implementation -simplicity (they require specialized semantic checking):: - - defined, definedInScope, compiles, low, high, sizeOf, - is, of, echo, shallowCopy, getAst, spawn - -Thus they act more like keywords than like ordinary identifiers; unlike a -keyword however, a redefinition may `shadow`:idx: the definition in -the ``system`` module. - - -Var parameters --------------- -The type of a parameter may be prefixed with the ``var`` keyword: - -.. code-block:: nimrod - proc divmod(a, b: int; res, remainder: var int) = - res = a div b - remainder = a mod b - - var - x, y: int - - divmod(8, 5, x, y) # modifies x and y - assert x == 1 - assert y == 3 - -In the example, ``res`` and ``remainder`` are `var parameters`. -Var parameters can be modified by the procedure and the changes are -visible to the caller. The argument passed to a var parameter has to be -an l-value. Var parameters are implemented as hidden pointers. The -above example is equivalent to: - -.. code-block:: nimrod - proc divmod(a, b: int; res, remainder: ptr int) = - res[] = a div b - remainder[] = a mod b - - var - x, y: int - divmod(8, 5, addr(x), addr(y)) - assert x == 1 - assert y == 3 - -In the examples, var parameters or pointers are used to provide two -return values. This can be done in a cleaner way by returning a tuple: - -.. code-block:: nimrod - proc divmod(a, b: int): tuple[res, remainder: int] = - (a div b, a mod b) - - var t = divmod(8, 5) - - assert t.res == 1 - assert t.remainder == 3 - -One can use `tuple unpacking`:idx: to access the tuple's fields: - -.. code-block:: nimrod - var (x, y) = divmod(8, 5) # tuple unpacking - assert x == 1 - assert y == 3 - - -Var return type ---------------- - -A proc, converter or iterator may return a ``var`` type which means that the -returned value is an l-value and can be modified by the caller: - -.. code-block:: nimrod - var g = 0 - - proc WriteAccessToG(): var int = - result = g - - WriteAccessToG() = 6 - assert g == 6 - -It is a compile time error if the implicitly introduced pointer could be -used to access a location beyond its lifetime: - -.. code-block:: nimrod - proc WriteAccessToG(): var int = - var g = 0 - result = g # Error! - -For iterators, a component of a tuple return type can have a ``var`` type too: - -.. code-block:: nimrod - iterator mpairs(a: var seq[string]): tuple[key: int, val: var string] = - for i in 0..a.high: - yield (i, a[i]) - -In the standard library every name of a routine that returns a ``var`` type -starts with the prefix ``m`` per convention. - - -Overloading of the subscript operator -------------------------------------- - -The ``[]`` subscript operator for arrays/openarrays/sequences can be overloaded. - - -Multi-methods -============= - -Procedures always use static dispatch. Multi-methods use dynamic -dispatch. - -.. code-block:: nimrod - type - TExpr = object ## abstract base class for an expression - TLiteral = object of TExpr - x: int - TPlusExpr = object of TExpr - a, b: ref TExpr - - method eval(e: ref TExpr): int = - # override this base method - quit "to override!" - - method eval(e: ref TLiteral): int = return e.x - - method eval(e: ref TPlusExpr): int = - # watch out: relies on dynamic binding - result = eval(e.a) + eval(e.b) - - proc newLit(x: int): ref TLiteral = - new(result) - result.x = x - - proc newPlus(a, b: ref TExpr): ref TPlusExpr = - new(result) - result.a = a - result.b = b - - echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) - -In the example the constructors ``newLit`` and ``newPlus`` are procs -because they should use static binding, but ``eval`` is a method because it -requires dynamic binding. - -In a multi-method all parameters that have an object type are used for the -dispatching: - -.. code-block:: nimrod - type - TThing = object - TUnit = object of TThing - x: int - - method collide(a, b: TThing) {.inline.} = - quit "to override!" - - method collide(a: TThing, b: TUnit) {.inline.} = - echo "1" - - method collide(a: TUnit, b: TThing) {.inline.} = - echo "2" - - var - a, b: TUnit - collide(a, b) # output: 2 - - -Invocation of a multi-method cannot be ambiguous: collide 2 is preferred over -collide 1 because the resolution works from left to right. -In the example ``TUnit, TThing`` is preferred over ``TThing, TUnit``. - -**Performance note**: Nimrod 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. - - -Iterators and the for statement -=============================== - -The `for`:idx: statement is an abstract mechanism to iterate over the elements -of a container. It relies on an `iterator`:idx: to do so. Like ``while`` -statements, ``for`` statements open an `implicit block`:idx:, so that they -can be left with a ``break`` statement. - -The ``for`` loop declares iteration variables - their scope reaches until the -end of the loop body. The iteration variables' types are inferred by the -return type of the iterator. - -An iterator is similar to a procedure, except that it can be called in the -context of a ``for`` loop. Iterators provide a way to specify the iteration over -an abstract type. A key role in the execution of a ``for`` loop plays the -``yield`` statement in the called iterator. Whenever a ``yield`` statement is -reached the data is bound to the ``for`` loop variables and control continues -in the body of the ``for`` loop. The iterator's local variables and execution -state are automatically saved between calls. Example: - -.. code-block:: nimrod - # this definition exists in the system module - iterator items*(a: string): char {.inline.} = - var i = 0 - while i < len(a): - yield a[i] - inc(i) - - for ch in items("hello world"): # `ch` is an iteration variable - echo(ch) - -The compiler generates code as if the programmer would have written this: - -.. code-block:: nimrod - var i = 0 - while i < len(a): - var ch = a[i] - echo(ch) - inc(i) - -If the iterator yields a tuple, there can be as many iteration variables -as there are components in the tuple. The i'th iteration variable's type is -the type of the i'th component. In other words, implicit tuple unpacking in a -for loop context is supported. - -Implict items/pairs invocations -------------------------------- - -If the for loop expression ``e`` does not denote an iterator and the for loop -has exactly 1 variable, the for loop expression is rewritten to ``items(e)``; -ie. an ``items`` iterator is implicitly invoked: - -.. code-block:: nimrod - for x in [1,2,3]: echo x - -If the for loop has exactly 2 variables, a ``pairs`` iterator is implicitly -invoked. - -Symbol lookup of the identifiers ``items``/``pairs`` is performed after -the rewriting step, so that all overloadings of ``items``/``pairs`` are taken -into account. - - -First class iterators ---------------------- - -There are 2 kinds of iterators in Nimrod: *inline* and *closure* iterators. -An `inline iterator`:idx: is an iterator that's always inlined by the compiler -leading to zero overhead for the abstraction, but may result in a heavy -increase in code size. Inline iterators are second class citizens; -They can be passed as parameters only to other inlining code facilities like -templates, macros and other inline iterators. - -In contrast to that, a `closure iterator`:idx: can be passed around more freely: - -.. code-block:: nimrod - iterator count0(): int {.closure.} = - yield 0 - - iterator count2(): int {.closure.} = - var x = 1 - yield x - inc x - yield x - - proc invoke(iter: iterator(): int {.closure.}) = - for x in iter(): echo x - - invoke(count0) - invoke(count2) - -Closure iterators have other restrictions than inline iterators: - -1. ``yield`` in a closure iterator can not occur in a ``try`` statement. -2. For now, a closure iterator cannot be evaluated at compile time. -3. ``return`` is allowed in a closure iterator (but rarely useful). -4. Both inline and closure iterators cannot be recursive. - -Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly -default to being inline, but that this may change in future versions of the -implementation. - -The ``iterator`` type is always of the calling convention ``closure`` -implicitly; the following example shows how to use iterators to implement -a `collaborative tasking`:idx: system: - -.. code-block:: nimrod - # simple tasking: - type - TTask = iterator (ticker: int) - - iterator a1(ticker: int) {.closure.} = - echo "a1: A" - yield - echo "a1: B" - yield - echo "a1: C" - yield - echo "a1: D" - - iterator a2(ticker: int) {.closure.} = - echo "a2: A" - yield - echo "a2: B" - yield - echo "a2: C" - - proc runTasks(t: varargs[TTask]) = - var ticker = 0 - while true: - let x = t[ticker mod t.len] - if finished(x): break - x(ticker) - inc ticker - - runTasks(a1, a2) - -The builtin ``system.finished`` can be used to determine if an iterator has -finished its operation; no exception is raised on an attempt to invoke an -iterator that has already finished its work. - -Closure iterators are *resumable functions* and so one has to provide the -arguments to every call. To get around this limitation one can capture -parameters of an outer factory proc: - -.. code-block:: nimrod - proc mycount(a, b: int): iterator (): int = - result = iterator (): int = - var x = a - while x <= b: - yield x - inc x - - let foo = mycount(1, 4) - - for f in foo(): - echo f - -Implicit return type --------------------- - -Since inline interators must always produce values that will be consumed in -a for loop, the compiler will implicity use the ``auto`` return type if no -type is given by the user. In contrast, since closure iterators can be used -as a collaborative tasking system, ``void`` is a valid return type for them. - - -Type sections -============= - -Example: - -.. code-block:: nimrod - type # example demonstrating mutually recursive types - PNode = ref TNode # a traced pointer to a TNode - TNode = object - le, ri: PNode # left and right subtrees - sym: ref TSym # leaves contain a reference to a TSym - - TSym = object # a symbol - name: string # the symbol's name - line: int # the line the symbol was declared in - code: PNode # the symbol's abstract syntax tree - -A type section begins with the ``type`` keyword. It contains multiple -type definitions. A type definition binds a type to a name. Type definitions -can be recursive or even mutually recursive. Mutually recursive types are only -possible within a single ``type`` section. Nominal types like ``objects`` -or ``enums`` can only be defined in a ``type`` section. - - -Exception handling -================== - -Try statement -------------- - -Example: - -.. code-block:: nimrod - # read the first two lines of a text file that should contain numbers - # and tries to add them - var - f: TFile - if open(f, "numbers.txt"): - try: - var a = readLine(f) - var b = readLine(f) - echo("sum: " & $(parseInt(a) + parseInt(b))) - except EOverflow: - echo("overflow!") - except EInvalidValue: - echo("could not convert string to integer") - except EIO: - echo("IO error!") - except: - echo("Unknown exception!") - finally: - close(f) - - -The statements after the ``try`` are executed in sequential order unless -an exception ``e`` is raised. If the exception type of ``e`` matches any -listed in an ``except`` clause the corresponding statements are executed. -The statements following the ``except`` clauses are called -`exception handlers`:idx:. - -The empty `except`:idx: clause is executed if there is an exception that is -not listed otherwise. It is similar to an ``else`` clause in ``if`` statements. - -If there is a `finally`:idx: clause, it is always executed after the -exception handlers. - -The exception is *consumed* in an exception handler. However, an -exception handler may raise another exception. If the exception is not -handled, it is propagated through the call stack. This means that often -the rest of the procedure - that is not within a ``finally`` clause - -is not executed (if an exception occurs). - - -Except and finally statements ------------------------------ - -``except`` and ``finally`` can also be used as a stand-alone statements. -Any statements following them in the current block will be considered to be -in an implicit try block: - -.. code-block:: nimrod - var f = open("numbers.txt") - finally: close(f) - ... - -The ``except`` statement has a limitation in this form: one can't specify the -type of the exception, one has to catch everything. Also, if one wants to use -both ``finally`` and ``except`` one needs to reverse the usual sequence of the -statements. Example: - -.. code-block:: nimrod - proc test() = - raise newException(E_base, "Hey ho") - - proc tester() = - finally: echo "3. Finally block" - except: echo "2. Except block" - echo "1. Pre exception" - test() - echo "4. Post exception" - # --> 1, 2, 3 is printed, 4 is never reached - - -Raise statement ---------------- - -Example: - -.. code-block:: nimrod - raise newEOS("operating system failed") - -Apart from built-in operations like array indexing, memory allocation, etc. -the ``raise`` statement is the only way to raise an exception. - -.. XXX document this better! - -If no exception name is given, the current exception is `re-raised`:idx:. The -`ENoExceptionToReraise`:idx: exception is raised if there is no exception to -re-raise. It follows that the ``raise`` statement *always* raises an -exception (unless a raise hook has been provided). - - -OnRaise builtin ---------------- - -`system.onRaise() <system.html#onRaise>`_ can be used to override the -behaviour of ``raise`` for a single ``try`` statement. ``onRaise`` has to be -called within the ``try`` statement that should be affected. - -This allows for a Lisp-like `condition system`:idx:\: - -.. code-block:: nimrod - var myFile = open("broken.txt", fmWrite) - try: - onRaise do (e: ref E_Base)-> bool: - if e of EIO: - stdout.writeln "ok, writing to stdout instead" - else: - # do raise other exceptions: - result = true - myFile.writeln "writing to broken file" - finally: - myFile.close() - -``OnRaise`` can only *filter* raised exceptions, it cannot transform one -exception into another. (Nor should ``onRaise`` raise an exception though -this is currently not enforced.) This restriction keeps the exception tracking -analysis sound. - - -Effect system -============= - -Exception tracking ------------------- - -Nimrod supports exception tracking. The `raises`:idx: pragma can be used -to explicitly define which exceptions a proc/iterator/method/converter is -allowed to raise. The compiler verifies this: - -.. code-block:: nimrod - proc p(what: bool) {.raises: [EIO, EOS].} = - if what: raise newException(EIO, "IO") - else: raise newException(EOS, "OS") - -An empty ``raises`` list (``raises: []``) means that no exception may be raised: - -.. code-block:: nimrod - proc p(): bool {.raises: [].} = - try: - unsafeCall() - result = true - except: - result = false - - -A ``raises`` list can also be attached to a proc type. This affects type -compatibility: - -.. code-block:: nimrod - type - TCallback = proc (s: string) {.raises: [EIO].} - var - c: TCallback - - proc p(x: string) = - raise newException(EOS, "OS") - - c = p # type error - - -For a routine ``p`` the compiler uses inference rules to determine the set of -possibly raised exceptions; the algorithm operates on ``p``'s call graph: - -1. Every indirect call via some proc type ``T`` is assumed to - raise ``system.E_Base`` (the base type of the exception hierarchy) and - thus any exception unless ``T`` has an explicit ``raises`` list. - However if the call is of the form ``f(...)`` where ``f`` is a parameter - of the currently analysed routine it is ignored. The call is optimistically - assumed to have no effect. Rule 2 compensates for this case. -2. Every expression of some proc type wihtin a call that is not a call - itself (and not nil) is assumed to be called indirectly somehow and thus - its raises list is added to ``p``'s raises list. -3. Every call to a proc ``q`` which has an unknown body (due to a forward - declaration or an ``importc`` pragma) is assumed to - raise ``system.E_Base`` unless ``q`` has an explicit ``raises`` list. -4. Every call to a method ``m`` is assumed to - raise ``system.E_Base`` unless ``m`` has an explicit ``raises`` list. -5. For every other call the analysis can determine an exact ``raises`` list. -6. For determining a ``raises`` list, the ``raise`` and ``try`` statements - of ``p`` are taken into consideration. - -Rules 1-2 ensure the following works: - -.. code-block:: nimrod - proc noRaise(x: proc()) {.raises: [].} = - # unknown call that might raise anything, but valid: - x() - - proc doRaise() {.raises: [EIO].} = - raise newException(EIO, "IO") - - proc use() {.raises: [].} = - # doesn't compile! Can raise EIO! - noRaise(doRaise) - -So in many cases a callback does not cause the compiler to be overly -conservative in its effect analysis. - - -Tag tracking ------------- - -The exception tracking is part of Nimrod's `effect system`:idx:. Raising an -exception is an *effect*. Other effects can also be defined. A user defined -effect is a means to *tag* a routine and to perform checks against this tag: - -.. code-block:: nimrod - type IO = object ## input/output effect - proc readLine(): string {.tags: [IO].} - - proc no_IO_please() {.tags: [].} = - # the compiler prevents this: - let x = readLine() - -A tag has to be a type name. A ``tags`` list - like a ``raises`` list - can -also be attached to a proc type. This affects type compatibility. - -The inference for tag tracking is analogous to the inference for -exception tracking. - - -Read/Write tracking -------------------- - -**Note**: Read/write tracking is not yet implemented! - -The inference for read/write tracking is analogous to the inference for -exception tracking. - - -Effects pragma --------------- - -The ``effects`` pragma has been designed to assist the programmer with the -effects analysis. It is a statement that makes the compiler output all inferred -effects up to the ``effects``'s position: - -.. code-block:: nimrod - proc p(what: bool) = - if what: - raise newException(EIO, "IO") - {.effects.} - else: - raise newException(EOS, "OS") - -The compiler produces a hint message that ``EIO`` can be raised. ``EOS`` is not -listed as it cannot be raised in the branch the ``effects`` pragma appears in. - - -Generics -======== - -Example: - -.. code-block:: nimrod - type - TBinaryTree[T] = object # TBinaryTree is a generic type with - # with generic param ``T`` - le, ri: ref TBinaryTree[T] # left and right subtrees; may be nil - data: T # the data stored in a node - PBinaryTree[T] = ref TBinaryTree[T] # a shorthand for notational convenience - - proc newNode[T](data: T): PBinaryTree[T] = # constructor for a node - new(result) - result.data = data - - proc add[T](root: var PBinaryTree[T], n: PBinaryTree[T]) = - if root == nil: - root = n - else: - var it = root - while it != nil: - var c = cmp(it.data, n.data) # compare the data items; uses - # the generic ``cmp`` proc that works for - # any type that has a ``==`` and ``<`` - # operator - if c < 0: - if it.le == nil: - it.le = n - return - it = it.le - else: - if it.ri == nil: - it.ri = n - return - it = it.ri - - iterator inorder[T](root: PBinaryTree[T]): T = - # inorder traversal of a binary tree - # recursive iterators are not yet implemented, so this does not work in - # the current compiler! - if root.le != nil: yield inorder(root.le) - yield root.data - if root.ri != nil: yield inorder(root.ri) - - var - root: PBinaryTree[string] # instantiate a PBinaryTree with the type string - add(root, newNode("hallo")) # instantiates generic procs ``newNode`` and - add(root, newNode("world")) # ``add`` - for str in inorder(root): - writeln(stdout, str) - -Generics are Nimrod's means to parametrize procs, iterators or types with -`type parameters`:idx:. Depending on context, the brackets are used either to -introduce type parameters or to instantiate a generic proc, iterator or type. - - -Is operator ------------ - -The ``is`` operator checks for type equivalence at compile time. It is -therefore very useful for type specialization within generic code: - -.. code-block:: nimrod - type - TTable[TKey, TValue] = object - keys: seq[TKey] - values: seq[TValue] - when not (TKey is string): # nil value for strings used for optimization - deletedKeys: seq[bool] - - -Type operator -------------- - -The ``type`` (in many other languages called `typeof`:idx:) operator can -be used to get the type of an expression: - -.. code-block:: nimrod - var x = 0 - var y: type(x) # y has type int - -If ``type`` is used to determine the result type of a proc/iterator/converter -call ``c(X)`` (where ``X`` stands for a possibly empty list of arguments), the -interpretation where ``c`` is an iterator is preferred over the -other interpretations: - -.. code-block:: nimrod - import strutils - - # strutils contains both a ``split`` proc and iterator, but since an - # an iterator is the preferred interpretation, `y` has the type ``string``: - var y: type("a b c".split) - - -Type Classes ------------- - -A type class is a special pseudo-type that can be used to match against -types in the context of overload resolution or the ``is`` operator. -Nimrod supports the following built-in type classes: - -================== =================================================== -type class matches -================== =================================================== -``object`` any object type -``tuple`` any tuple type - -``enum`` any enumeration -``proc`` any proc type -``ref`` any ``ref`` type -``ptr`` any ``ptr`` type -``var`` any ``var`` type -``distinct`` any distinct type -``array`` any array type -``set`` any set type -``seq`` any seq type -``auto`` any type -================== =================================================== - -Furthermore, every generic type automatically creates a type class of the same -name that will match any instantiation of the generic type. - -Type classes can be combined using the standard boolean operators to form -more complex type classes: - -.. code-block:: nimrod - # create a type class that will match all tuple and object types - type TRecordType = tuple or object - - proc printFields(rec: TRecordType) = - for key, value in fieldPairs(rec): - echo key, " = ", value - -Procedures utilizing type classes in such manner are considered to be -`implicitly generic`:idx:. They will be instantiated once for each unique -combination of param types used within the program. - -Nimrod also allows for type classes and regular types to be specified -as `type constraints`:idx: of the generic type parameter: - -.. code-block:: nimrod - proc onlyIntOrString[T: int|string](x, y: T) = discard - - onlyIntOrString(450, 616) # valid - onlyIntOrString(5.0, 0.0) # type mismatch - onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time - -By default, during overload resolution each named type class will bind to -exactly one concrete type. Here is an example taken directly from the system -module to illustrate this: - -.. code-block:: nimrod - proc `==`*(x, y: tuple): bool = - ## requires `x` and `y` to be of the same tuple type - ## generic ``==`` operator for tuples that is lifted from the components - ## of `x` and `y`. - result = true - for a, b in fields(x, y): - if a != b: result = false - -Alternatively, the ``distinct`` type modifier can be applied to the type class -to allow each param matching the type class to bind to a different type. - -If a proc param doesn't have a type specified, Nimrod will use the -``distinct auto`` type class (also known as ``any``): - -.. code-block:: nimrod - # allow any combination of param types - proc concat(a, b): string = $a & $b - -Procs written with the implicitly generic style will often need to refer to the -type parameters of the matched generic type. They can be easily accessed using -the dot syntax: - -.. code-block:: nimrod - type TMatrix[T, Rows, Columns] = object - ... - - proc `[]`(m: TMatrix, row, col: int): TMatrix.T = - m.data[col * high(TMatrix.Columns) + row] - -Alternatively, the `type` operator can be used over the proc params for similar -effect when anonymous or distinct type classes are used. - -When a generic type is instantiated with a type class instead of a concrete -type, this results in another more specific type class: - -.. code-block:: nimrod - seq[ref object] # Any sequence storing references to any object type - - type T1 = auto - proc foo(s: seq[T1], e: T1) - # seq[T1] is the same as just `seq`, but T1 will be allowed to bind - # to a single type, while the signature is being matched - - TMatrix[Ordinal] # Any TMatrix instantiation using integer values - -As seen in the previous example, in such instantiations, it's not necessary to -supply all type parameters of the generic type, because any missing ones will -be inferred to have the equivalent of the `any` type class and thus they will -match anything without discrimination. - - -User defined type classes -------------------------- - -**Note**: User defined type classes are still in development. - -The user-defined type classes are available in two flavours - declarative and -imperative. Both are used to specify an arbitrary set of requirements that the -matched type must satisfy. - -Declarative type classes are written in the following form: - -.. code-block:: nimrod - type - Comparable = generic x, y - (x < y) is bool - - Container[T] = generic c - c.len is ordinal - items(c) is iterator - for value in c: - type(value) is T - -The type class will be matched if: - -a) all of the expressions within the body can be compiled for the tested type -b) all statically evaluatable boolean expressions in the body must be true - -The identifiers following the `generic` keyword represent instances of the -currently matched type. These instances can act both as variables of the type, -when used in contexts where a value is expected, and as the type itself when -used in contexts where a type is expected. - -Please note that the ``is`` operator allows one to easily verify the precise -type signatures of the required operations, but since type inference and -default parameters are still applied in the provided block, it's also possible -to encode usage protocols that do not reveal implementation details. - -As a special rule providing further convenience when writing type classes, any -type value appearing in a callable expression will be treated as a variable of -the designated type for overload resolution purposes, unless the type value was -passed in its explicit ``typedesc[T]`` form: - -.. code-block:: nimrod - type - OutputStream = generic S - write(var S, string) - -Much like generics, the user defined type classes will be instantiated exactly -once for each tested type and any static code included within them will also be -executed once. - - -Return Type Inference ---------------------- - -If a type class is used as the return type of a proc and it won't be bound to -a concrete type by some of the proc params, Nimrod will infer the return type -from the proc body. This is usually used with the ``auto`` type class: - -.. code-block:: nimrod - proc makePair(a, b): auto = (first: a, second: b) - -The return type will be treated as additional generic param and can be -explicitly specified at call sites as any other generic param. - -Future versions of Nimrod may also support overloading based on the return type -of the overloads. In such settings, the expected result type at call sites may -also influence the inferred return type. - - -Symbol lookup in generics -------------------------- - -The symbol binding rules in generics are slightly subtle: There are "open" and -"closed" symbols. A "closed" symbol cannot be re-bound in the instantiation -context, an "open" symbol can. Per default overloaded symbols are open -and every other symbol is closed. - -Open symbols are looked up in two different contexts: Both the context -at definition and the context at instantiation are considered: - -.. code-block:: nimrod - type - TIndex = distinct int - - proc `==` (a, b: TIndex): bool {.borrow.} - - var a = (0, 0.TIndex) - var b = (0, 0.TIndex) - - echo a == b # works! - -In the example the generic ``==`` for tuples (as defined in the system module) -uses the ``==`` operators of the tuple's components. However, the ``==`` for -the ``TIndex`` type is defined *after* the ``==`` for tuples; yet the example -compiles as the instantiation takes the currently defined symbols into account -too. - -A symbol can be forced to be open by a `mixin`:idx: declaration: - -.. code-block:: nimrod - proc create*[T](): ref T = - # there is no overloaded 'init' here, so we need to state that it's an - # open symbol explicitly: - mixin init - new result - init result - - -Bind statement --------------- - -The ``bind`` statement is the counterpart to the ``mixin`` statement. It -can be used to explicitly declare identifiers that should be bound early (i.e. -the identifiers should be looked up in the scope of the template/generic -definition): - -.. code-block:: nimrod - # Module A - var - lastId = 0 - - template genId*: expr = - bind lastId - inc(lastId) - lastId - -.. code-block:: nimrod - # Module B - import A - - echo genId() - -But a ``bind`` is rarely useful because symbol binding from the definition -scope is the default. - - -Templates -========= - -A template is a simple form of a macro: It is a simple substitution -mechanism that operates on Nimrod's abstract syntax trees. It is processed in -the semantic pass of the compiler. - -The syntax to *invoke* a template is the same as calling a procedure. - -Example: - -.. code-block:: nimrod - template `!=` (a, b: expr): expr = - # this definition exists in the System module - not (a == b) - - assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6)) - -The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact -templates: - -| ``a > b`` is transformed into ``b < a``. -| ``a in b`` is transformed into ``contains(b, a)``. -| ``notin`` and ``isnot`` have the obvious meanings. - -The "types" of templates can be the symbols ``expr`` (stands for *expression*), -``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type -description*). These are "meta types", they can only be used in certain -contexts. Real types can be used too; this implies that expressions are -expected. - - -Ordinary vs immediate templates -------------------------------- - -There are two different kinds of templates: immediate templates and -ordinary templates. Ordinary templates take part in overloading resolution. As -such their arguments need to be type checked before the template is invoked. -So ordinary templates cannot receive undeclared identifiers: - -.. code-block:: nimrod - - template declareInt(x: expr) = - var x: int - - declareInt(x) # error: unknown identifier: 'x' - -An ``immediate`` template does not participate in overload resolution and so -its arguments are not checked for semantics before invocation. So they can -receive undeclared identifiers: - -.. code-block:: nimrod - - template declareInt(x: expr) {.immediate.} = - var x: int - - declareInt(x) # valid - - -Passing a code block to a template ----------------------------------- - -If there is a ``stmt`` parameter it should be the last in the template -declaration, because statements are passed to a template via a -special ``:`` syntax: - -.. code-block:: nimrod - - template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} = - var f: TFile - if open(f, fn, mode): - try: - actions - finally: - close(f) - else: - quit("cannot open: " & fn) - - withFile(txt, "ttempl3.txt", fmWrite): - txt.writeln("line 1") - txt.writeln("line 2") - -In the example the two ``writeln`` statements are bound to the ``actions`` -parameter. - - -Symbol binding in templates ---------------------------- - -A template is a `hygienic`:idx: macro and so opens a new scope. Most symbols are -bound from the definition scope of the template: - -.. code-block:: nimrod - # Module A - var - lastId = 0 - - template genId*: expr = - inc(lastId) - lastId - -.. code-block:: nimrod - # Module B - import A - - echo genId() # Works as 'lastId' has been bound in 'genId's defining scope - -As in generics symbol binding can be influenced via ``mixin`` or ``bind`` -statements. - - - -Identifier construction ------------------------ - -In templates identifiers can be constructed with the backticks notation: - -.. code-block:: nimrod - - template typedef(name: expr, typ: typedesc) {.immediate.} = - type - `T name`* {.inject.} = typ - `P name`* {.inject.} = ref `T name` - - typedef(myint, int) - var x: PMyInt - -In the example ``name`` is instantiated with ``myint``, so \`T name\` becomes -``Tmyint``. - - -Lookup rules for template parameters ------------------------------------- - -A parameter ``p`` in a template is even substituted in the expression ``x.p``. -Thus template arguments can be used as field names and a global symbol can be -shadowed by the same argument name even when fully qualified: - -.. code-block:: nimrod - # module 'm' - - type - TLev = enum - levA, levB - - var abclev = levB - - template tstLev(abclev: TLev) = - echo abclev, " ", m.abclev - - tstLev(levA) - # produces: 'levA levA' - -But the global symbol can properly be captured by a ``bind`` statement: - -.. code-block:: nimrod - # module 'm' - - type - TLev = enum - levA, levB - - var abclev = levB - - template tstLev(abclev: TLev) = - bind m.abclev - echo abclev, " ", m.abclev - - tstLev(levA) - # produces: 'levA levB' - - -Hygiene in templates --------------------- - -Per default templates are `hygienic`:idx:\: Local identifiers declared in a -template cannot be accessed in the instantiation context: - -.. code-block:: nimrod - - template newException*(exceptn: typedesc, message: string): expr = - var - e: ref exceptn # e is implicitly gensym'ed here - new(e) - e.msg = message - e - - # so this works: - let e = "message" - raise newException(EIO, e) - - -Whether a symbol that is declared in a template is exposed to the instantiation -scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas: gensym'ed -symbols are not exposed but inject'ed are. - -The default for symbols of entity ``type``, ``var``, ``let`` and ``const`` -is ``gensym`` and for ``proc``, ``iterator``, ``converter``, ``template``, -``macro`` is ``inject``. However, if the name of the entity is passed as a -template parameter, it is an inject'ed symbol: - -.. code-block:: nimrod - template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} = - block: - var f: TFile # since 'f' is a template param, it's injected implicitly - ... - - withFile(txt, "ttempl3.txt", fmWrite): - txt.writeln("line 1") - txt.writeln("line 2") - - -The ``inject`` and ``gensym`` pragmas are second class annotations; they have -no semantics outside of a template definition and cannot be abstracted over: - -.. code-block:: nimrod - {.pragma myInject: inject.} - - template t() = - var x {.myInject.}: int # does NOT work - - -To get rid of hygiene in templates, one can use the `dirty`:idx: pragma for -a template. ``inject`` and ``gensym`` have no effect in ``dirty`` templates. - - - -Macros -====== - -A macro is a special kind of low level template. Macros can be used -to implement `domain specific languages`:idx:. Like templates, macros come in -the 2 flavors *immediate* and *ordinary*. - -While macros enable advanced compile-time code transformations, they -cannot change Nimrod's syntax. However, this is no real restriction because -Nimrod's syntax is flexible enough anyway. - -To write macros, one needs to know how the Nimrod concrete syntax is converted -to an abstract syntax tree. - -There are two ways to invoke a macro: -(1) invoking a macro like a procedure call (`expression macros`) -(2) invoking a macro with the special ``macrostmt`` syntax (`statement macros`) - - -Expression Macros ------------------ - -The following example implements a powerful ``debug`` command that accepts a -variable number of arguments: - -.. code-block:: nimrod - # to work with Nimrod syntax trees, we need an API that is defined in the - # ``macros`` module: - import macros - - macro debug(n: varargs[expr]): stmt = - # `n` is a Nimrod AST that contains the whole macro invocation - # this macro returns a list of statements: - result = newNimNode(nnkStmtList, n) - # iterate over any argument that is passed to this macro: - for i in 0..n.len-1: - # add a call to the statement list that writes the expression; - # `toStrLit` converts an AST to its string representation: - add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i]))) - # add a call to the statement list that writes ": " - add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": "))) - # add a call to the statement list that writes the expressions value: - add(result, newCall("writeln", newIdentNode("stdout"), n[i])) - - var - a: array [0..10, int] - x = "some string" - a[0] = 42 - a[1] = 45 - - debug(a[0], a[1], x) - -The macro call expands to: - -.. code-block:: nimrod - write(stdout, "a[0]") - write(stdout, ": ") - writeln(stdout, a[0]) - - write(stdout, "a[1]") - write(stdout, ": ") - writeln(stdout, a[1]) - - write(stdout, "x") - write(stdout, ": ") - writeln(stdout, x) - - -Arguments that are passed to a ``varargs`` parameter are wrapped in an array -constructor expression. This is why ``debug`` iterates over all of ``n``'s -children. - - -BindSym -------- - -The above ``debug`` macro relies on the fact that ``write``, ``writeln`` and -``stdout`` are declared in the system module and thus visible in the -instantiating context. There is a way to use bound identifiers -(aka `symbols`:idx:) instead of using unbound identifiers. The ``bindSym`` -builtin can be used for that: - -.. code-block:: nimrod - import macros - - macro debug(n: varargs[expr]): stmt = - result = newNimNode(nnkStmtList, n) - for i in 0..n.len-1: - # we can bind symbols in scope via 'bindSym': - add(result, newCall(bindSym"write", bindSym"stdout", toStrLit(n[i]))) - add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": "))) - add(result, newCall(bindSym"writeln", bindSym"stdout", n[i])) - - var - a: array [0..10, int] - x = "some string" - a[0] = 42 - a[1] = 45 - - debug(a[0], a[1], x) - -The macro call expands to: - -.. code-block:: nimrod - write(stdout, "a[0]") - write(stdout, ": ") - writeln(stdout, a[0]) - - write(stdout, "a[1]") - write(stdout, ": ") - writeln(stdout, a[1]) - - write(stdout, "x") - write(stdout, ": ") - writeln(stdout, x) - -However, the symbols ``write``, ``writeln`` and ``stdout`` are already bound -and are not looked up again. As the example shows, ``bindSym`` does work with -overloaded symbols implicitly. - - -Statement Macros ----------------- - -Statement macros are defined just as expression macros. However, they are -invoked by an expression following a colon. - -The following example outlines a macro that generates a lexical analyzer from -regular expressions: - -.. code-block:: nimrod - import macros - - macro case_token(n: stmt): stmt = - # creates a lexical analyzer from regular expressions - # ... (implementation is an exercise for the reader :-) - discard - - case_token: # this colon tells the parser it is a macro statement - of r"[A-Za-z_]+[A-Za-z_0-9]*": - return tkIdentifier - of r"0-9+": - return tkInteger - of r"[\+\-\*\?]+": - return tkOperator - else: - return tkUnknown - - -**Style note**: For code readability, it is the best idea to use the least -powerful programming construct that still suffices. So the "check list" is: - -(1) Use an ordinary proc/iterator, if possible. -(2) Else: Use a generic proc/iterator, if possible. -(3) Else: Use a template, if possible. -(4) Else: Use a macro. - - -Macros as pragmas ------------------ - -Whole routines (procs, iterators etc.) can also be passed to a template or -a macro via the pragma notation: - -.. code-block:: nimrod - template m(s: stmt) = discard - - proc p() {.m.} = discard - -This is a simple syntactic transformation into: - -.. code-block:: nimrod - template m(s: stmt) = discard - - m: - proc p() = discard - - -Special Types -============= - -static[T] ---------- - -**Note**: static[T] is still in development. - -As their name suggests, static params must be known at compile-time: - -.. code-block:: nimrod - - proc precompiledRegex(pattern: static[string]): TRegEx = - var res {.global.} = re(pattern) - return res - - precompiledRegex("/d+") # Replaces the call with a precompiled - # regex, stored in a global variable - - precompiledRegex(paramStr(1)) # Error, command-line options - # are not known at compile-time - - -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 -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: - -.. code-block:: nimrod - - # The following proc will be compiled once for each unique static - # value and also once for the case handling all run-time values: - - proc re(pattern: semistatic[string]): TRegEx = - when isStatic(pattern): - result = precompiledRegex(pattern) - else: - result = compile(pattern) - -Static params can also appear in the signatures of generic types: - -.. code-block:: nimrod - - type - Matrix[M,N: static[int]; T: Number] = array[0..(M*N - 1), T] - # Note how `Number` is just a type constraint here, while - # `static[int]` requires us to supply a compile-time int value - - AffineTransform2D[T] = Matrix[3, 3, T] - AffineTransform3D[T] = Matrix[4, 4, T] - - var m1: AffineTransform3D[float] # OK - var m2: AffineTransform2D[string] # Error, `string` is not a `Number` - - -typedesc --------- - -`typedesc` is a special type allowing one to treat types as compile-time values -(i.e. if types are compile-time values and all values have a type, then -typedesc must be their type). - -When used as a regular proc param, typedesc acts as a type class. The proc -will be instantiated for each unique type parameter and one can refer to the -instantiation type using the param name: - -.. code-block:: nimrod - - proc new(T: typedesc): ref T = - echo "allocating ", T.name - new(result) - - var n = TNode.new - var tree = new(TBinaryTree[int]) - -When multiple typedesc params are present, they act like a distinct type class -(i.e. they will bind freely to different types). To force a bind-once behavior -one can use a named alias or an explicit `typedesc` generic param: - -.. code-block:: nimrod - - # `type1` and `type2` are aliases for typedesc available from system.nim - proc acceptOnlyTypePairs(A, B: type1; C, D: type2) - proc acceptOnlyTypePairs[T: typedesc, U: typedesc](A, B: T; C, D: U) - -Once bound, typedesc params can appear in the rest of the proc signature: - -.. code-block:: nimrod - - template declareVariableWithType(T: typedesc, value: T) = - var x: T = value - - declareVariableWithType int, 42 - -When used with macros and .compileTime. procs on the other hand, the compiler -does not need to instantiate the code multiple times, because types then can be -manipulated using the unified internal symbol representation. In such context -typedesc acts as any other type. One can create variables, store typedesc -values inside containers and so on. For example, here is how one can create -a type-safe wrapper for the unsafe `printf` function from C: - -.. code-block:: nimrod - macro safePrintF(formatString: string{lit}, args: varargs[expr]): expr = - var i = 0 - for c in formatChars(formatString): - var expectedType = case c - of 'c': char - of 'd', 'i', 'x', 'X': int - of 'f', 'e', 'E', 'g', 'G': float - of 's': string - of 'p': pointer - else: EOutOfRange - - var actualType = args[i].getType - inc i - - if expectedType == EOutOfRange: - error c & " is not a valid format character" - elif expectedType != actualType: - error "type mismatch for argument ", i, ". expected type: ", - expectedType.name, ", actual type: ", actualType.name - - # keep the original callsite, but use cprintf instead - result = callsite() - result[0] = newIdentNode(!"cprintf") - - -Overload resolution can be further influenced by constraining the set of -types that will match the typedesc param: - -.. code-block:: nimrod - - template maxval(T: typedesc[int]): int = high(int) - template maxval(T: typedesc[float]): float = Inf - - var i = int.maxval - var f = float.maxval - var s = string.maxval # error, maxval is not implemented for string - -The constraint can be a concrete type or a type class. - - -Special Operators -================= - -dot operators -------------- - -Nimrod offers a special family of dot operators that can be used to -intercept and rewrite proc call and field access attempts, referring -to previously undeclared symbol names. They can be used to provide a -fluent interface to objects lying outside the static confines of the -type system such as values from dynamic scripting languages -or dynamic file formats such as JSON or XML. - -When Nimrod encounters an expression that cannot be resolved by the -standard overload resolution rules, the current scope will be searched -for a dot operator that can be matched against a re-written form of -the expression, where the unknown field or proc name is converted to -an additional static string parameter: - -.. code-block:: nimrod - a.b # becomes `.`(a, "b") - a.b(c, d) # becomes `.`(a, "b", c, d) - -The matched dot operators can be symbols of any callable kind (procs, -templates and macros), depending on the desired effect: - -.. code-block:: nimrod - proc `.` (js: PJsonNode, field: string): JSON = js[field] - - var js = parseJson("{ x: 1, y: 2}") - echo js.x # outputs 1 - echo js.y # outputs 2 - -The following dot operators are available: - -operator `.` ------------- -This operator will be matched against both field accesses and method calls. - -operator `.()` ---------------- -This operator will be matched exclusively against method calls. It has higher -precedence than the `.` operator and this allows one to handle expressions like -`x.y` and `x.y()` differently if one is interfacing with a scripting language -for example. - -operator `.=` -------------- -This operator will be matched against assignments to missing fields. - -.. code-block:: nimrod - a.b = c # becomes `.=`(a, "b", c) - - -Type bound operations -===================== - -There are 3 operations that are bound to a type: - -1. Assignment -2. Destruction -3. Deep copying for communication between threads - -These operations can be *overriden* instead of *overloaded*. This means the -implementation is automatically lifted to structured types. For instance if type -``T`` has an overriden assignment operator ``=`` this operator is also used -for assignments of the type ``seq[T]``. Since these operations are bound to a -type they have to be bound to a nominal type for reasons of simplicity of -implementation: This means an overriden ``deepCopy`` for ``ref T`` is really -bound to ``T`` and not to ``ref T``. This also means that one cannot override -``deepCopy`` for both ``ptr T`` and ``ref T`` at the same time; instead a -helper distinct or object type has to be used for one pointer type. - - -operator `=` ------------- - -This operator is the assignment operator. Note that in the contexts -like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for -parameter passing no assignment is performed. The ``override`` pragma is -optional for overriding ``=``. - - -destructors ------------ - -A destructor must have a single parameter with a concrete type (the name of a -generic type is allowed too). The name of the destructor has to be ``destroy`` -and it need to be annotated with the ``override`` pragma. - -``destroy(v)`` will be automatically invoked for every local stack -variable ``v`` that goes out of scope. - -If a structured type features a field with destructable type and -the user has not provided an explicit implementation, a destructor for the -structured type will be automatically generated. Calls to any base class -destructors in both user-defined and generated destructors will be inserted. - -A destructor is attached to the type it destructs; expressions of this type -can then only be used in *destructible contexts* and as parameters: - -.. code-block:: nimrod - type - TMyObj = object - x, y: int - p: pointer - - proc destroy(o: var TMyObj) {.override.} = - if o.p != nil: dealloc o.p - - proc open: TMyObj = - result = TMyObj(x: 1, y: 2, p: alloc(3)) - - proc work(o: TMyObj) = - echo o.x - # No destructor invoked here for 'o' as 'o' is a parameter. - - proc main() = - # destructor automatically invoked at the end of the scope: - var x = open() - # valid: pass 'x' to some other proc: - work(x) - - # Error: usage of a type with a destructor in a non destructible context - echo open() - -A destructible context is currently only the following: - -1. The ``expr`` in ``var x = expr``. -2. The ``expr`` in ``let x = expr``. -3. The ``expr`` in ``return expr``. -4. The ``expr`` in ``result = expr`` where ``result`` is the special symbol - introduced by the compiler. - -These rules ensure that the construction is tied to a variable and can easily -be destructed at its scope exit. Later versions of the language will improve -the support of destructors. - -Be aware that destructors are not called for objects allocated with ``new``. -This may change in future versions of language, but for now the ``finalizer`` -parameter to ``new`` has to be used. - - -deepCopy --------- - -``deepCopy`` is a builtin that is invoked whenever data is passed to -a ``spawn``'ed proc to ensure memory safety. The programmer can override its -behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the -language may weaken this restriction.) - -The signature has to be: - -.. code-block:: nimrod - proc deepCopy(x: T): T {.override.} - -This mechanism is used by most data structures that support shared memory like -channels to implement thread safe automatic memory management. - -The builtin ``deepCopy`` can even clone closures and their environments. See -the documentation of `spawn`_ for details. - - -Term rewriting macros -===================== - -Term rewriting macros are macros or templates that have not only -a *name* but also a *pattern* that is searched for after the semantic checking -phase of the compiler: This means they provide an easy way to enhance the -compilation pipeline with user defined optimizations: - -.. code-block:: nimrod - template optMul{`*`(a, 2)}(a: int): int = a+a - - let x = 3 - echo x * 2 - -The compiler now rewrites ``x * 2`` as ``x + x``. The code inside the -curlies is the pattern to match against. The operators ``*``, ``**``, -``|``, ``~`` have a special meaning in patterns if they are written in infix -notation, so to match verbatim against ``*`` the ordinary function call syntax -needs to be used. - - -Unfortunately optimizations are hard to get right and even the tiny example -is **wrong**: - -.. code-block:: nimrod - template optMul{`*`(a, 2)}(a: int): int = a+a - - proc f(): int = - echo "side effect!" - result = 55 - - echo f() * 2 - -We cannot duplicate 'a' if it denotes an expression that has a side effect! -Fortunately Nimrod supports side effect analysis: - -.. code-block:: nimrod - template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a - - proc f(): int = - echo "side effect!" - result = 55 - - echo f() * 2 # not optimized ;-) - -So what about ``2 * a``? We should tell the compiler ``*`` is commutative. We -cannot really do that however as the following code only swaps arguments -blindly: - -.. code-block:: nimrod - template mulIsCommutative{`*`(a, b)}(a, b: int): int = b*a - -What optimizers really need to do is a *canonicalization*: - -.. code-block:: nimrod - template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b*a - -The ``int{lit}`` parameter pattern matches against an expression of -type ``int``, but only if it's a literal. - - - -Parameter constraints ---------------------- - -The `parameter constraint`:idx: expression can use the operators ``|`` (or), -``&`` (and) and ``~`` (not) and the following predicates: - -=================== ===================================================== -Predicate Meaning -=================== ===================================================== -``atom`` The matching node has no children. -``lit`` The matching node is a literal like "abc", 12. -``sym`` The matching node must be a symbol (a bound - identifier). -``ident`` The matching node must be an identifier (an unbound - identifier). -``call`` The matching AST must be a call/apply expression. -``lvalue`` The matching AST must be an lvalue. -``sideeffect`` The matching AST must have a side effect. -``nosideeffect`` The matching AST must have no side effect. -``param`` A symbol which is a parameter. -``genericparam`` A symbol which is a generic parameter. -``module`` A symbol which is a module. -``type`` A symbol which is a type. -``var`` A symbol which is a variable. -``let`` A symbol which is a ``let`` variable. -``const`` A symbol which is a constant. -``result`` The special ``result`` variable. -``proc`` A symbol which is a proc. -``method`` A symbol which is a method. -``iterator`` A symbol which is an iterator. -``converter`` A symbol which is a converter. -``macro`` A symbol which is a macro. -``template`` A symbol which is a template. -``field`` A symbol which is a field in a tuple or an object. -``enumfield`` A symbol which is a field in an enumeration. -``forvar`` A for loop variable. -``label`` A label (used in ``block`` statements). -``nk*`` The matching AST must have the specified kind. - (Example: ``nkIfStmt`` denotes an ``if`` statement.) -``alias`` States that the marked parameter needs to alias - with *some* other parameter. -``noalias`` States that *every* other parameter must not alias - with the marked parameter. -=================== ===================================================== - -The ``alias`` and ``noalias`` predicates refer not only to the matching AST, -but also to every other bound parameter; syntactially they need to occur after -the ordinary AST predicates: - -.. code-block:: nimrod - template ex{a = b + c}(a: int{noalias}, b, c: int) = - # this transformation is only valid if 'b' and 'c' do not alias 'a': - a = b - inc a, c - - -Pattern operators ------------------ - -The operators ``*``, ``**``, ``|``, ``~`` have a special meaning in patterns -if they are written in infix notation. - - -The ``|`` operator -~~~~~~~~~~~~~~~~~~ - -The ``|`` operator if used as infix operator creates an ordered choice: - -.. code-block:: nimrod - template t{0|1}(): expr = 3 - let a = 1 - # outputs 3: - echo a - -The matching is performed after the compiler performed some optimizations like -constant folding, so the following does not work: - -.. code-block:: nimrod - template t{0|1}(): expr = 3 - # outputs 1: - echo 1 - -The reason is that the compiler already transformed the 1 into "1" for -the ``echo`` statement. However, a term rewriting macro should not change the -semantics anyway. In fact they can be deactived with the ``--patterns:off`` -command line option or temporarily with the ``patterns`` pragma. - - -The ``{}`` operator -~~~~~~~~~~~~~~~~~~~ - -A pattern expression can be bound to a pattern parameter via the ``expr{param}`` -notation: - -.. code-block:: nimrod - template t{(0|1|2){x}}(x: expr): expr = x+1 - let a = 1 - # outputs 2: - echo a - - -The ``~`` operator -~~~~~~~~~~~~~~~~~~ - -The ``~`` operator is the **not** operator in patterns: - -.. code-block:: nimrod - template t{x = (~x){y} and (~x){z}}(x, y, z: bool): stmt = - x = y - if x: x = z - - var - a = false - b = true - c = false - a = b and c - echo a - - -The ``*`` operator -~~~~~~~~~~~~~~~~~~ - -The ``*`` operator can *flatten* a nested binary expression like ``a & b & c`` -to ``&(a, b, c)``: - -.. code-block:: nimrod - var - calls = 0 - - proc `&&`(s: varargs[string]): string = - result = s[0] - for i in 1..len(s)-1: result.add s[i] - inc calls - - template optConc{ `&&` * a }(a: string): expr = &&a - - let space = " " - echo "my" && (space & "awe" && "some " ) && "concat" - - # check that it's been optimized properly: - doAssert calls == 1 - - -The second operator of `*` must be a parameter; it is used to gather all the -arguments. The expression ``"my" && (space & "awe" && "some " ) && "concat"`` -is passed to ``optConc`` in ``a`` as a special list (of kind ``nkArgList``) -which is flattened into a call expression; thus the invocation of ``optConc`` -produces: - -.. code-block:: nimrod - `&&`("my", space & "awe", "some ", "concat") - - -The ``**`` operator -~~~~~~~~~~~~~~~~~~~ - -The ``**`` is much like the ``*`` operator, except that it gathers not only -all the arguments, but also the matched operators in reverse polish notation: - -.. code-block:: nimrod - import macros - - type - TMatrix = object - dummy: int - - proc `*`(a, b: TMatrix): TMatrix = discard - proc `+`(a, b: TMatrix): TMatrix = discard - proc `-`(a, b: TMatrix): TMatrix = discard - proc `$`(a: TMatrix): string = result = $a.dummy - proc mat21(): TMatrix = - result.dummy = 21 - - macro optM{ (`+`|`-`|`*`) ** a }(a: TMatrix): expr = - echo treeRepr(a) - result = newCall(bindSym"mat21") - - var x, y, z: TMatrix - - echo x + y * z - x - -This passes the expression ``x + y * z - x`` to the ``optM`` macro as -an ``nnkArgList`` node containing:: - - Arglist - Sym "x" - Sym "y" - Sym "z" - Sym "*" - Sym "+" - Sym "x" - Sym "-" - -(Which is the reverse polish notation of ``x + y * z - x``.) - - -Parameters ----------- - -Parameters in a pattern are type checked in the matching process. If a -parameter is of the type ``varargs`` it is treated specially and it can match -0 or more arguments in the AST to be matched against: - -.. code-block:: nimrod - template optWrite{ - write(f, x) - ((write|writeln){w})(f, y) - }(x, y: varargs[expr], f: TFile, w: expr) = - w(f, x, y) - - - -Example: Partial evaluation ---------------------------- - -The following example shows how some simple partial evaluation can be -implemented with term rewriting: - -.. code-block:: nimrod - proc p(x, y: int; cond: bool): int = - result = if cond: x + y else: x - y - - template optP1{p(x, y, true)}(x, y: expr): expr = x + y - template optP2{p(x, y, false)}(x, y: expr): expr = x - y - - -Example: Hoisting ------------------ - -The following example shows how some form of hoisting can be implemented: - -.. code-block:: nimrod - import pegs - - template optPeg{peg(pattern)}(pattern: string{lit}): TPeg = - var gl {.global, gensym.} = peg(pattern) - gl - - for i in 0 .. 3: - echo match("(a b c)", peg"'(' @ ')'") - echo match("W_HI_Le", peg"\y 'while'") - -The ``optPeg`` template optimizes the case of a peg constructor with a string -literal, so that the pattern will only be parsed once at program startup and -stored in a global ``gl`` which is then re-used. This optimization is called -hoisting because it is comparable to classical loop hoisting. - - -AST based overloading -===================== - -Parameter constraints can also be used for ordinary routine parameters; these -constraints affect ordinary overloading resolution then: - -.. code-block:: nimrod - proc optLit(a: string{lit|`const`}) = - echo "string literal" - proc optLit(a: string) = - echo "no string literal" - - const - constant = "abc" - - var - variable = "xyz" - - optLit("literal") - optLit(constant) - optLit(variable) - -However, the constraints ``alias`` and ``noalias`` are not available in -ordinary routines. - - -Move optimization ------------------ - -The ``call`` constraint is particularly useful to implement a move -optimization for types that have copying semantics: - -.. code-block:: nimrod - proc `[]=`*(t: var TTable, key: string, val: string) = - ## puts a (key, value)-pair into `t`. The semantics of string require - ## a copy here: - let idx = findInsertionPosition(key) - t[idx] = key - t[idx] = val - - proc `[]=`*(t: var TTable, key: string{call}, val: string{call}) = - ## puts a (key, value)-pair into `t`. Optimized version that knows that - ## the strings are unique and thus don't need to be copied: - let idx = findInsertionPosition(key) - shallowCopy t[idx], key - shallowCopy t[idx], val - - var t: TTable - # overloading resolution ensures that the optimized []= is called here: - t[f()] = g() - - - -Modules -======= -Nimrod supports splitting a program into pieces by a module concept. -Each module needs to be in its own file and has its own `namespace`:idx:. -Modules enable `information hiding`:idx: and `separate compilation`:idx:. -A module may gain access to symbols of another module by the `import`:idx: -statement. `Recursive module dependencies`:idx: are allowed, but slightly -subtle. Only top-level symbols that are marked with an asterisk (``*``) are -exported. - -The algorithm for compiling modules is: - -- compile the whole module as usual, following import statements recursively - -- if there is a cycle only import the already parsed symbols (that are - exported); if an unknown identifier occurs then abort - -This is best illustrated by an example: - -.. code-block:: nimrod - # Module A - type - T1* = int # Module A exports the type ``T1`` - import B # the compiler starts parsing B - - proc main() = - var i = p(3) # works because B has been parsed completely here - - main() - - -.. code-block:: nimrod - # Module B - import A # A is not parsed here! Only the already known symbols - # of A are imported. - - proc p*(x: A.T1): A.T1 = - # this works because the compiler has already - # added T1 to A's interface symbol table - result = x + 1 - - -Import statement -~~~~~~~~~~~~~~~~ - -After the ``import`` statement a list of module names can follow or a single -module name followed by an ``except`` to prevent some symbols to be imported: - -.. code-block:: nimrod - import strutils except `%` - - # doesn't work then: - echo "$1" % "abc" - - -Module names in imports -~~~~~~~~~~~~~~~~~~~~~~~ - -A module alias can be introduced via the ``as`` keyword: - -.. code-block:: nimrod - import strutils as su, sequtils as qu - - echo su.format("$1", "lalelu") - -The original module name is then not accessible. The -notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"`` -can be used to refer to a module in subdirectories: - -.. code-block:: nimrod - import lib.pure.strutils, lib/pure/os, "lib/pure/times" - -Note that the module name is still ``strutils`` and not ``lib.pure.strutils`` -and so one **cannot** do: - -.. code-block:: nimrod - import lib.pure.strutils - echo lib.pure.strutils - -Likewise the following does not make sense as the name is ``strutils`` already: - -.. code-block:: nimrod - import lib.pure.strutils as strutils - - -From import statement -~~~~~~~~~~~~~~~~~~~~~ - -After the ``from`` statement a module name follows followed by -an ``import`` to list the symbols one likes to use without explict -full qualification: - -.. code-block:: nimrod - from strutils import `%` - - echo "$1" % "abc" - # always possible: full qualification: - echo strutils.replace("abc", "a", "z") - -It's also possible to use ``from module import nil`` if one wants to import -the module but wants to enforce fully qualified access to every symbol -in ``module``. - - -Export statement -~~~~~~~~~~~~~~~~ - -An ``export`` statement can be used for symbol fowarding so that client -modules don't need to import a module's dependencies: - -.. code-block:: nimrod - # module B - type TMyObject* = object - -.. code-block:: nimrod - # module A - import B - export B.TMyObject - - proc `$`*(x: TMyObject): string = "my object" - - -.. code-block:: nimrod - # module C - import A - - # B.TMyObject has been imported implicitly here: - var x: TMyObject - echo($x) - - -Scope rules ------------ -Identifiers are valid from the point of their declaration until the end of -the block in which the declaration occurred. The range where the identifier -is known is the scope of the identifier. The exact scope of an -identifier depends on the way it was declared. - -Block scope -~~~~~~~~~~~ -The *scope* of a variable declared in the declaration part of a block -is valid from the point of declaration until the end of the block. If a -block contains a second block, in which the identifier is redeclared, -then inside this block, the second declaration will be valid. Upon -leaving the inner block, the first declaration is valid again. An -identifier cannot be redefined in the same block, except if valid for -procedure or iterator overloading purposes. - - -Tuple or object scope -~~~~~~~~~~~~~~~~~~~~~ -The field identifiers inside a tuple or object definition are valid in the -following places: - -* To the end of the tuple/object definition. -* Field designators of a variable of the given tuple/object type. -* In all descendant types of the object type. - -Module scope -~~~~~~~~~~~~ -All identifiers of a module are valid from the point of declaration until -the end of the module. Identifiers from indirectly dependent modules are *not* -available. The `system`:idx: module is automatically imported in every other -module. - -If a module imports an identifier by two different modules, each occurrence of -the identifier has to be qualified, unless it is an overloaded procedure or -iterator in which case the overloading resolution takes place: - -.. code-block:: nimrod - # Module A - var x*: string - -.. code-block:: nimrod - # Module B - var x*: int - -.. code-block:: nimrod - # Module C - import A, B - write(stdout, x) # error: x is ambiguous - write(stdout, A.x) # no error: qualifier used - - var x = 4 - write(stdout, x) # not ambiguous: uses the module C's x - - -Compiler Messages -================= - -The Nimrod compiler emits different kinds of messages: `hint`:idx:, -`warning`:idx:, and `error`:idx: messages. An *error* message is emitted if -the compiler encounters any static error. - - -Pragmas -======= - -Pragmas are Nimrod's method to give the compiler additional information / -commands without introducing a massive number of new keywords. Pragmas are -processed on the fly during semantic checking. Pragmas are enclosed in the -special ``{.`` and ``.}`` curly brackets. Pragmas are also often used as a -first implementation to play with a language feature before a nicer syntax -to access the feature becomes available. - - -noSideEffect pragma -------------------- -The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side -effects. This means that the proc/iterator only changes locations that are -reachable from its parameters and the return value only depends on the -arguments. If none of its parameters have the type ``var T`` -or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static -error to mark a proc/iterator to have no side effect if the compiler cannot -verify this. - -As a special semantic rule, the built-in `debugEcho <system.html#debugEcho>`_ -pretends to be free of side effects, so that it can be used for debugging -routines marked as ``noSideEffect``. - -**Future directions**: ``func`` may become a keyword and syntactic sugar for a -proc with no side effects: - -.. code-block:: nimrod - func `+` (x, y: int): int - - -destructor pragma ------------------ - -The ``destructor`` pragma is used to mark a proc to act as a type destructor. -Its usage is deprecated, use the ``override`` pragma instead. -See `type bound operations`_. - - -override pragma ---------------- - -See `type bound operations`_ instead. - -procvar pragma --------------- -The ``procvar`` pragma is used to mark a proc that it can be passed to a -procedural variable. - - -compileTime pragma ------------------- -The ``compileTime`` pragma is used to mark a proc to be used at compile -time only. No code will be generated for it. Compile time procs are useful -as helpers for macros. - - -noReturn pragma ---------------- -The ``noreturn`` pragma is used to mark a proc that never returns. - - -Acyclic pragma --------------- -The ``acyclic`` pragma can be used for object types to mark them as acyclic -even though they seem to be cyclic. This is an **optimization** for the garbage -collector to not consider objects of this type as part of a cycle: - -.. code-block:: nimrod - type - PNode = ref TNode - TNode {.acyclic, final.} = object - left, right: PNode - data: string - -In the example a tree structure is declared with the ``TNode`` type. Note that -the type definition is recursive and the GC has to assume that objects of -this type may form a cyclic graph. The ``acyclic`` pragma passes the -information that this cannot happen to the GC. If the programmer uses the -``acyclic`` pragma for data types that are in reality cyclic, the GC may leak -memory, but nothing worse happens. - -**Future directions**: The ``acyclic`` pragma may become a property of a -``ref`` type: - -.. code-block:: nimrod - type - PNode = acyclic ref TNode - TNode = object - left, right: PNode - data: string - - -Final pragma ------------- -The ``final`` pragma can be used for an object type to specify that it -cannot be inherited from. - - -shallow pragma --------------- -The ``shallow`` pragma affects the semantics of a type: The compiler is -allowed to make a shallow copy. This can cause serious semantic issues and -break memory safety! However, it can speed up assignments considerably, -because the semantics of Nimrod require deep copying of sequences and strings. -This can be expensive, especially if sequences are used to build a tree -structure: - -.. code-block:: nimrod - type - TNodeKind = enum nkLeaf, nkInner - TNode {.final, shallow.} = object - case kind: TNodeKind - of nkLeaf: - strVal: string - of nkInner: - children: seq[TNode] - - -Pure pragma ------------ -An object type can be marked with the ``pure`` pragma so that its type -field which is used for runtime type identification is omitted. This is -necessary for binary compatibility with other compiled languages. - - -AsmNoStackFrame pragma ----------------------- -A proc can be marked with the ``AsmNoStackFrame`` pragma to tell the compiler -it should not generate a stack frame for the proc. There are also no exit -statements like ``return result;`` generated and the generated C function is -declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on -the used C compiler). - -**Note**: This pragma should only be used by procs which consist solely of -assembler statements. - -error pragma ------------- -The ``error`` pragma is used to make the compiler output an error message -with the given content. Compilation does not necessarily abort after an error -though. - -The ``error`` pragma can also be used to -annotate a symbol (like an iterator or proc). The *usage* of the symbol then -triggers a compile-time error. This is especially useful to rule out that some -operation is valid due to overloading and type conversions: - -.. code-block:: nimrod - ## check that underlying int values are compared and not the pointers: - proc `==`(x, y: ptr int): bool {.error.} - - -fatal pragma ------------- -The ``fatal`` pragma is used to make the compiler output an error message -with the given content. In contrast to the ``error`` pragma, compilation -is guaranteed to be aborted by this pragma. Example: - -.. code-block:: nimrod - when not defined(objc): - {.fatal: "Compile this program with the objc command!".} - -warning pragma --------------- -The ``warning`` pragma is used to make the compiler output a warning message -with the given content. Compilation continues after the warning. - -hint pragma ------------ -The ``hint`` pragma is used to make the compiler output a hint message with -the given content. Compilation continues after the hint. - -line pragma ------------ -The ``line`` pragma can be used to affect line information of the annotated -statement as seen in stack backtraces: - -.. code-block:: nimrod - - template myassert*(cond: expr, msg = "") = - if not cond: - # change run-time line information of the 'raise' statement: - {.line: InstantiationInfo().}: - raise newException(EAssertionFailed, msg) - -If the ``line`` pragma is used with a parameter, the parameter needs be a -``tuple[filename: string, line: int]``. If it is used without a parameter, -``system.InstantiationInfo()`` is used. - - -linearScanEnd pragma --------------------- -The ``linearScanEnd`` pragma can be used to tell the compiler how to -compile a Nimrod `case`:idx: statement. Syntactically it has to be used as a -statement: - -.. code-block:: nimrod - case myInt - of 0: - echo "most common case" - of 1: - {.linearScanEnd.} - echo "second most common case" - of 2: echo "unlikely: use branch table" - else: echo "unlikely too: use branch table for ", myInt - -In the example, the case branches ``0`` and ``1`` are much more common than -the other cases. Therefore the generated assembler code should test for these -values first, so that the CPU's branch predictor has a good chance to succeed -(avoiding an expensive CPU pipeline stall). The other cases might be put into a -jump table for O(1) overhead, but at the cost of a (very likely) pipeline -stall. - -The ``linearScanEnd`` pragma should be put into the last branch that should be -tested against via linear scanning. If put into the last branch of the -whole ``case`` statement, the whole ``case`` statement uses linear scanning. - - -computedGoto pragma -------------------- -The ``computedGoto`` pragma can be used to tell the compiler how to -compile a Nimrod `case`:idx: in a ``while true`` statement. -Syntactically it has to be used as a statement inside the loop: - -.. code-block:: nimrod - - type - MyEnum = enum - enumA, enumB, enumC, enumD, enumE - - proc vm() = - var instructions: array [0..100, MyEnum] - instructions[2] = enumC - instructions[3] = enumD - instructions[4] = enumA - instructions[5] = enumD - instructions[6] = enumC - instructions[7] = enumA - instructions[8] = enumB - - instructions[12] = enumE - var pc = 0 - while true: - {.computedGoto.} - let instr = instructions[pc] - case instr - of enumA: - echo "yeah A" - of enumC, enumD: - echo "yeah CD" - of enumB: - echo "yeah B" - of enumE: - break - inc(pc) - - vm() - -As the example shows ``computedGoto`` is mostly useful for interpreters. If -the underlying backend (C compiler) does not support the computed goto -extension the pragma is simply ignored. - - -unroll pragma -------------- -The ``unroll`` pragma can be used to tell the compiler that it should unroll -a `for`:idx: or `while`:idx: loop for runtime efficiency: - -.. code-block:: nimrod - proc searchChar(s: string, c: char): int = - for i in 0 .. s.high: - {.unroll: 4.} - if s[i] == c: return i - result = -1 - -In the above example, the search loop is unrolled by a factor 4. The unroll -factor can be left out too; the compiler then chooses an appropriate unroll -factor. - -**Note**: Currently the compiler recognizes but ignores this pragma. - - -immediate pragma ----------------- - -See `Ordinary vs immediate templates`_. - - -compilation option pragmas --------------------------- -The listed pragmas here can be used to override the code generation options -for a proc/method/converter. - -The implementation currently provides the following possible options (various -others may be added later). - -=============== =============== ============================================ -pragma allowed values description -=============== =============== ============================================ -checks on|off Turns the code generation for all runtime - checks on or off. -boundChecks on|off Turns the code generation for array bound - checks on or off. -overflowChecks on|off Turns the code generation for over- or - underflow checks on or off. -nilChecks on|off Turns the code generation for nil pointer - checks on or off. -assertions on|off Turns the code generation for assertions - on or off. -warnings on|off Turns the warning messages of the compiler - on or off. -hints on|off Turns the hint messages of the compiler - on or off. -optimization none|speed|size Optimize the code for speed or size, or - disable optimization. -patterns on|off Turns the term rewriting templates/macros - on or off. -callconv cdecl|... Specifies the default calling convention for - all procedures (and procedure types) that - follow. -=============== =============== ============================================ - -Example: - -.. code-block:: nimrod - {.checks: off, optimization: speed.} - # compile without runtime checks and optimize for speed - - -push and pop pragmas --------------------- -The `push/pop`:idx: pragmas are very similar to the option directive, -but are used to override the settings temporarily. Example: - -.. code-block:: nimrod - {.push checks: off.} - # compile this section without runtime checks as it is - # speed critical - # ... some code ... - {.pop.} # restore old settings - - -register pragma ---------------- -The ``register`` pragma is for variables only. It declares the variable as -``register``, giving the compiler a hint that the variable should be placed -in a hardware register for faster access. C compilers usually ignore this -though and for good reasons: Often they do a better job without it anyway. - -In highly specific cases (a dispatch loop of an bytecode interpreter for -example) it may provide benefits, though. - - -global pragma -------------- -The ``global`` pragma can be applied to a variable within a proc to instruct -the compiler to store it in a global location and initialize it once at program -startup. - -.. code-block:: nimrod - proc isHexNumber(s: string): bool = - var pattern {.global.} = re"[0-9a-fA-F]+" - result = s.match(pattern) - -When used within a generic proc, a separate unique global variable will be -created for each instantiation of the proc. The order of initialization of -the created global variables within a module is not defined, but all of them -will be initialized after any top-level variables in their originating module -and before any variable in a module that imports it. - -DeadCodeElim pragma -------------------- -The ``deadCodeElim`` pragma only applies to whole modules: It tells the -compiler to activate (or deactivate) dead code elimination for the module the -pragma appears in. - -The ``--deadCodeElim:on`` command line switch has the same effect as marking -every module with ``{.deadCodeElim:on}``. However, for some modules such as -the GTK wrapper it makes sense to *always* turn on dead code elimination - -no matter if it is globally active or not. - -Example: - -.. code-block:: nimrod - {.deadCodeElim: on.} - - -.. - NoForward pragma - ---------------- - The ``noforward`` pragma can be used to turn on and off a special compilation - mode that to large extent eliminates the need for forward declarations. In this - mode, the proc definitions may appear out of order and the compiler will postpone - their semantic analysis and compilation until it actually needs to generate code - using the definitions. In this regard, this mode is similar to the modus operandi - of dynamic scripting languages, where the function calls are not resolved until - the code is executed. Here is the detailed algorithm taken by the compiler: - - 1. When a callable symbol is first encountered, the compiler will only note the - symbol callable name and it will add it to the appropriate overload set in the - current scope. At this step, it won't try to resolve any of the type expressions - used in the signature of the symbol (so they can refer to other not yet defined - symbols). - - 2. When a top level call is encountered (usually at the very end of the module), - the compiler will try to determine the actual types of all of the symbols in the - matching overload set. This is a potentially recursive process as the signatures - of the symbols may include other call expressions, whoose types will be resolved - at this point too. - - 3. Finally, after the best overload is picked, the compiler will start compiling - the body of the respective symbol. This in turn will lead the compiler to discover - more call expresions that need to be resolved and steps 2 and 3 will be repeated - as necessary. - - Please note that if a callable symbol is never used in this scenario, its body - will never be compiled. This is the default behavior leading to best compilation - times, but if exhaustive compilation of all definitions is required, using - ``nimrod check`` provides this option as well. - - Example: - - .. code-block:: nimrod - - {.noforward: on.} - - proc foo(x: int) = - bar x - - proc bar(x: int) = - echo x - - foo(10) - - -Pragma pragma -------------- - -The ``pragma`` pragma can be used to declare user defined pragmas. This is -useful because Nimrod's templates and macros do not affect pragmas. User -defined pragmas are in a different module-wide scope than all other symbols. -They cannot be imported from a module. - -Example: - -.. code-block:: nimrod - when appType == "lib": - {.pragma: rtl, exportc, dynlib, cdecl.} - else: - {.pragma: rtl, importc, dynlib: "client.dll", cdecl.} - - proc p*(a, b: int): int {.rtl.} = - result = a+b - -In the example a new pragma named ``rtl`` is introduced that either imports -a symbol from a dynamic library or exports the symbol for dynamic library -generation. - - -Disabling certain messages --------------------------- -Nimrod generates some warnings and hints ("line too long") that may annoy the -user. A mechanism for disabling certain messages is provided: Each hint -and warning message contains a symbol in brackets. This is the message's -identifier that can be used to enable or disable it: - -.. code-block:: Nimrod - {.hint[LineTooLong]: off.} # turn off the hint about too long lines - -This is often better than disabling all warnings at once. - - -Foreign function interface -========================== - -Nimrod's `FFI`:idx: (foreign function interface) is extensive and only the -parts that scale to other future backends (like the LLVM/JavaScript backends) -are documented here. - - -Importc pragma --------------- -The ``importc`` pragma provides a means to import a proc or a variable -from C. The optional argument is a string containing the C identifier. If -the argument is missing, the C name is the Nimrod identifier *exactly as -spelled*: - -.. code-block:: - proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.} - -Note that this pragma is somewhat of a misnomer: Other backends will provide -the same feature under the same name. Also, if one is interfacing with C++ -the `ImportCpp pragma <nimrodc.html#importcpp-pragma>`_ and -interfacing with Objective-C the `ImportObjC pragma -<nimrodc.html#importobjc-pragma>`_ can be used. - - -Exportc pragma --------------- -The ``exportc`` pragma provides a means to export a type, a variable, or a -procedure to C. Enums and constants can't be exported. The optional argument -is a string containing the C identifier. If the argument is missing, the C -name is the Nimrod identifier *exactly as spelled*: - -.. code-block:: Nimrod - proc callme(formatstr: cstring) {.exportc: "callMe", varargs.} - -Note that this pragma is somewhat of a misnomer: Other backends will provide -the same feature under the same name. - - -Extern pragma -------------- -Like ``exportc`` or ``importc``, the ``extern`` pragma affects name -mangling. The string literal passed to ``extern`` can be a format string: - -.. code-block:: Nimrod - proc p(s: string) {.extern: "prefix$1".} = - echo s - -In the example the external name of ``p`` is set to ``prefixp``. - - -Bycopy pragma -------------- - -The ``bycopy`` pragma can be applied to an object or tuple type and -instructs the compiler to pass the type by value to procs: - -.. code-block:: nimrod - type - TVector {.bycopy, pure.} = object - x, y, z: float - - -Byref pragma ------------- - -The ``byref`` pragma can be applied to an object or tuple type and instructs -the compiler to pass the type by reference (hidden pointer) to procs. - - -Varargs pragma --------------- -The ``varargs`` pragma can be applied to procedures only (and procedure -types). It tells Nimrod that the proc can take a variable number of parameters -after the last specified parameter. Nimrod string values will be converted to C -strings automatically: - -.. code-block:: Nimrod - proc printf(formatstr: cstring) {.nodecl, varargs.} - - printf("hallo %s", "world") # "world" will be passed as C string - - -Union pragma ------------- -The ``union`` pragma can be applied to any ``object`` type. It means all -of the object's fields are overlaid in memory. This produces a ``union`` -instead of a ``struct`` in the generated C/C++ code. The object declaration -then must not use inheritance or any GC'ed memory but this is currently not -checked. - -**Future directions**: GC'ed memory should be allowed in unions and the GC -should scan unions conservatively. - -Packed pragma -------------- -The ``packed`` pragma can be applied to any ``object`` type. It ensures -that the fields of an object are packed back-to-back in memory. It is useful -to store packets or messages from/to network or hardware drivers, and for -interoperability with C. Combining packed pragma with inheritance is not -defined, and it should not be used with GC'ed memory (ref's). - -**Future directions**: Using GC'ed memory in packed pragma will result in -compile-time error. Usage with inheritance should be defined and documented. - -Unchecked pragma ----------------- -The ``unchecked`` pragma can be used to mark a named array as ``unchecked`` -meaning its bounds are not checked. This is often useful when one wishes to -implement his own flexibly sized arrays. Additionally an unchecked array is -translated into a C array of undetermined size: - -.. code-block:: nimrod - type - ArrayPart{.unchecked.} = array[0..0, int] - MySeq = object - len, cap: int - data: ArrayPart - -Produces roughly this C code: - -.. code-block:: C - typedef struct { - NI len; - NI cap; - NI data[]; - } MySeq; - -The bounds checking done at compile time is not disabled for now, so to access -``s.data[C]`` (where ``C`` is a constant) the array's index needs needs to -include ``C``. - -The base type of the unchecked array may not contain any GC'ed memory but this -is currently not checked. - -**Future directions**: GC'ed memory should be allowed in unchecked arrays and -there should be an explicit annotation of how the GC is to determine the -runtime size of the array. - - -Dynlib pragma for import ------------------------- -With the ``dynlib`` pragma a procedure or a variable can be imported from -a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). -The non-optional argument has to be the name of the dynamic library: - -.. code-block:: Nimrod - proc gtk_image_new(): PGtkWidget - {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.} - -In general, importing a dynamic library does not require any special linker -options or linking with import libraries. This also implies that no *devel* -packages need to be installed. - -The ``dynlib`` import mechanism supports a versioning scheme: - -.. code-block:: nimrod - proc Tcl_Eval(interp: pTcl_Interp, script: cstring): int {.cdecl, - importc, dynlib: "libtcl(|8.5|8.4|8.3).so.(1|0)".} - -At runtime the dynamic library is searched for (in this order):: - - libtcl.so.1 - libtcl.so.0 - libtcl8.5.so.1 - libtcl8.5.so.0 - libtcl8.4.so.1 - libtcl8.4.so.0 - libtcl8.3.so.1 - libtcl8.3.so.0 - -The ``dynlib`` pragma supports not only constant strings as argument but also -string expressions in general: - -.. code-block:: nimrod - import os - - proc getDllName: string = - result = "mylib.dll" - if existsFile(result): return - result = "mylib2.dll" - if existsFile(result): return - quit("could not load dynamic library") - - proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().} - -**Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant -strings, because they are precompiled. - -**Note**: Passing variables to the ``dynlib`` pragma will fail at runtime -because of order of initialization problems. - -**Note**: A ``dynlib`` import can be overriden with -the ``--dynlibOverride:name`` command line option. The Compiler User Guide -contains further information. - - -Dynlib pragma for export ------------------------- - -With the ``dynlib`` pragma a procedure can also be exported to -a dynamic library. The pragma then has no argument and has to be used in -conjunction with the ``exportc`` pragma: - -.. code-block:: Nimrod - proc exportme(): int {.cdecl, exportc, dynlib.} - -This is only useful if the program is compiled as a dynamic library via the -``--app:lib`` command line option. - - -Threads -======= - -To enable thread support the ``--threads:on`` command line switch needs to -be used. The ``system`` module then contains several threading primitives. -See the `threads <threads.html>`_ and `channels <channels.html>`_ modules -for the thread API. - -Nimrod's memory model for threads is quite different than that of other common -programming languages (C, Pascal, Java): Each thread has its own (garbage -collected) heap and sharing of memory is restricted to global variables. This -helps to prevent race conditions. GC efficiency is improved quite a lot, -because the GC never has to stop other threads and see what they reference. -Memory allocation requires no lock at all! This design easily scales to massive -multicore processors that will become the norm in the future. - - -Thread pragma -------------- - -A proc that is executed as a new thread of execution should be marked by the -``thread`` pragma. The compiler checks procedures marked as ``thread`` for -violations of the `no heap sharing restriction`:idx:\: This restriction implies -that it is invalid to construct a data structure that consists of memory -allocated from different (thread local) heaps. - -A thread proc is passed to ``createThread`` or ``spawn`` and invoked -indirectly; so the ``thread`` pragma implies ``procvar``. - - -GC safety ---------- - -We call a proc ``p`` `GC safe`:idx: when it doesn't access any global variable -that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either -directly or indirectly through a call to a GC unsafe proc. - -The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe -otherwise this property is inferred by the compiler. Note that ``noSideEfect`` -implies ``gcsafe``. The only way to create a thread is via ``spawn`` or -``createThead``. ``spawn`` is usually the preferable method. Either way -the invoked proc must not use ``var`` parameters nor must any of its parameters -contain a ``ref`` or ``closure`` type. This enforces -the *no heap sharing restriction*. - -Routines that are imported from C are always assumed to be ``gcsafe``. -To enable the GC-safety checking the ``--threadAnalysis:on`` command line -switch must be used. This is a temporary workaround to ease the porting effort -from old code to the new threading model. In the future the thread analysis -will always be performed. - - -Future directions: - -- For structured fork&join parallelism more efficient parameter passing can - be performed and much more can be proven safe. -- A shared GC'ed heap is planned. - - -Threadvar pragma ----------------- - -A global variable can be marked with the ``threadvar`` pragma; it is -a `thread-local`:idx: variable then: - -.. code-block:: nimrod - var checkpoints* {.threadvar.}: seq[string] - -Due to implementation restrictions thread local variables cannot be -initialized within the ``var`` section. (Every thread local variable needs to -be replicated at thread creation.) - - -Threads and exceptions ----------------------- - -The interaction between threads and exceptions is simple: A *handled* exception -in one thread cannot affect any other thread. However, an *unhandled* -exception in one thread terminates the whole *process*! - - -Spawn ------ - -Nimrod has a builtin thread pool that can be used for CPU intensive tasks. For -IO intensive tasks the upcoming ``async`` and ``await`` features should be -used instead. `spawn`:idx: is used to pass a task to the thread pool: - -.. code-block:: nimrod - proc processLine(line: string) = - # do some heavy lifting here: - discard - - for x in lines("myinput.txt"): - spawn processLine(x) - sync() - -Currently the expression that ``spawn`` takes is however quite restricted: - -* It must be a call expression ``f(a, ...)``. -* ``f`` must be ``gcsafe``. -* ``f`` must not have the calling convention ``closure``. -* ``f``'s parameters may not be of type ``var``. - This means one has to use raw ``ptr``'s for data passing reminding the - programmer to be careful. -* ``ref`` parameters are deeply copied which is a subtle semantic change and - can cause performance problems but ensures memory safety. -* For *safe* data exchange between ``f`` and the caller a global ``TChannel`` - needs to be used. Other means will be provided soon. - - - -Taint mode -========== - -The Nimrod compiler and most parts of the standard library support -a taint mode. Input strings are declared with the `TaintedString`:idx: -string type declared in the ``system`` module. - -If the taint mode is turned on (via the ``--taintMode:on`` command line -option) it is a distinct string type which helps to detect input -validation errors: - -.. code-block:: nimrod - echo "your name: " - var name: TaintedString = stdin.readline - # it is safe here to output the name without any input validation, so - # we simply convert `name` to string to make the compiler happy: - echo "hi, ", name.string - -If the taint mode is turned off, ``TaintedString`` is simply an alias for -``string``. - +.. include:: manual/about.txt +.. include:: manual/definitions.txt +.. include:: manual/lexing.txt +.. include:: manual/syntax.txt +.. include:: manual/types.txt +.. include:: manual/type_rel.txt +.. include:: manual/stmts.txt +.. include:: manual/procs.txt +.. include:: manual/type_sections.txt +.. include:: manual/exceptions.txt +.. include:: manual/effects.txt +.. include:: manual/generics.txt +.. include:: manual/templates.txt +.. include:: manual/typedesc.txt +.. include:: manual/special_ops.txt +.. include:: manual/type_bound_ops.txt +.. include:: manual/trmacros.txt +.. include:: manual/modules.txt +.. include:: manual/compiler_msgs.txt +.. include:: manual/pragmas.txt +.. include:: manual/ffi.txt +.. include:: manual/threads.txt +.. include:: manual/locking.txt +.. include:: manual/taint.txt diff --git a/doc/manual/about.txt b/doc/manual/about.txt new file mode 100644 index 000000000..13307279b --- /dev/null +++ b/doc/manual/about.txt @@ -0,0 +1,37 @@ +About this document +=================== + +**Note**: This document is a draft! Several of Nim's features need more +precise wording. This manual will evolve into a proper specification some +day. + +This document describes the lexis, the syntax, and the semantics of Nim. + +The language constructs are explained using an extended BNF, in +which ``(a)*`` means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and +``(a)?`` means an optional *a*. Parentheses may be used to group elements. + +``&`` is the lookahead operator; ``&a`` means that an ``a`` is expected but +not consumed. It will be consumed in the following rule. + +The ``|``, ``/`` symbols are used to mark alternatives and have the lowest +precedence. ``/`` is the ordered choice that requires the parser to try the +alternatives in the given order. ``/`` is often used to ensure the grammar +is not ambiguous. + +Non-terminals start with a lowercase letter, abstract terminal symbols are in +UPPERCASE. Verbatim terminal symbols (including keywords) are quoted +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 +separated by its second argument; likewise ``^+`` means 1 or more +occurances: ``a ^+ b`` is short for ``a (b a)*`` +and ``a ^* b`` is short for ``(a (b a)*)?``. Example:: + + arrayConstructor = '[' expr ^* ',' ']' + +Other parts of Nim - like scoping rules or runtime semantics are only +described in an informal manner for now. + diff --git a/doc/manual/compiler_msgs.txt b/doc/manual/compiler_msgs.txt new file mode 100644 index 000000000..3cf8417b0 --- /dev/null +++ b/doc/manual/compiler_msgs.txt @@ -0,0 +1,7 @@ +Compiler Messages +================= + +The Nim compiler emits different kinds of messages: `hint`:idx:, +`warning`:idx:, and `error`:idx: messages. An *error* message is emitted if +the compiler encounters any static error. + diff --git a/doc/manual/definitions.txt b/doc/manual/definitions.txt new file mode 100644 index 000000000..687980dbc --- /dev/null +++ b/doc/manual/definitions.txt @@ -0,0 +1,49 @@ + +Definitions +=========== + +A Nim program specifies a computation that acts on a memory consisting of +components called `locations`:idx:. A variable is basically a name for a +location. Each variable and location is of a certain `type`:idx:. The +variable's type is called `static type`:idx:, the location's type is called +`dynamic type`:idx:. If the static type is not the same as the dynamic type, +it is a super-type or subtype of the dynamic type. + +An `identifier`:idx: is a symbol declared as a name for a variable, type, +procedure, etc. The region of the program over which a declaration applies is +called the `scope`:idx: of the declaration. Scopes can be nested. The meaning +of an identifier is determined by the smallest enclosing scope in which the +identifier is declared unless overloading resolution rules suggest otherwise. + +An expression specifies a computation that produces a value or location. +Expressions that produce locations are called `l-values`:idx:. An l-value +can denote either a location or the value the location contains, depending on +the context. Expressions whose values can be determined statically are called +`constant expressions`:idx:; they are never l-values. + +A `static error`:idx: is an error that the implementation detects before +program execution. Unless explicitly classified, an error is a static error. + +A `checked runtime error`:idx: is an error that the implementation detects +and reports at runtime. The method for reporting such errors is via *raising +exceptions* or *dying with a fatal error*. However, the implementation +provides a means to disable these runtime checks. See the section pragmas_ +for details. + +Wether a checked runtime error results in an exception or in a fatal error at +runtime is implementation specific. Thus the following program is always +invalid: + +.. code-block:: nim + var a: array[0..1, char] + let i = 5 + try: + a[i] = 'N' + except EInvalidIndex: + echo "invalid index" + +An `unchecked runtime error`:idx: is an error that is not guaranteed to be +detected, and can cause the subsequent behavior of the computation to +be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx: +language features are used. + diff --git a/doc/manual/effects.txt b/doc/manual/effects.txt new file mode 100644 index 000000000..73934ab34 --- /dev/null +++ b/doc/manual/effects.txt @@ -0,0 +1,129 @@ +Effect system +============= + +Exception tracking +------------------ + +Nim supports exception tracking. The `raises`:idx: pragma can be used +to explicitly define which exceptions a proc/iterator/method/converter is +allowed to raise. The compiler verifies this: + +.. code-block:: nim + proc p(what: bool) {.raises: [IOError, OSError].} = + if what: raise newException(IOError, "IO") + else: raise newException(OSError, "OS") + +An empty ``raises`` list (``raises: []``) means that no exception may be raised: + +.. code-block:: nim + proc p(): bool {.raises: [].} = + try: + unsafeCall() + result = true + except: + result = false + + +A ``raises`` list can also be attached to a proc type. This affects type +compatibility: + +.. code-block:: nim + type + TCallback = proc (s: string) {.raises: [IOError].} + var + c: TCallback + + proc p(x: string) = + raise newException(OSError, "OS") + + c = p # type error + + +For a routine ``p`` the compiler uses inference rules to determine the set of +possibly raised exceptions; the algorithm operates on ``p``'s call graph: + +1. Every indirect call via some proc type ``T`` is assumed to + raise ``system.Exception`` (the base type of the exception hierarchy) and + thus any exception unless ``T`` has an explicit ``raises`` list. + However if the call is of the form ``f(...)`` where ``f`` is a parameter + of the currently analysed routine it is ignored. The call is optimistically + assumed to have no effect. Rule 2 compensates for this case. +2. Every expression of some proc type wihtin a call that is not a call + itself (and not nil) is assumed to be called indirectly somehow and thus + its raises list is added to ``p``'s raises list. +3. Every call to a proc ``q`` which has an unknown body (due to a forward + declaration or an ``importc`` pragma) is assumed to + raise ``system.Exception`` unless ``q`` has an explicit ``raises`` list. +4. Every call to a method ``m`` is assumed to + raise ``system.Exception`` unless ``m`` has an explicit ``raises`` list. +5. For every other call the analysis can determine an exact ``raises`` list. +6. For determining a ``raises`` list, the ``raise`` and ``try`` statements + of ``p`` are taken into consideration. + +Rules 1-2 ensure the following works: + +.. code-block:: nim + proc noRaise(x: proc()) {.raises: [].} = + # unknown call that might raise anything, but valid: + x() + + proc doRaise() {.raises: [IOError].} = + raise newException(IOError, "IO") + + proc use() {.raises: [].} = + # doesn't compile! Can raise IOError! + noRaise(doRaise) + +So in many cases a callback does not cause the compiler to be overly +conservative in its effect analysis. + + +Tag tracking +------------ + +The exception tracking is part of Nim's `effect system`:idx:. Raising an +exception is an *effect*. Other effects can also be defined. A user defined +effect is a means to *tag* a routine and to perform checks against this tag: + +.. code-block:: nim + type IO = object ## input/output effect + proc readLine(): string {.tags: [IO].} + + proc no_IO_please() {.tags: [].} = + # the compiler prevents this: + let x = readLine() + +A tag has to be a type name. A ``tags`` list - like a ``raises`` list - can +also be attached to a proc type. This affects type compatibility. + +The inference for tag tracking is analogous to the inference for +exception tracking. + + +Read/Write tracking +------------------- + +**Note**: Read/write tracking is not yet implemented! + +The inference for read/write tracking is analogous to the inference for +exception tracking. + + +Effects pragma +-------------- + +The ``effects`` pragma has been designed to assist the programmer with the +effects analysis. It is a statement that makes the compiler output all inferred +effects up to the ``effects``'s position: + +.. code-block:: nim + proc p(what: bool) = + if what: + raise newException(IOError, "IO") + {.effects.} + else: + raise newException(OSError, "OS") + +The compiler produces a hint message that ``IOError`` can be raised. ``OSError`` +is not listed as it cannot be raised in the branch the ``effects`` pragma +appears in. diff --git a/doc/manual/exceptions.txt b/doc/manual/exceptions.txt new file mode 100644 index 000000000..ba2ea30a0 --- /dev/null +++ b/doc/manual/exceptions.txt @@ -0,0 +1,132 @@ +Exception handling +================== + +Try statement +------------- + +Example: + +.. code-block:: nim + # read the first two lines of a text file that should contain numbers + # and tries to add them + var + f: File + if open(f, "numbers.txt"): + try: + var a = readLine(f) + var b = readLine(f) + echo("sum: " & $(parseInt(a) + parseInt(b))) + except OverflowError: + echo("overflow!") + except ValueError: + echo("could not convert string to integer") + except IOError: + echo("IO error!") + except: + echo("Unknown exception!") + finally: + close(f) + + +The statements after the ``try`` are executed in sequential order unless +an exception ``e`` is raised. If the exception type of ``e`` matches any +listed in an ``except`` clause the corresponding statements are executed. +The statements following the ``except`` clauses are called +`exception handlers`:idx:. + +The empty `except`:idx: clause is executed if there is an exception that is +not listed otherwise. It is similar to an ``else`` clause in ``if`` statements. + +If there is a `finally`:idx: clause, it is always executed after the +exception handlers. + +The exception is *consumed* in an exception handler. However, an +exception handler may raise another exception. If the exception is not +handled, it is propagated through the call stack. This means that often +the rest of the procedure - that is not within a ``finally`` clause - +is not executed (if an exception occurs). + + +Except and finally statements +----------------------------- + +``except`` and ``finally`` can also be used as a stand-alone statements. +Any statements following them in the current block will be considered to be +in an implicit try block: + +.. code-block:: nim + var f = open("numbers.txt") + finally: close(f) + ... + +The ``except`` statement has a limitation in this form: one can't specify the +type of the exception, one has to catch everything. Also, if one wants to use +both ``finally`` and ``except`` one needs to reverse the usual sequence of the +statements. Example: + +.. code-block:: nim + proc test() = + raise newException(Exception, "Hey ho") + + proc tester() = + finally: echo "3. Finally block" + except: echo "2. Except block" + echo "1. Pre exception" + test() + echo "4. Post exception" + # --> 1, 2, 3 is printed, 4 is never reached + + +Raise statement +--------------- + +Example: + +.. code-block:: nim + raise newEOS("operating system failed") + +Apart from built-in operations like array indexing, memory allocation, etc. +the ``raise`` statement is the only way to raise an exception. + +.. XXX document this better! + +If no exception name is given, the current exception is `re-raised`:idx:. The +`ReraiseError`:idx: exception is raised if there is no exception to +re-raise. It follows that the ``raise`` statement *always* raises an +exception (unless a raise hook has been provided). + + +onRaise builtin +--------------- + +`system.onRaise() <system.html#onRaise>`_ can be used to override the +behaviour of ``raise`` for a single ``try`` statement. ``onRaise`` has to be +called within the ``try`` statement that should be affected. + +This allows for a Lisp-like `condition system`:idx:\: + +.. code-block:: nim + var myFile = open("broken.txt", fmWrite) + try: + onRaise do (e: ref Exception)-> bool: + if e of IOError: + stdout.writeln "ok, writing to stdout instead" + else: + # do raise other exceptions: + result = true + myFile.writeln "writing to broken file" + finally: + myFile.close() + +``onRaise`` can only *filter* raised exceptions, it cannot transform one +exception into another. (Nor should ``onRaise`` raise an exception though +this is currently not enforced.) This restriction keeps the exception tracking +analysis sound. + + +Exception hierarchy +------------------- + +The exception tree is defined in the `system <system.html>`_ module: + +.. include:: exception_hierarchy_fragment.txt diff --git a/doc/manual/ffi.txt b/doc/manual/ffi.txt new file mode 100644 index 000000000..0ad4ebba9 --- /dev/null +++ b/doc/manual/ffi.txt @@ -0,0 +1,209 @@ +Foreign function interface +========================== + +Nim's `FFI`:idx: (foreign function interface) is extensive and only the +parts that scale to other future backends (like the LLVM/JavaScript backends) +are documented here. + + +Importc pragma +-------------- +The ``importc`` pragma provides a means to import a proc or a variable +from C. The optional argument is a string containing the C identifier. If +the argument is missing, the C name is the Nim identifier *exactly as +spelled*: + +.. code-block:: + proc printf(formatstr: cstring) {.header: "<stdio.h>", importc: "printf", varargs.} + +Note that this pragma is somewhat of a misnomer: Other backends will provide +the same feature under the same name. Also, if one is interfacing with C++ +the `ImportCpp pragma <nimc.html#importcpp-pragma>`_ and +interfacing with Objective-C the `ImportObjC pragma +<nimc.html#importobjc-pragma>`_ can be used. + + +Exportc pragma +-------------- +The ``exportc`` pragma provides a means to export a type, a variable, or a +procedure to C. Enums and constants can't be exported. The optional argument +is a string containing the C identifier. If the argument is missing, the C +name is the Nim identifier *exactly as spelled*: + +.. code-block:: Nim + proc callme(formatstr: cstring) {.exportc: "callMe", varargs.} + +Note that this pragma is somewhat of a misnomer: Other backends will provide +the same feature under the same name. + + +Extern pragma +------------- +Like ``exportc`` or ``importc``, the ``extern`` pragma affects name +mangling. The string literal passed to ``extern`` can be a format string: + +.. code-block:: Nim + proc p(s: string) {.extern: "prefix$1".} = + echo s + +In the example the external name of ``p`` is set to ``prefixp``. + + +Bycopy pragma +------------- + +The ``bycopy`` pragma can be applied to an object or tuple type and +instructs the compiler to pass the type by value to procs: + +.. code-block:: nim + type + TVector {.bycopy, pure.} = object + x, y, z: float + + +Byref pragma +------------ + +The ``byref`` pragma can be applied to an object or tuple type and instructs +the compiler to pass the type by reference (hidden pointer) to procs. + + +Varargs pragma +-------------- +The ``varargs`` pragma can be applied to procedures only (and procedure +types). It tells Nim that the proc can take a variable number of parameters +after the last specified parameter. Nim string values will be converted to C +strings automatically: + +.. code-block:: Nim + proc printf(formatstr: cstring) {.nodecl, varargs.} + + printf("hallo %s", "world") # "world" will be passed as C string + + +Union pragma +------------ +The ``union`` pragma can be applied to any ``object`` type. It means all +of the object's fields are overlaid in memory. This produces a ``union`` +instead of a ``struct`` in the generated C/C++ code. The object declaration +then must not use inheritance or any GC'ed memory but this is currently not +checked. + +**Future directions**: GC'ed memory should be allowed in unions and the GC +should scan unions conservatively. + +Packed pragma +------------- +The ``packed`` pragma can be applied to any ``object`` type. It ensures +that the fields of an object are packed back-to-back in memory. It is useful +to store packets or messages from/to network or hardware drivers, and for +interoperability with C. Combining packed pragma with inheritance is not +defined, and it should not be used with GC'ed memory (ref's). + +**Future directions**: Using GC'ed memory in packed pragma will result in +compile-time error. Usage with inheritance should be defined and documented. + +Unchecked pragma +---------------- +The ``unchecked`` pragma can be used to mark a named array as ``unchecked`` +meaning its bounds are not checked. This is often useful when one wishes to +implement his own flexibly sized arrays. Additionally an unchecked array is +translated into a C array of undetermined size: + +.. code-block:: nim + type + ArrayPart{.unchecked.} = array[0..0, int] + MySeq = object + len, cap: int + data: ArrayPart + +Produces roughly this C code: + +.. code-block:: C + typedef struct { + NI len; + NI cap; + NI data[]; + } MySeq; + +The bounds checking done at compile time is not disabled for now, so to access +``s.data[C]`` (where ``C`` is a constant) the array's index needs needs to +include ``C``. + +The base type of the unchecked array may not contain any GC'ed memory but this +is currently not checked. + +**Future directions**: GC'ed memory should be allowed in unchecked arrays and +there should be an explicit annotation of how the GC is to determine the +runtime size of the array. + + +Dynlib pragma for import +------------------------ +With the ``dynlib`` pragma a procedure or a variable can be imported from +a dynamic library (``.dll`` files for Windows, ``lib*.so`` files for UNIX). +The non-optional argument has to be the name of the dynamic library: + +.. code-block:: Nim + proc gtk_image_new(): PGtkWidget + {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.} + +In general, importing a dynamic library does not require any special linker +options or linking with import libraries. This also implies that no *devel* +packages need to be installed. + +The ``dynlib`` import mechanism supports a versioning scheme: + +.. code-block:: nim + proc Tcl_Eval(interp: pTcl_Interp, script: cstring): int {.cdecl, + importc, dynlib: "libtcl(|8.5|8.4|8.3).so.(1|0)".} + +At runtime the dynamic library is searched for (in this order):: + + libtcl.so.1 + libtcl.so.0 + libtcl8.5.so.1 + libtcl8.5.so.0 + libtcl8.4.so.1 + libtcl8.4.so.0 + libtcl8.3.so.1 + libtcl8.3.so.0 + +The ``dynlib`` pragma supports not only constant strings as argument but also +string expressions in general: + +.. code-block:: nim + import os + + proc getDllName: string = + result = "mylib.dll" + if existsFile(result): return + result = "mylib2.dll" + if existsFile(result): return + quit("could not load dynamic library") + + proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().} + +**Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant +strings, because they are precompiled. + +**Note**: Passing variables to the ``dynlib`` pragma will fail at runtime +because of order of initialization problems. + +**Note**: A ``dynlib`` import can be overriden with +the ``--dynlibOverride:name`` command line option. The Compiler User Guide +contains further information. + + +Dynlib pragma for export +------------------------ + +With the ``dynlib`` pragma a procedure can also be exported to +a dynamic library. The pragma then has no argument and has to be used in +conjunction with the ``exportc`` pragma: + +.. code-block:: Nim + proc exportme(): int {.cdecl, exportc, dynlib.} + +This is only useful if the program is compiled as a dynamic library via the +``--app:lib`` command line option. diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt new file mode 100644 index 000000000..6f1b2ee0d --- /dev/null +++ b/doc/manual/generics.txt @@ -0,0 +1,346 @@ +Generics +======== + +Generics are Nim's means to parametrize procs, iterators or types with +`type parameters`:idx:. Depending on context, the brackets are used either to +introduce type parameters or to instantiate a generic proc, iterator or type. + +The following example shows a generic binary tree can be modelled: + +.. code-block:: nim + type + TBinaryTree[T] = object # TBinaryTree is a generic type with + # with generic param ``T`` + le, ri: ref TBinaryTree[T] # left and right subtrees; may be nil + data: T # the data stored in a node + PBinaryTree[T] = ref TBinaryTree[T] # a shorthand for notational convenience + + proc newNode[T](data: T): PBinaryTree[T] = # constructor for a node + new(result) + result.data = data + + proc add[T](root: var PBinaryTree[T], n: PBinaryTree[T]) = + if root == nil: + root = n + else: + var it = root + while it != nil: + var c = cmp(it.data, n.data) # compare the data items; uses + # the generic ``cmp`` proc that works for + # any type that has a ``==`` and ``<`` + # operator + if c < 0: + if it.le == nil: + it.le = n + return + it = it.le + else: + if it.ri == nil: + it.ri = n + return + it = it.ri + + iterator inorder[T](root: PBinaryTree[T]): T = + # inorder traversal of a binary tree + # recursive iterators are not yet implemented, so this does not work in + # the current compiler! + if root.le != nil: yield inorder(root.le) + yield root.data + if root.ri != nil: yield inorder(root.ri) + + var + root: PBinaryTree[string] # instantiate a PBinaryTree with the type string + add(root, newNode("hallo")) # instantiates generic procs ``newNode`` and + add(root, newNode("world")) # ``add`` + for str in inorder(root): + writeln(stdout, str) + + +Is operator +----------- + +The ``is`` operator checks for type equivalence at compile time. It is +therefore very useful for type specialization within generic code: + +.. code-block:: nim + type + TTable[TKey, TValue] = object + keys: seq[TKey] + values: seq[TValue] + when not (TKey is string): # nil value for strings used for optimization + deletedKeys: seq[bool] + + +Type operator +------------- + +The ``type`` (in many other languages called `typeof`:idx:) operator can +be used to get the type of an expression: + +.. code-block:: nim + var x = 0 + var y: type(x) # y has type int + +If ``type`` is used to determine the result type of a proc/iterator/converter +call ``c(X)`` (where ``X`` stands for a possibly empty list of arguments), the +interpretation where ``c`` is an iterator is preferred over the +other interpretations: + +.. code-block:: nim + import strutils + + # strutils contains both a ``split`` proc and iterator, but since an + # an iterator is the preferred interpretation, `y` has the type ``string``: + var y: type("a b c".split) + + +Type Classes +------------ + +A type class is a special pseudo-type that can be used to match against +types in the context of overload resolution or the ``is`` operator. +Nim supports the following built-in type classes: + +================== =================================================== +type class matches +================== =================================================== +``object`` any object type +``tuple`` any tuple type + +``enum`` any enumeration +``proc`` any proc type +``ref`` any ``ref`` type +``ptr`` any ``ptr`` type +``var`` any ``var`` type +``distinct`` any distinct type +``array`` any array type +``set`` any set type +``seq`` any seq type +``auto`` any type +================== =================================================== + +Furthermore, every generic type automatically creates a type class of the same +name that will match any instantiation of the generic type. + +Type classes can be combined using the standard boolean operators to form +more complex type classes: + +.. code-block:: nim + # create a type class that will match all tuple and object types + type TRecordType = tuple or object + + proc printFields(rec: TRecordType) = + for key, value in fieldPairs(rec): + echo key, " = ", value + +Procedures utilizing type classes in such manner are considered to be +`implicitly generic`:idx:. They will be instantiated once for each unique +combination of param types used within the program. + +Nim also allows for type classes and regular types to be specified +as `type constraints`:idx: of the generic type parameter: + +.. code-block:: nim + proc onlyIntOrString[T: int|string](x, y: T) = discard + + onlyIntOrString(450, 616) # valid + onlyIntOrString(5.0, 0.0) # type mismatch + onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time + +By default, during overload resolution each named type class will bind to +exactly one concrete type. Here is an example taken directly from the system +module to illustrate this: + +.. code-block:: nim + proc `==`*(x, y: tuple): bool = + ## requires `x` and `y` to be of the same tuple type + ## generic ``==`` operator for tuples that is lifted from the components + ## of `x` and `y`. + result = true + for a, b in fields(x, y): + if a != b: result = false + +Alternatively, the ``distinct`` type modifier can be applied to the type class +to allow each param matching the type class to bind to a different type. + +If a proc param doesn't have a type specified, Nim will use the +``distinct auto`` type class (also known as ``any``): + +.. code-block:: nim + # allow any combination of param types + proc concat(a, b): string = $a & $b + +Procs written with the implicitly generic style will often need to refer to the +type parameters of the matched generic type. They can be easily accessed using +the dot syntax: + +.. code-block:: nim + type TMatrix[T, Rows, Columns] = object + ... + + proc `[]`(m: TMatrix, row, col: int): TMatrix.T = + m.data[col * high(TMatrix.Columns) + row] + +Alternatively, the `type` operator can be used over the proc params for similar +effect when anonymous or distinct type classes are used. + +When a generic type is instantiated with a type class instead of a concrete +type, this results in another more specific type class: + +.. code-block:: nim + seq[ref object] # Any sequence storing references to any object type + + type T1 = auto + proc foo(s: seq[T1], e: T1) + # seq[T1] is the same as just `seq`, but T1 will be allowed to bind + # to a single type, while the signature is being matched + + TMatrix[Ordinal] # Any TMatrix instantiation using integer values + +As seen in the previous example, in such instantiations, it's not necessary to +supply all type parameters of the generic type, because any missing ones will +be inferred to have the equivalent of the `any` type class and thus they will +match anything without discrimination. + + +User defined type classes +------------------------- + +**Note**: User defined type classes are still in development. + +The user-defined type classes are available in two flavours - declarative and +imperative. Both are used to specify an arbitrary set of requirements that the +matched type must satisfy. + +Declarative type classes are written in the following form: + +.. code-block:: nim + type + Comparable = generic x, y + (x < y) is bool + + Container[T] = generic c + c.len is ordinal + items(c) is iterator + for value in c: + type(value) is T + +The type class will be matched if: + +a) all of the expressions within the body can be compiled for the tested type +b) all statically evaluatable boolean expressions in the body must be true + +The identifiers following the `generic` keyword represent instances of the +currently matched type. These instances can act both as variables of the type, +when used in contexts where a value is expected, and as the type itself when +used in contexts where a type is expected. + +Please note that the ``is`` operator allows one to easily verify the precise +type signatures of the required operations, but since type inference and +default parameters are still applied in the provided block, it's also possible +to encode usage protocols that do not reveal implementation details. + +As a special rule providing further convenience when writing type classes, any +type value appearing in a callable expression will be treated as a variable of +the designated type for overload resolution purposes, unless the type value was +passed in its explicit ``typedesc[T]`` form: + +.. code-block:: nim + type + OutputStream = generic S + write(var S, string) + +Much like generics, the user defined type classes will be instantiated exactly +once for each tested type and any static code included within them will also be +executed once. + + +Type inference with type classes +-------------------------------- + +If a type class is used as the return type of a proc and it won't be bound to +a concrete type by some of the proc params, Nim will infer the return type +from the proc body. This is usually used with the ``auto`` type class: + +.. code-block:: nim + proc makePair(a, b): auto = (first: a, second: b) + +The return type will be treated as an additional generic param and can be +explicitly specified at call sites as any other generic param. + +Future versions of Nim may also support overloading based on the return type +of the overloads. In such settings, the expected result type at call sites may +also influence the inferred return type. + +.. + Likewise, if a type class is used in another position where Nim expects a + concrete type (e.g. a variable declaration or a type coercion), Nim will try + to infer the concrete type by applying the matching algorithm that also used + in overload resolution. + + +Symbol lookup in generics +------------------------- + +The symbol binding rules in generics are slightly subtle: There are "open" and +"closed" symbols. A "closed" symbol cannot be re-bound in the instantiation +context, an "open" symbol can. Per default overloaded symbols are open +and every other symbol is closed. + +Open symbols are looked up in two different contexts: Both the context +at definition and the context at instantiation are considered: + +.. code-block:: nim + type + TIndex = distinct int + + proc `==` (a, b: TIndex): bool {.borrow.} + + var a = (0, 0.TIndex) + var b = (0, 0.TIndex) + + echo a == b # works! + +In the example the generic ``==`` for tuples (as defined in the system module) +uses the ``==`` operators of the tuple's components. However, the ``==`` for +the ``TIndex`` type is defined *after* the ``==`` for tuples; yet the example +compiles as the instantiation takes the currently defined symbols into account +too. + +A symbol can be forced to be open by a `mixin`:idx: declaration: + +.. code-block:: nim + proc create*[T](): ref T = + # there is no overloaded 'init' here, so we need to state that it's an + # open symbol explicitly: + mixin init + new result + init result + + +Bind statement +-------------- + +The ``bind`` statement is the counterpart to the ``mixin`` statement. It +can be used to explicitly declare identifiers that should be bound early (i.e. +the identifiers should be looked up in the scope of the template/generic +definition): + +.. code-block:: nim + # Module A + var + lastId = 0 + + template genId*: expr = + bind lastId + inc(lastId) + lastId + +.. code-block:: nim + # Module B + import A + + echo genId() + +But a ``bind`` is rarely useful because symbol binding from the definition +scope is the default. diff --git a/doc/manual/lexing.txt b/doc/manual/lexing.txt new file mode 100644 index 000000000..c3894b13d --- /dev/null +++ b/doc/manual/lexing.txt @@ -0,0 +1,356 @@ +Lexical Analysis +================ + +Encoding +-------- + +All Nim source files are in the UTF-8 encoding (or its ASCII subset). Other +encodings are not supported. Any of the standard platform line termination +sequences can be used - the Unix form using ASCII LF (linefeed), the Windows +form using the ASCII sequence CR LF (return followed by linefeed), or the old +Macintosh form using the ASCII CR (return) character. All of these forms can be +used equally, regardless of platform. + + +Indentation +----------- + +Nim's standard grammar describes an `indentation sensitive`:idx: language. +This means that all the control structures are recognized by indentation. +Indentation consists only of spaces; tabulators are not allowed. + +The indentation handling is implemented as follows: The lexer annotates the +following token with the preceding number of spaces; indentation is not +a separate token. This trick allows parsing of Nim with only 1 token of +lookahead. + +The parser uses a stack of indentation levels: the stack consists of integers +counting the spaces. The indentation information is queried at strategic +places in the parser but ignored otherwise: The pseudo terminal ``IND{>}`` +denotes an indentation that consists of more spaces than the entry at the top +of the stack; IND{=} an indentation that has the same number of spaces. ``DED`` +is another pseudo terminal that describes the *action* of popping a value +from the stack, ``IND{>}`` then implies to push onto the stack. + +With this notation we can now easily define the core of the grammar: A block of +statements (simplified example):: + + ifStmt = 'if' expr ':' stmt + (IND{=} 'elif' expr ':' stmt)* + (IND{=} 'else' ':' stmt)? + + simpleStmt = ifStmt / ... + + stmt = IND{>} stmt ^+ IND{=} DED # list of statements + / simpleStmt # or a simple statement + + + +Comments +-------- + +Comments start anywhere outside a string or character literal with the +hash character ``#``. +Comments consist of a concatenation of `comment pieces`:idx:. A comment piece +starts with ``#`` and runs until the end of the line. The end of line characters +belong to the piece. If the next line only consists of a comment piece with +no other tokens between it and the preceding one, it does not start a new +comment: + + +.. code-block:: nim + i = 0 # This is a single comment over multiple lines. + # The scanner merges these two pieces. + # The comment continues here. + + +`Documentation comments`:idx: are comments that start with two ``##``. +Documentation comments are tokens; they are only allowed at certain places in +the input file as they belong to the syntax tree! + + +Identifiers & Keywords +---------------------- + +Identifiers in Nim can be any string of letters, digits +and underscores, beginning with a letter. Two immediate following +underscores ``__`` are not allowed:: + + letter ::= 'A'..'Z' | 'a'..'z' | '\x80'..'\xff' + digit ::= '0'..'9' + IDENTIFIER ::= letter ( ['_'] (letter | digit) )* + +Currently any unicode character with an ordinal value > 127 (non ASCII) is +classified as a ``letter`` and may thus be part of an identifier but later +versions of the language may assign some Unicode characters to belong to the +operator characters instead. + +The following keywords are reserved and cannot be used as identifiers: + +.. code-block:: nim + :file: keywords.txt + +Some keywords are unused; they are reserved for future developments of the +language. + +Nim is a `style-insensitive`:idx: language. This means that it is not +case-sensitive and even underscores are ignored: +**type** is a reserved word, and so is **TYPE** or **T_Y_P_E**. The idea behind +this is that this allows programmers to use their own preferred spelling style +and libraries written by different programmers cannot use incompatible +conventions. A Nim-aware editor or IDE can show the identifiers as +preferred. Another advantage is that it frees the programmer from remembering +the exact spelling of an identifier. + + +String literals +--------------- + +Terminal symbol in the grammar: ``STR_LIT``. + +String literals can be delimited by matching double quotes, and can +contain the following `escape sequences`:idx:\ : + +================== =================================================== + Escape sequence Meaning +================== =================================================== + ``\n`` `newline`:idx: + ``\r``, ``\c`` `carriage return`:idx: + ``\l`` `line feed`:idx: + ``\f`` `form feed`:idx: + ``\t`` `tabulator`:idx: + ``\v`` `vertical tabulator`:idx: + ``\\`` `backslash`:idx: + ``\"`` `quotation mark`:idx: + ``\'`` `apostrophe`:idx: + ``\`` '0'..'9'+ `character with decimal value d`:idx:; + all decimal digits directly + following are used for the character + ``\a`` `alert`:idx: + ``\b`` `backspace`:idx: + ``\e`` `escape`:idx: `[ESC]`:idx: + ``\x`` HH `character with hex value HH`:idx:; + exactly two hex digits are allowed +================== =================================================== + + +Strings in Nim may contain any 8-bit value, even embedded zeros. However +some operations may interpret the first binary zero as a terminator. + + +Triple quoted string literals +----------------------------- + +Terminal symbol in the grammar: ``TRIPLESTR_LIT``. + +String literals can also be delimited by three double quotes +``"""`` ... ``"""``. +Literals in this form may run for several lines, may contain ``"`` and do not +interpret any escape sequences. +For convenience, when the opening ``"""`` is followed by a newline (there may +be whitespace between the opening ``"""`` and the newline), +the newline (and the preceding whitespace) is not included in the string. The +ending of the string literal is defined by the pattern ``"""[^"]``, so this: + +.. code-block:: nim + """"long string within quotes"""" + +Produces:: + + "long string within quotes" + + +Raw string literals +------------------- + +Terminal symbol in the grammar: ``RSTR_LIT``. + +There are also raw string literals that are preceded with the +letter ``r`` (or ``R``) and are delimited by matching double quotes (just +like ordinary string literals) and do not interpret the escape sequences. +This is especially convenient for regular expressions or Windows paths: + +.. code-block:: nim + + var f = openFile(r"C:\texts\text.txt") # a raw string, so ``\t`` is no tab + +To produce a single ``"`` within a raw string literal, it has to be doubled: + +.. code-block:: nim + + r"a""b" + +Produces:: + + a"b + +``r""""`` is not possible with this notation, because the three leading +quotes introduce a triple quoted string literal. ``r"""`` is the same +as ``"""`` since triple quoted string literals do not interpret escape +sequences either. + + +Generalized raw string literals +------------------------------- + +Terminal symbols in the grammar: ``GENERALIZED_STR_LIT``, +``GENERALIZED_TRIPLESTR_LIT``. + +The construct ``identifier"string literal"`` (without whitespace between the +identifier and the opening quotation mark) is a +generalized raw string literal. It is a shortcut for the construct +``identifier(r"string literal")``, so it denotes a procedure call with a +raw string literal as its only argument. Generalized raw string literals +are especially convenient for embedding mini languages directly into Nim +(for example regular expressions). + +The construct ``identifier"""string literal"""`` exists too. It is a shortcut +for ``identifier("""string literal""")``. + + +Character literals +------------------ + +Character literals are enclosed in single quotes ``''`` and can contain the +same escape sequences as strings - with one exception: `newline`:idx: (``\n``) +is not allowed as it may be wider than one character (often it is the pair +CR/LF for example). Here are the valid `escape sequences`:idx: for character +literals: + +================== =================================================== + Escape sequence Meaning +================== =================================================== + ``\r``, ``\c`` `carriage return`:idx: + ``\l`` `line feed`:idx: + ``\f`` `form feed`:idx: + ``\t`` `tabulator`:idx: + ``\v`` `vertical tabulator`:idx: + ``\\`` `backslash`:idx: + ``\"`` `quotation mark`:idx: + ``\'`` `apostrophe`:idx: + ``\`` '0'..'9'+ `character with decimal value d`:idx:; + all decimal digits directly + following are used for the character + ``\a`` `alert`:idx: + ``\b`` `backspace`:idx: + ``\e`` `escape`:idx: `[ESC]`:idx: + ``\x`` HH `character with hex value HH`:idx:; + exactly two hex digits are allowed +================== =================================================== + +A character is not an Unicode character but a single byte. The reason for this +is efficiency: for the overwhelming majority of use-cases, the resulting +programs will still handle UTF-8 properly as UTF-8 was specially designed for +this. Another reason is that Nim can thus support ``array[char, int]`` or +``set[char]`` efficiently as many algorithms rely on this feature. The `TRune` +type is used for Unicode characters, it can represent any Unicode character. +``TRune`` is declared in the `unicode module <unicode.html>`_. + + +Numerical constants +------------------- + +Numerical constants are of a single type and have the form:: + + hexdigit = digit | 'A'..'F' | 'a'..'f' + octdigit = '0'..'7' + bindigit = '0'..'1' + HEX_LIT = '0' ('x' | 'X' ) hexdigit ( ['_'] hexdigit )* + DEC_LIT = digit ( ['_'] digit )* + OCT_LIT = '0o' octdigit ( ['_'] octdigit )* + BIN_LIT = '0' ('b' | 'B' ) bindigit ( ['_'] bindigit )* + + INT_LIT = HEX_LIT + | DEC_LIT + | OCT_LIT + | BIN_LIT + + INT8_LIT = INT_LIT ['\''] ('i' | 'I') '8' + INT16_LIT = INT_LIT ['\''] ('i' | 'I') '16' + INT32_LIT = INT_LIT ['\''] ('i' | 'I') '32' + INT64_LIT = INT_LIT ['\''] ('i' | 'I') '64' + + UINT8_LIT = INT_LIT ['\''] ('u' | 'U') + UINT8_LIT = INT_LIT ['\''] ('u' | 'U') '8' + UINT16_LIT = INT_LIT ['\''] ('u' | 'U') '16' + UINT32_LIT = INT_LIT ['\''] ('u' | 'U') '32' + UINT64_LIT = INT_LIT ['\''] ('u' | 'U') '64' + + exponent = ('e' | 'E' ) ['+' | '-'] digit ( ['_'] digit )* + FLOAT_LIT = digit (['_'] digit)* (('.' (['_'] digit)* [exponent]) |exponent) + FLOAT32_LIT = HEX_LIT '\'' ('f'|'F') '32' + | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '32' + FLOAT64_LIT = HEX_LIT '\'' ('f'|'F') '64' + | (FLOAT_LIT | DEC_LIT | OCT_LIT | BIN_LIT) ['\''] ('f'|'F') '64' + + +As can be seen in the productions, numerical constants can contain underscores +for readability. Integer and floating point literals may be given in decimal (no +prefix), binary (prefix ``0b``), octal (prefix ``0o``) and hexadecimal +(prefix ``0x``) notation. + +There exists a literal for each numerical type that is +defined. The suffix starting with an apostrophe ('\'') is called a +`type suffix`:idx:. Literals without a type suffix are of the type ``int``, +unless the literal contains a dot or ``E|e`` in which case it is of +type ``float``. For notational convenience the apostrophe of a type suffix +is optional if it is not ambiguous (only hexadecimal floating point literals +with a type suffix can be ambiguous). + + +The type suffixes are: + +================= ========================= + Type Suffix Resulting type of literal +================= ========================= + ``'i8`` int8 + ``'i16`` int16 + ``'i32`` int32 + ``'i64`` int64 + ``'u`` uint + ``'u8`` uint8 + ``'u16`` uint16 + ``'u32`` uint32 + ``'u64`` uint64 + ``'f32`` float32 + ``'f64`` float64 +================= ========================= + +Floating point literals may also be in binary, octal or hexadecimal +notation: +``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64`` +is approximately 1.72826e35 according to the IEEE floating point standard. + + +Operators +--------- + +In Nim one can define his own operators. An operator is any +combination of the following characters:: + + = + - * / < > + @ $ ~ & % | + ! ? ^ . : \ + +These keywords are also operators: +``and or not xor shl shr div mod in notin is isnot of``. + +`=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they +are used for other notational purposes. + +``*:`` is as a special case the two tokens `*`:tok: and `:`:tok: +(to support ``var v*: T``). + + +Other tokens +------------ + +The following strings denote other tokens:: + + ` ( ) { } [ ] , ; [. .] {. .} (. .) + + +The `slice`:idx: operator `..`:tok: takes precedence over other tokens that +contain a dot: `{..}`:tok: are the three tokens `{`:tok:, `..`:tok:, `}`:tok: +and not the two tokens `{.`:tok:, `.}`:tok:. + diff --git a/doc/manual/locking.txt b/doc/manual/locking.txt new file mode 100644 index 000000000..1a6d2783c --- /dev/null +++ b/doc/manual/locking.txt @@ -0,0 +1,199 @@ +Guards and locks +================ + +Apart from ``spawn`` and ``parallel`` Nim also provides all the common low level +concurrency mechanisms like locks, atomic intristics or condition variables. + +Nim significantly improves on the safety of these features via additional +pragmas: + +1) A `guard`:idx: annotation is introduced to prevent data races. +2) Every access of a guarded memory location needs to happen in an + appropriate `locks`:idx: statement. +3) Locks and routines can be annotated with `lock levels`:idx: to prevent + deadlocks at compile time. + +Guards and the locks section +---------------------------- + +Protecting global variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Object fields and global variables can be annotated via a ``guard`` pragma: + +.. code-block:: nim + var glock: TLock + var gdata {.guard: glock.}: int + +The compiler then ensures that every access of ``gdata`` is within a ``locks`` +section: + +.. code-block:: nim + proc invalid = + # invalid: unguarded access: + echo gdata + + proc valid = + # valid access: + {.locks: [glock].}: + echo gdata + +Top level accesses to ``gdata`` are always allowed so that it can be initialized +conveniently. It is *assumed* (but not enforced) that every top level statement +is executed before any concurrent action happens. + +The ``locks`` section deliberately looks ugly because it has no runtime +semantics and should not be used directly! It should only be used in templates +that also implement some form of locking at runtime: + +.. code-block:: nim + template lock(a: TLock; body: stmt) = + pthread_mutex_lock(a) + {.locks: [a].}: + try: + body + finally: + pthread_mutex_unlock(a) + + +The guard does not need to be of any particular type. It is flexible enough to +model low level lockfree mechanisms: + +.. code-block:: nim + var dummyLock {.compileTime.}: int + var atomicCounter {.guard: dummyLock.}: int + + template atomicRead(x): expr = + {.locks: [dummyLock].}: + memoryReadBarrier() + x + + echo atomicRead(atomicCounter) + + +The ``locks`` pragma takes a list of lock expressions ``locks: [a, b, ...]`` +in order to support *multi lock* statements. Why these are essential is +explained in the `lock levels`_ section. + + +Protecting general locations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``guard`` annotation can also be used to protect fields within an object. +The guard then needs to be another field within the same object or a +global variable. + +Since objects can reside on the heap or on the stack this greatly enhances the +expressivity of the language: + +.. code-block:: nim + type + ProtectedCounter = object + v {.guard: L.}: int + L: TLock + + proc incCounters(counters: var openArray[ProtectedCounter]) = + for i in 0..counters.high: + lock counters[i].L: + inc counters[i].v + +The access to field ``x.v`` is allowed since its guard ``x.L`` is active. +After template expansion, this amounts to: + +.. code-block:: nim + proc incCounters(counters: var openArray[ProtectedCounter]) = + for i in 0..counters.high: + pthread_mutex_lock(counters[i].L) + {.locks: [counters[i].L].}: + try: + inc counters[i].v + finally: + pthread_mutex_unlock(counters[i].L) + +There is an analysis that checks that ``counters[i].L`` is the lock that +corresponds to the protected location ``counters[i].v``. This analysis is called +`path analysis`:idx: because it deals with paths to locations +like ``obj.field[i].fieldB[j]``. + +The path analysis is **currently unsound**, but that doesn't make it useless. +Two paths are considered equivalent if they are syntactically the same. + +This means the following compiles (for now) even though it really should not: + +.. code-block:: nim + {.locks: [a[i].L].}: + inc i + access a[i].v + + + +Lock levels +----------- + +Lock levels are used to enforce a global locking order in order to prevent +deadlocks at compile-time. A lock level is an constant integer in the range +0..1_000. Lock level 0 means that no lock is acquired at all. + +If a section of code holds a lock of level ``M`` than it can also acquire any +lock of level ``N < M``. Another lock of level ``M`` cannot be acquired. Locks +of the same level can only be acquired *at the same time* within a +single ``locks`` section: + +.. code-block:: nim + var a, b: TLock[2] + var x: TLock[1] + # invalid locking order: TLock[1] cannot be acquired before TLock[2]: + {.locks: [x].}: + {.locks: [a].}: + ... + # valid locking order: TLock[2] acquired before TLock[1]: + {.locks: [a].}: + {.locks: [x].}: + ... + + # invalid locking order: TLock[2] acquired before TLock[2]: + {.locks: [a].}: + {.locks: [b].}: + ... + + # valid locking order, locks of the same level acquired at the same time: + {.locks: [a, b].}: + ... + + +Here is how a typical multilock statement can be implemented in Nim. Note how +the runtime check is required to ensure a global ordering for two locks ``a`` +and ``b`` of the same lock level: + +.. code-block:: nim + template multilock(a, b: ptr TLock; body: stmt) = + if cast[ByteAddress](a) < cast[ByteAddress](b): + pthread_mutex_lock(a) + pthread_mutex_lock(b) + else: + pthread_mutex_lock(b) + pthread_mutex_lock(a) + {.locks: [a, b].}: + try: + body + finally: + pthread_mutex_unlock(a) + pthread_mutex_unlock(b) + + +Whole routines can also be annotated with a ``locks`` pragma that takes a lock +level. This then means that the routine may acquire locks of up to this level. +This is essential so that procs can be called within a ``locks`` section: + +.. code-block:: nim + proc p() {.locks: 3.} = discard + + var a: TLock[4] + {.locks: [a].}: + # p's locklevel (3) is strictly less than a's (4) so the call is allowed: + p() + + +As usual ``locks`` is an inferred effect and there is a subtype +relation: ``proc () {.locks: N.}`` is a subtype of ``proc () {.locks: M.}`` +iff (M <= N). diff --git a/doc/manual/modules.txt b/doc/manual/modules.txt new file mode 100644 index 000000000..f412587db --- /dev/null +++ b/doc/manual/modules.txt @@ -0,0 +1,185 @@ +Modules +======= +Nim supports splitting a program into pieces by a module concept. +Each module needs to be in its own file and has its own `namespace`:idx:. +Modules enable `information hiding`:idx: and `separate compilation`:idx:. +A module may gain access to symbols of another module by the `import`:idx: +statement. `Recursive module dependencies`:idx: are allowed, but slightly +subtle. Only top-level symbols that are marked with an asterisk (``*``) are +exported. + +The algorithm for compiling modules is: + +- compile the whole module as usual, following import statements recursively + +- if there is a cycle only import the already parsed symbols (that are + exported); if an unknown identifier occurs then abort + +This is best illustrated by an example: + +.. code-block:: nim + # Module A + type + T1* = int # Module A exports the type ``T1`` + import B # the compiler starts parsing B + + proc main() = + var i = p(3) # works because B has been parsed completely here + + main() + + +.. code-block:: nim + # Module B + import A # A is not parsed here! Only the already known symbols + # of A are imported. + + proc p*(x: A.T1): A.T1 = + # this works because the compiler has already + # added T1 to A's interface symbol table + result = x + 1 + + +Import statement +~~~~~~~~~~~~~~~~ + +After the ``import`` statement a list of module names can follow or a single +module name followed by an ``except`` to prevent some symbols to be imported: + +.. code-block:: nim + import strutils except `%` + + # doesn't work then: + echo "$1" % "abc" + + +Module names in imports +~~~~~~~~~~~~~~~~~~~~~~~ + +A module alias can be introduced via the ``as`` keyword: + +.. code-block:: nim + import strutils as su, sequtils as qu + + echo su.format("$1", "lalelu") + +The original module name is then not accessible. The +notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"`` +can be used to refer to a module in subdirectories: + +.. code-block:: nim + import lib.pure.strutils, lib/pure/os, "lib/pure/times" + +Note that the module name is still ``strutils`` and not ``lib.pure.strutils`` +and so one **cannot** do: + +.. code-block:: nim + import lib.pure.strutils + echo lib.pure.strutils + +Likewise the following does not make sense as the name is ``strutils`` already: + +.. code-block:: nim + import lib.pure.strutils as strutils + + +From import statement +~~~~~~~~~~~~~~~~~~~~~ + +After the ``from`` statement a module name follows followed by +an ``import`` to list the symbols one likes to use without explict +full qualification: + +.. code-block:: nim + from strutils import `%` + + echo "$1" % "abc" + # always possible: full qualification: + echo strutils.replace("abc", "a", "z") + +It's also possible to use ``from module import nil`` if one wants to import +the module but wants to enforce fully qualified access to every symbol +in ``module``. + + +Export statement +~~~~~~~~~~~~~~~~ + +An ``export`` statement can be used for symbol fowarding so that client +modules don't need to import a module's dependencies: + +.. code-block:: nim + # module B + type TMyObject* = object + +.. code-block:: nim + # module A + import B + export B.TMyObject + + proc `$`*(x: TMyObject): string = "my object" + + +.. code-block:: nim + # module C + import A + + # B.TMyObject has been imported implicitly here: + var x: TMyObject + echo($x) + + +Scope rules +----------- +Identifiers are valid from the point of their declaration until the end of +the block in which the declaration occurred. The range where the identifier +is known is the scope of the identifier. The exact scope of an +identifier depends on the way it was declared. + +Block scope +~~~~~~~~~~~ +The *scope* of a variable declared in the declaration part of a block +is valid from the point of declaration until the end of the block. If a +block contains a second block, in which the identifier is redeclared, +then inside this block, the second declaration will be valid. Upon +leaving the inner block, the first declaration is valid again. An +identifier cannot be redefined in the same block, except if valid for +procedure or iterator overloading purposes. + + +Tuple or object scope +~~~~~~~~~~~~~~~~~~~~~ +The field identifiers inside a tuple or object definition are valid in the +following places: + +* To the end of the tuple/object definition. +* Field designators of a variable of the given tuple/object type. +* In all descendant types of the object type. + +Module scope +~~~~~~~~~~~~ +All identifiers of a module are valid from the point of declaration until +the end of the module. Identifiers from indirectly dependent modules are *not* +available. The `system`:idx: module is automatically imported in every other +module. + +If a module imports an identifier by two different modules, each occurrence of +the identifier has to be qualified, unless it is an overloaded procedure or +iterator in which case the overloading resolution takes place: + +.. code-block:: nim + # Module A + var x*: string + +.. code-block:: nim + # Module B + var x*: int + +.. code-block:: nim + # Module C + import A, B + write(stdout, x) # error: x is ambiguous + write(stdout, A.x) # no error: qualifier used + + var x = 4 + write(stdout, x) # not ambiguous: uses the module C's x diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt new file mode 100644 index 000000000..1a19cb129 --- /dev/null +++ b/doc/manual/pragmas.txt @@ -0,0 +1,477 @@ +Pragmas +======= + +Pragmas are Nim's method to give the compiler additional information / +commands without introducing a massive number of new keywords. Pragmas are +processed on the fly during semantic checking. Pragmas are enclosed in the +special ``{.`` and ``.}`` curly brackets. Pragmas are also often used as a +first implementation to play with a language feature before a nicer syntax +to access the feature becomes available. + + +noSideEffect pragma +------------------- +The ``noSideEffect`` pragma is used to mark a proc/iterator to have no side +effects. This means that the proc/iterator only changes locations that are +reachable from its parameters and the return value only depends on the +arguments. If none of its parameters have the type ``var T`` +or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static +error to mark a proc/iterator to have no side effect if the compiler cannot +verify this. + +As a special semantic rule, the built-in `debugEcho <system.html#debugEcho>`_ +pretends to be free of side effects, so that it can be used for debugging +routines marked as ``noSideEffect``. + +**Future directions**: ``func`` may become a keyword and syntactic sugar for a +proc with no side effects: + +.. code-block:: nim + func `+` (x, y: int): int + + +destructor pragma +----------------- + +The ``destructor`` pragma is used to mark a proc to act as a type destructor. +Its usage is deprecated, use the ``override`` pragma instead. +See `type bound operations`_. + + +override pragma +--------------- + +See `type bound operations`_ instead. + +procvar pragma +-------------- +The ``procvar`` pragma is used to mark a proc that it can be passed to a +procedural variable. + + +compileTime pragma +------------------ +The ``compileTime`` pragma is used to mark a proc to be used at compile +time only. No code will be generated for it. Compile time procs are useful +as helpers for macros. + + +noReturn pragma +--------------- +The ``noreturn`` pragma is used to mark a proc that never returns. + + +acyclic pragma +-------------- +The ``acyclic`` pragma can be used for object types to mark them as acyclic +even though they seem to be cyclic. This is an **optimization** for the garbage +collector to not consider objects of this type as part of a cycle: + +.. code-block:: nim + type + PNode = ref TNode + TNode {.acyclic, final.} = object + left, right: PNode + data: string + +In the example a tree structure is declared with the ``TNode`` type. Note that +the type definition is recursive and the GC has to assume that objects of +this type may form a cyclic graph. The ``acyclic`` pragma passes the +information that this cannot happen to the GC. If the programmer uses the +``acyclic`` pragma for data types that are in reality cyclic, the GC may leak +memory, but nothing worse happens. + +**Future directions**: The ``acyclic`` pragma may become a property of a +``ref`` type: + +.. code-block:: nim + type + PNode = acyclic ref TNode + TNode = object + left, right: PNode + data: string + + +final pragma +------------ +The ``final`` pragma can be used for an object type to specify that it +cannot be inherited from. + + +shallow pragma +-------------- +The ``shallow`` pragma affects the semantics of a type: The compiler is +allowed to make a shallow copy. This can cause serious semantic issues and +break memory safety! However, it can speed up assignments considerably, +because the semantics of Nim require deep copying of sequences and strings. +This can be expensive, especially if sequences are used to build a tree +structure: + +.. code-block:: nim + type + TNodeKind = enum nkLeaf, nkInner + TNode {.final, shallow.} = object + case kind: TNodeKind + of nkLeaf: + strVal: string + of nkInner: + children: seq[TNode] + + +pure pragma +----------- +An object type can be marked with the ``pure`` pragma so that its type +field which is used for runtime type identification is omitted. This used to be +necessary for binary compatibility with other compiled languages. + +An enum type can be marked as ``pure``. Then access of its fields always +requires full qualification. + + +asmNoStackFrame pragma +---------------------- +A proc can be marked with the ``AsmNoStackFrame`` pragma to tell the compiler +it should not generate a stack frame for the proc. There are also no exit +statements like ``return result;`` generated and the generated C function is +declared as ``__declspec(naked)`` or ``__attribute__((naked))`` (depending on +the used C compiler). + +**Note**: This pragma should only be used by procs which consist solely of +assembler statements. + +error pragma +------------ +The ``error`` pragma is used to make the compiler output an error message +with the given content. Compilation does not necessarily abort after an error +though. + +The ``error`` pragma can also be used to +annotate a symbol (like an iterator or proc). The *usage* of the symbol then +triggers a compile-time error. This is especially useful to rule out that some +operation is valid due to overloading and type conversions: + +.. code-block:: nim + ## check that underlying int values are compared and not the pointers: + proc `==`(x, y: ptr int): bool {.error.} + + +fatal pragma +------------ +The ``fatal`` pragma is used to make the compiler output an error message +with the given content. In contrast to the ``error`` pragma, compilation +is guaranteed to be aborted by this pragma. Example: + +.. code-block:: nim + when not defined(objc): + {.fatal: "Compile this program with the objc command!".} + +warning pragma +-------------- +The ``warning`` pragma is used to make the compiler output a warning message +with the given content. Compilation continues after the warning. + +hint pragma +----------- +The ``hint`` pragma is used to make the compiler output a hint message with +the given content. Compilation continues after the hint. + +line pragma +----------- +The ``line`` pragma can be used to affect line information of the annotated +statement as seen in stack backtraces: + +.. code-block:: nim + + template myassert*(cond: expr, msg = "") = + if not cond: + # change run-time line information of the 'raise' statement: + {.line: InstantiationInfo().}: + raise newException(EAssertionFailed, msg) + +If the ``line`` pragma is used with a parameter, the parameter needs be a +``tuple[filename: string, line: int]``. If it is used without a parameter, +``system.InstantiationInfo()`` is used. + + +linearScanEnd pragma +-------------------- +The ``linearScanEnd`` pragma can be used to tell the compiler how to +compile a Nim `case`:idx: statement. Syntactically it has to be used as a +statement: + +.. code-block:: nim + case myInt + of 0: + echo "most common case" + of 1: + {.linearScanEnd.} + echo "second most common case" + of 2: echo "unlikely: use branch table" + else: echo "unlikely too: use branch table for ", myInt + +In the example, the case branches ``0`` and ``1`` are much more common than +the other cases. Therefore the generated assembler code should test for these +values first, so that the CPU's branch predictor has a good chance to succeed +(avoiding an expensive CPU pipeline stall). The other cases might be put into a +jump table for O(1) overhead, but at the cost of a (very likely) pipeline +stall. + +The ``linearScanEnd`` pragma should be put into the last branch that should be +tested against via linear scanning. If put into the last branch of the +whole ``case`` statement, the whole ``case`` statement uses linear scanning. + + +computedGoto pragma +------------------- +The ``computedGoto`` pragma can be used to tell the compiler how to +compile a Nim `case`:idx: in a ``while true`` statement. +Syntactically it has to be used as a statement inside the loop: + +.. code-block:: nim + + type + MyEnum = enum + enumA, enumB, enumC, enumD, enumE + + proc vm() = + var instructions: array [0..100, MyEnum] + instructions[2] = enumC + instructions[3] = enumD + instructions[4] = enumA + instructions[5] = enumD + instructions[6] = enumC + instructions[7] = enumA + instructions[8] = enumB + + instructions[12] = enumE + var pc = 0 + while true: + {.computedGoto.} + let instr = instructions[pc] + case instr + of enumA: + echo "yeah A" + of enumC, enumD: + echo "yeah CD" + of enumB: + echo "yeah B" + of enumE: + break + inc(pc) + + vm() + +As the example shows ``computedGoto`` is mostly useful for interpreters. If +the underlying backend (C compiler) does not support the computed goto +extension the pragma is simply ignored. + + +unroll pragma +------------- +The ``unroll`` pragma can be used to tell the compiler that it should unroll +a `for`:idx: or `while`:idx: loop for runtime efficiency: + +.. code-block:: nim + proc searchChar(s: string, c: char): int = + for i in 0 .. s.high: + {.unroll: 4.} + if s[i] == c: return i + result = -1 + +In the above example, the search loop is unrolled by a factor 4. The unroll +factor can be left out too; the compiler then chooses an appropriate unroll +factor. + +**Note**: Currently the compiler recognizes but ignores this pragma. + + +immediate pragma +---------------- + +See `Ordinary vs immediate templates`_. + + +compilation option pragmas +-------------------------- +The listed pragmas here can be used to override the code generation options +for a proc/method/converter. + +The implementation currently provides the following possible options (various +others may be added later). + +=============== =============== ============================================ +pragma allowed values description +=============== =============== ============================================ +checks on|off Turns the code generation for all runtime + checks on or off. +boundChecks on|off Turns the code generation for array bound + checks on or off. +overflowChecks on|off Turns the code generation for over- or + underflow checks on or off. +nilChecks on|off Turns the code generation for nil pointer + checks on or off. +assertions on|off Turns the code generation for assertions + on or off. +warnings on|off Turns the warning messages of the compiler + on or off. +hints on|off Turns the hint messages of the compiler + on or off. +optimization none|speed|size Optimize the code for speed or size, or + disable optimization. +patterns on|off Turns the term rewriting templates/macros + on or off. +callconv cdecl|... Specifies the default calling convention for + all procedures (and procedure types) that + follow. +=============== =============== ============================================ + +Example: + +.. code-block:: nim + {.checks: off, optimization: speed.} + # compile without runtime checks and optimize for speed + + +push and pop pragmas +-------------------- +The `push/pop`:idx: pragmas are very similar to the option directive, +but are used to override the settings temporarily. Example: + +.. code-block:: nim + {.push checks: off.} + # compile this section without runtime checks as it is + # speed critical + # ... some code ... + {.pop.} # restore old settings + + +register pragma +--------------- +The ``register`` pragma is for variables only. It declares the variable as +``register``, giving the compiler a hint that the variable should be placed +in a hardware register for faster access. C compilers usually ignore this +though and for good reasons: Often they do a better job without it anyway. + +In highly specific cases (a dispatch loop of an bytecode interpreter for +example) it may provide benefits, though. + + +global pragma +------------- +The ``global`` pragma can be applied to a variable within a proc to instruct +the compiler to store it in a global location and initialize it once at program +startup. + +.. code-block:: nim + proc isHexNumber(s: string): bool = + var pattern {.global.} = re"[0-9a-fA-F]+" + result = s.match(pattern) + +When used within a generic proc, a separate unique global variable will be +created for each instantiation of the proc. The order of initialization of +the created global variables within a module is not defined, but all of them +will be initialized after any top-level variables in their originating module +and before any variable in a module that imports it. + +deadCodeElim pragma +------------------- +The ``deadCodeElim`` pragma only applies to whole modules: It tells the +compiler to activate (or deactivate) dead code elimination for the module the +pragma appears in. + +The ``--deadCodeElim:on`` command line switch has the same effect as marking +every module with ``{.deadCodeElim:on}``. However, for some modules such as +the GTK wrapper it makes sense to *always* turn on dead code elimination - +no matter if it is globally active or not. + +Example: + +.. code-block:: nim + {.deadCodeElim: on.} + + +.. + NoForward pragma + ---------------- + The ``noforward`` pragma can be used to turn on and off a special compilation + mode that to large extent eliminates the need for forward declarations. In this + mode, the proc definitions may appear out of order and the compiler will postpone + their semantic analysis and compilation until it actually needs to generate code + using the definitions. In this regard, this mode is similar to the modus operandi + of dynamic scripting languages, where the function calls are not resolved until + the code is executed. Here is the detailed algorithm taken by the compiler: + + 1. When a callable symbol is first encountered, the compiler will only note the + symbol callable name and it will add it to the appropriate overload set in the + current scope. At this step, it won't try to resolve any of the type expressions + used in the signature of the symbol (so they can refer to other not yet defined + symbols). + + 2. When a top level call is encountered (usually at the very end of the module), + the compiler will try to determine the actual types of all of the symbols in the + matching overload set. This is a potentially recursive process as the signatures + of the symbols may include other call expressions, whoose types will be resolved + at this point too. + + 3. Finally, after the best overload is picked, the compiler will start compiling + the body of the respective symbol. This in turn will lead the compiler to discover + more call expresions that need to be resolved and steps 2 and 3 will be repeated + as necessary. + + Please note that if a callable symbol is never used in this scenario, its body + will never be compiled. This is the default behavior leading to best compilation + times, but if exhaustive compilation of all definitions is required, using + ``nim check`` provides this option as well. + + Example: + + .. code-block:: nim + + {.noforward: on.} + + proc foo(x: int) = + bar x + + proc bar(x: int) = + echo x + + foo(10) + + +pragma pragma +------------- + +The ``pragma`` pragma can be used to declare user defined pragmas. This is +useful because Nim's templates and macros do not affect pragmas. User +defined pragmas are in a different module-wide scope than all other symbols. +They cannot be imported from a module. + +Example: + +.. code-block:: nim + when appType == "lib": + {.pragma: rtl, exportc, dynlib, cdecl.} + else: + {.pragma: rtl, importc, dynlib: "client.dll", cdecl.} + + proc p*(a, b: int): int {.rtl.} = + result = a+b + +In the example a new pragma named ``rtl`` is introduced that either imports +a symbol from a dynamic library or exports the symbol for dynamic library +generation. + + +Disabling certain messages +-------------------------- +Nim generates some warnings and hints ("line too long") that may annoy the +user. A mechanism for disabling certain messages is provided: Each hint +and warning message contains a symbol in brackets. This is the message's +identifier that can be used to enable or disable it: + +.. code-block:: Nim + {.hint[LineTooLong]: off.} # turn off the hint about too long lines + +This is often better than disabling all warnings at once. + + diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt new file mode 100644 index 000000000..66f9ad58f --- /dev/null +++ b/doc/manual/procs.txt @@ -0,0 +1,554 @@ +Procedures +========== + +What most programming languages call `methods`:idx: or `functions`:idx: are +called `procedures`:idx: in Nim (which is the correct terminology). A +procedure declaration defines an identifier and associates it with a block +of code. +A procedure may call itself recursively. A parameter may be given a default +value that is used if the caller does not provide a value for this parameter. + +If the proc declaration has no body, it is a `forward`:idx: declaration. If +the proc returns a value, the procedure body can access an implicitly declared +variable named `result`:idx: that represents the return value. Procs can be +overloaded. The overloading resolution algorithm tries to find the proc that is +the best match for the arguments. Example: + +.. code-block:: nim + + proc toLower(c: Char): Char = # toLower for characters + if c in {'A'..'Z'}: + result = chr(ord(c) + (ord('a') - ord('A'))) + else: + result = c + + proc toLower(s: string): string = # toLower for strings + result = newString(len(s)) + for i in 0..len(s) - 1: + result[i] = toLower(s[i]) # calls toLower for characters; no recursion! + +Calling a procedure can be done in many different ways: + +.. code-block:: nim + proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ... + + # call with positional arguments # parameter bindings: + callme(0, 1, "abc", '\t', true) # (x=0, y=1, s="abc", c='\t', b=true) + # call with named and positional arguments: + callme(y=1, x=0, "abd", '\t') # (x=0, y=1, s="abd", c='\t', b=false) + # call with named arguments (order is not relevant): + callme(c='\t', y=1, x=0) # (x=0, y=1, s="", c='\t', b=false) + # call as a command statement: no () needed: + callme 0, 1, "abc", '\t' + + +A procedure cannot modify its parameters (unless the parameters have the type +`var`). + +`Operators`:idx: are procedures with a special operator symbol as identifier: + +.. code-block:: nim + proc `$` (x: int): string = + # converts an integer to a string; this is a prefix operator. + result = intToStr(x) + +Operators with one parameter are prefix operators, operators with two +parameters are infix operators. (However, the parser distinguishes these from +the operator's position within an expression.) There is no way to declare +postfix operators: all postfix operators are built-in and handled by the +grammar explicitly. + +Any operator can be called like an ordinary proc with the '`opr`' +notation. (Thus an operator can have more than two parameters): + +.. code-block:: nim + proc `*+` (a, b, c: int): int = + # Multiply and add + result = a * b + c + + assert `*+`(3, 4, 6) == `*`(a, `+`(b, c)) + + +Method call syntax +------------------ + +For object oriented programming, the syntax ``obj.method(args)`` can be used +instead of ``method(obj, args)``. The parentheses can be omitted if there are no +remaining arguments: ``obj.len`` (instead of ``len(obj)``). + +This method call syntax is not restricted to objects, it can be used +to supply any type of first argument for procedures: + +.. code-block:: nim + + echo("abc".len) # is the same as echo(len("abc")) + echo("abc".toUpper()) + echo({'a', 'b', 'c'}.card) + stdout.writeln("Hallo") # the same as writeln(stdout, "Hallo") + +Another way to look at the method call syntax is that it provides the missing +postfix notation. + + +Properties +---------- +Nim has no need for *get-properties*: Ordinary get-procedures that are called +with the *method call syntax* achieve the same. But setting a value is +different; for this a special setter syntax is needed: + +.. code-block:: nim + + type + TSocket* = object of TObject + FHost: int # cannot be accessed from the outside of the module + # the `F` prefix is a convention to avoid clashes since + # the accessors are named `host` + + proc `host=`*(s: var TSocket, value: int) {.inline.} = + ## setter of hostAddr + s.FHost = value + + proc host*(s: TSocket): int {.inline.} = + ## getter of hostAddr + s.FHost + + var + s: TSocket + s.host = 34 # same as `host=`(s, 34) + + +Command invocation syntax +------------------------- + +Routines can be invoked without the ``()`` if the call is syntatically +a statement. This command invocation syntax also works for +expressions, but then only a single argument may follow. This restriction +means ``echo f 1, f 2`` is parsed as ``echo(f(1), f(2))`` and not as +``echo(f(1, f(2)))``. The method call syntax may be used to provide one +more argument in this case: + +.. code-block:: nim + proc optarg(x:int, y:int = 0):int = x + y + proc singlearg(x:int):int = 20*x + + echo optarg 1, " ", singlearg 2 # prints "1 40" + + let fail = optarg 1, optarg 8 # Wrong. Too many arguments for a command call + let x = optarg(1, optarg 8) # traditional procedure call with 2 arguments + let y = 1.optarg optarg 8 # same thing as above, w/o the parenthesis + assert x == y + +The command invocation syntax also can't have complex expressions as arguments. +For example: (`anonymous procs`_), ``if``, ``case`` or ``try``. The (`do +notation`_) is limited, but usable for a single proc (see the example in the +corresponding section). Function calls with no arguments still needs () to +distinguish between a call and the function itself as a first class value. + + +Closures +-------- + +Procedures can appear at the top level in a module as well as inside other +scopes, in which case they are called nested procs. A nested proc can access +local variables from its enclosing scope and if it does so it becomes a +closure. Any captured variables are stored in a hidden additional argument +to the closure (its environment) and they are accessed by reference by both +the closure and its enclosing scope (i.e. any modifications made to them are +visible in both places). The closure environment may be allocated on the heap +or on the stack if the compiler determines that this would be safe. + + +Anonymous Procs +--------------- + +Procs can also be treated as expressions, in which case it's allowed to omit +the proc's name. + +.. code-block:: nim + var cities = @["Frankfurt", "Tokyo", "New York"] + + cities.sort(proc (x,y: string): int = + cmp(x.len, y.len)) + + +Procs as expressions can appear both as nested procs and inside top level +executable code. + + +Do notation +----------- + +As a special more convenient notation, proc expressions involved in procedure +calls can use the ``do`` keyword: + +.. code-block:: nim + sort(cities) do (x,y: string) -> int: + cmp(x.len, y.len) + # Less parenthesis using the method plus command syntax: + cities = cities.map do (x:string) -> string: + "City of " & x + +``do`` is written after the parentheses enclosing the regular proc params. +The proc expression represented by the do block is appended to them. + +More than one ``do`` block can appear in a single call: + +.. code-block:: nim + proc performWithUndo(task: proc(), undo: proc()) = ... + + performWithUndo do: + # multiple-line block of code + # to perform the task + do: + # code to undo it + +For compatibility with ``stmt`` templates and macros, the ``do`` keyword can be +omitted if the supplied proc doesn't have any parameters and return value. +The compatibility works in the other direction too as the ``do`` syntax can be +used with macros and templates expecting ``stmt`` blocks. + + +Nonoverloadable builtins +------------------------ + +The following builtin procs cannot be overloaded for reasons of implementation +simplicity (they require specialized semantic checking):: + + defined, definedInScope, compiles, low, high, sizeOf, + is, of, echo, shallowCopy, getAst, spawn + +Thus they act more like keywords than like ordinary identifiers; unlike a +keyword however, a redefinition may `shadow`:idx: the definition in +the ``system`` module. + + +Var parameters +-------------- +The type of a parameter may be prefixed with the ``var`` keyword: + +.. code-block:: nim + proc divmod(a, b: int; res, remainder: var int) = + res = a div b + remainder = a mod b + + var + x, y: int + + divmod(8, 5, x, y) # modifies x and y + assert x == 1 + assert y == 3 + +In the example, ``res`` and ``remainder`` are `var parameters`. +Var parameters can be modified by the procedure and the changes are +visible to the caller. The argument passed to a var parameter has to be +an l-value. Var parameters are implemented as hidden pointers. The +above example is equivalent to: + +.. code-block:: nim + proc divmod(a, b: int; res, remainder: ptr int) = + res[] = a div b + remainder[] = a mod b + + var + x, y: int + divmod(8, 5, addr(x), addr(y)) + assert x == 1 + assert y == 3 + +In the examples, var parameters or pointers are used to provide two +return values. This can be done in a cleaner way by returning a tuple: + +.. code-block:: nim + proc divmod(a, b: int): tuple[res, remainder: int] = + (a div b, a mod b) + + var t = divmod(8, 5) + + assert t.res == 1 + assert t.remainder == 3 + +One can use `tuple unpacking`:idx: to access the tuple's fields: + +.. code-block:: nim + var (x, y) = divmod(8, 5) # tuple unpacking + assert x == 1 + assert y == 3 + + +Var return type +--------------- + +A proc, converter or iterator may return a ``var`` type which means that the +returned value is an l-value and can be modified by the caller: + +.. code-block:: nim + var g = 0 + + proc WriteAccessToG(): var int = + result = g + + WriteAccessToG() = 6 + assert g == 6 + +It is a compile time error if the implicitly introduced pointer could be +used to access a location beyond its lifetime: + +.. code-block:: nim + proc WriteAccessToG(): var int = + var g = 0 + result = g # Error! + +For iterators, a component of a tuple return type can have a ``var`` type too: + +.. code-block:: nim + iterator mpairs(a: var seq[string]): tuple[key: int, val: var string] = + for i in 0..a.high: + yield (i, a[i]) + +In the standard library every name of a routine that returns a ``var`` type +starts with the prefix ``m`` per convention. + + +Overloading of the subscript operator +------------------------------------- + +The ``[]`` subscript operator for arrays/openarrays/sequences can be overloaded. + + +Multi-methods +============= + +Procedures always use static dispatch. Multi-methods use dynamic +dispatch. + +.. code-block:: nim + type + TExpr = object ## abstract base class for an expression + TLiteral = object of TExpr + x: int + TPlusExpr = object of TExpr + a, b: ref TExpr + + method eval(e: ref TExpr): int = + # override this base method + quit "to override!" + + method eval(e: ref TLiteral): int = return e.x + + method eval(e: ref TPlusExpr): int = + # watch out: relies on dynamic binding + result = eval(e.a) + eval(e.b) + + proc newLit(x: int): ref TLiteral = + new(result) + result.x = x + + proc newPlus(a, b: ref TExpr): ref TPlusExpr = + new(result) + result.a = a + result.b = b + + echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) + +In the example the constructors ``newLit`` and ``newPlus`` are procs +because they should use static binding, but ``eval`` is a method because it +requires dynamic binding. + +In a multi-method all parameters that have an object type are used for the +dispatching: + +.. code-block:: nim + type + TThing = object + TUnit = object of TThing + x: int + + method collide(a, b: TThing) {.inline.} = + quit "to override!" + + method collide(a: TThing, b: TUnit) {.inline.} = + echo "1" + + method collide(a: TUnit, b: TThing) {.inline.} = + echo "2" + + var + a, b: TUnit + collide(a, b) # output: 2 + + +Invocation of a multi-method cannot be ambiguous: collide 2 is preferred over +collide 1 because the resolution works from left to right. +In the example ``TUnit, TThing`` is preferred over ``TThing, TUnit``. + +**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. + + +Iterators and the for statement +=============================== + +The `for`:idx: statement is an abstract mechanism to iterate over the elements +of a container. It relies on an `iterator`:idx: to do so. Like ``while`` +statements, ``for`` statements open an `implicit block`:idx:, so that they +can be left with a ``break`` statement. + +The ``for`` loop declares iteration variables - their scope reaches until the +end of the loop body. The iteration variables' types are inferred by the +return type of the iterator. + +An iterator is similar to a procedure, except that it can be called in the +context of a ``for`` loop. Iterators provide a way to specify the iteration over +an abstract type. A key role in the execution of a ``for`` loop plays the +``yield`` statement in the called iterator. Whenever a ``yield`` statement is +reached the data is bound to the ``for`` loop variables and control continues +in the body of the ``for`` loop. The iterator's local variables and execution +state are automatically saved between calls. Example: + +.. code-block:: nim + # this definition exists in the system module + iterator items*(a: string): char {.inline.} = + var i = 0 + while i < len(a): + yield a[i] + inc(i) + + for ch in items("hello world"): # `ch` is an iteration variable + echo(ch) + +The compiler generates code as if the programmer would have written this: + +.. code-block:: nim + var i = 0 + while i < len(a): + var ch = a[i] + echo(ch) + inc(i) + +If the iterator yields a tuple, there can be as many iteration variables +as there are components in the tuple. The i'th iteration variable's type is +the type of the i'th component. In other words, implicit tuple unpacking in a +for loop context is supported. + +Implict items/pairs invocations +------------------------------- + +If the for loop expression ``e`` does not denote an iterator and the for loop +has exactly 1 variable, the for loop expression is rewritten to ``items(e)``; +ie. an ``items`` iterator is implicitly invoked: + +.. code-block:: nim + for x in [1,2,3]: echo x + +If the for loop has exactly 2 variables, a ``pairs`` iterator is implicitly +invoked. + +Symbol lookup of the identifiers ``items``/``pairs`` is performed after +the rewriting step, so that all overloadings of ``items``/``pairs`` are taken +into account. + + +First class iterators +--------------------- + +There are 2 kinds of iterators in Nim: *inline* and *closure* iterators. +An `inline iterator`:idx: is an iterator that's always inlined by the compiler +leading to zero overhead for the abstraction, but may result in a heavy +increase in code size. Inline iterators are second class citizens; +They can be passed as parameters only to other inlining code facilities like +templates, macros and other inline iterators. + +In contrast to that, a `closure iterator`:idx: can be passed around more freely: + +.. code-block:: nim + iterator count0(): int {.closure.} = + yield 0 + + iterator count2(): int {.closure.} = + var x = 1 + yield x + inc x + yield x + + proc invoke(iter: iterator(): int {.closure.}) = + for x in iter(): echo x + + invoke(count0) + invoke(count2) + +Closure iterators have other restrictions than inline iterators: + +1. ``yield`` in a closure iterator can not occur in a ``try`` statement. +2. For now, a closure iterator cannot be evaluated at compile time. +3. ``return`` is allowed in a closure iterator (but rarely useful). +4. Both inline and closure iterators cannot be recursive. + +Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly +default to being inline, but that this may change in future versions of the +implementation. + +The ``iterator`` type is always of the calling convention ``closure`` +implicitly; the following example shows how to use iterators to implement +a `collaborative tasking`:idx: system: + +.. code-block:: nim + # simple tasking: + type + TTask = iterator (ticker: int) + + iterator a1(ticker: int) {.closure.} = + echo "a1: A" + yield + echo "a1: B" + yield + echo "a1: C" + yield + echo "a1: D" + + iterator a2(ticker: int) {.closure.} = + echo "a2: A" + yield + echo "a2: B" + yield + echo "a2: C" + + proc runTasks(t: varargs[TTask]) = + var ticker = 0 + while true: + let x = t[ticker mod t.len] + if finished(x): break + x(ticker) + inc ticker + + runTasks(a1, a2) + +The builtin ``system.finished`` can be used to determine if an iterator has +finished its operation; no exception is raised on an attempt to invoke an +iterator that has already finished its work. + +Closure iterators are *resumable functions* and so one has to provide the +arguments to every call. To get around this limitation one can capture +parameters of an outer factory proc: + +.. code-block:: nim + proc mycount(a, b: int): iterator (): int = + result = iterator (): int = + var x = a + while x <= b: + yield x + inc x + + let foo = mycount(1, 4) + + for f in foo(): + echo f + +Implicit return type +-------------------- + +Since inline interators must always produce values that will be consumed in +a for loop, the compiler will implicity use the ``auto`` return type if no +type is given by the user. In contrast, since closure iterators can be used +as a collaborative tasking system, ``void`` is a valid return type for them. diff --git a/doc/manual/special_ops.txt b/doc/manual/special_ops.txt new file mode 100644 index 000000000..46135f129 --- /dev/null +++ b/doc/manual/special_ops.txt @@ -0,0 +1,54 @@ +Special Operators +================= + +dot operators +------------- + +Nim offers a special family of dot operators that can be used to +intercept and rewrite proc call and field access attempts, referring +to previously undeclared symbol names. They can be used to provide a +fluent interface to objects lying outside the static confines of the +type system such as values from dynamic scripting languages +or dynamic file formats such as JSON or XML. + +When Nim encounters an expression that cannot be resolved by the +standard overload resolution rules, the current scope will be searched +for a dot operator that can be matched against a re-written form of +the expression, where the unknown field or proc name is converted to +an additional static string parameter: + +.. code-block:: nim + a.b # becomes `.`(a, "b") + a.b(c, d) # becomes `.`(a, "b", c, d) + +The matched dot operators can be symbols of any callable kind (procs, +templates and macros), depending on the desired effect: + +.. code-block:: nim + proc `.` (js: PJsonNode, field: string): JSON = js[field] + + var js = parseJson("{ x: 1, y: 2}") + echo js.x # outputs 1 + echo js.y # outputs 2 + +The following dot operators are available: + +operator `.` +------------ +This operator will be matched against both field accesses and method calls. + +operator `.()` +--------------- +This operator will be matched exclusively against method calls. It has higher +precedence than the `.` operator and this allows one to handle expressions like +`x.y` and `x.y()` differently if one is interfacing with a scripting language +for example. + +operator `.=` +------------- +This operator will be matched against assignments to missing fields. + +.. code-block:: nim + a.b = c # becomes `.=`(a, "b", c) + + diff --git a/doc/manual/stmts.txt b/doc/manual/stmts.txt new file mode 100644 index 000000000..1307ff917 --- /dev/null +++ b/doc/manual/stmts.txt @@ -0,0 +1,645 @@ +Statements and expressions +========================== + +Nim uses the common statement/expression paradigm: Statements do not +produce a value in contrast to expressions. However, some expressions are +statements. + +Statements are separated into `simple statements`:idx: and +`complex statements`:idx:. +Simple statements are statements that cannot contain other statements like +assignments, calls or the ``return`` statement; complex statements can +contain other statements. To avoid the `dangling else problem`:idx:, complex +statements always have to be intended. The details can be found in the grammar. + + +Statement list expression +------------------------- + +Statements can also occur in an expression context that looks +like ``(stmt1; stmt2; ...; ex)``. This is called +an statement list expression or ``(;)``. The type +of ``(stmt1; stmt2; ...; ex)`` is the type of ``ex``. All the other statements +must be of type ``void``. (One can use ``discard`` to produce a ``void`` type.) +``(;)`` does not introduce a new scope. + + +Discard statement +----------------- + +Example: + +.. code-block:: nim + proc p(x, y: int): int = + result = x + y + + discard p(3, 4) # discard the return value of `p` + +The ``discard`` statement evaluates its expression for side-effects and +throws the expression's resulting value away. + +Ignoring the return value of a procedure without using a discard statement is +a static error. + +The return value can be ignored implicitly if the called proc/iterator has +been declared with the `discardable`:idx: pragma: + +.. code-block:: nim + proc p(x, y: int): int {.discardable.} = + result = x + y + + p(3, 4) # now valid + +An empty ``discard`` statement is often used as a null statement: + +.. code-block:: nim + proc classify(s: string) = + case s[0] + of SymChars, '_': echo "an identifier" + of '0'..'9': echo "a number" + else: discard + + +Var statement +------------- + +Var statements declare new local and global variables and +initialize them. A comma separated list of variables can be used to specify +variables of the same type: + +.. code-block:: nim + + var + a: int = 0 + x, y, z: int + +If an initializer is given the type can be omitted: the variable is then of the +same type as the initializing expression. Variables are always initialized +with a default value if there is no initializing expression. The default +value depends on the type and is always a zero in binary. + +============================ ============================================== +Type default value +============================ ============================================== +any integer type 0 +any float 0.0 +char '\\0' +bool false +ref or pointer type nil +procedural type nil +sequence nil (*not* ``@[]``) +string nil (*not* "") +tuple[x: A, y: B, ...] (default(A), default(B), ...) + (analogous for objects) +array[0..., T] [default(T), ...] +range[T] default(T); this may be out of the valid range +T = enum cast[T](0); this may be an invalid value +============================ ============================================== + + +The implicit initialization can be avoided for optimization reasons with the +`noinit`:idx: pragma: + +.. code-block:: nim + var + a {.noInit.}: array [0..1023, char] + +If a proc is annotated with the ``noinit`` pragma this refers to its implicit +``result`` variable: + +.. code-block:: nim + proc returnUndefinedValue: int {.noinit.} = discard + + +The implicit initialization can be also prevented by the `requiresInit`:idx: +type pragma. The compiler requires an explicit initialization then. However +it does a `control flow analysis`:idx: to prove the variable has been +initialized and does not rely on syntactic properties: + +.. code-block:: nim + type + TMyObject = object {.requiresInit.} + + proc p() = + # the following is valid: + var x: TMyObject + if someCondition(): + x = a() + else: + x = a() + use x + +let statement +------------- + +A ``let`` statement declares new local and global `single assignment`:idx: +variables and binds a value to them. The syntax is the of the ``var`` +statement, except that the keyword ``var`` is replaced by the keyword ``let``. +Let variables are not l-values and can thus not be passed to ``var`` parameters +nor can their address be taken. They cannot be assigned new values. + +For let variables the same pragmas are available as for ordinary variables. + + +Const section +------------- + +`Constants`:idx: are symbols which are bound to a value. The constant's value +cannot change. The compiler must be able to evaluate the expression in a +constant declaration at compile time. + +Nim contains a sophisticated compile-time evaluator, so procedures which +have no side-effect can be used in constant expressions too: + +.. code-block:: nim + import strutils + const + constEval = contains("abc", 'b') # computed at compile time! + + +The rules for compile-time computability are: + +1. Literals are compile-time computable. +2. Type conversions are compile-time computable. +3. Procedure calls of the form ``p(X)`` are compile-time computable if + ``p`` is a proc without side-effects (see the `noSideEffect pragma`_ + for details) and if ``X`` is a (possibly empty) list of compile-time + computable arguments. + + +Constants cannot be of type ``ptr``, ``ref``, ``var`` or ``object``, nor can +they contain such a type. + + +Static statement/expression +--------------------------- + +A static statement/expression can be used to enforce compile +time evaluation explicitly. Enforced compile time evaluation can even evaluate +code that has side effects: + +.. code-block:: + + static: + echo "echo at compile time" + +It's a static error if the compiler cannot perform the evaluation at compile +time. + +The current implementation poses some restrictions for compile time +evaluation: Code which contains ``cast`` or makes use of the foreign function +interface cannot be evaluated at compile time. Later versions of Nim will +support the FFI at compile time. + + +If statement +------------ + +Example: + +.. code-block:: nim + + var name = readLine(stdin) + + if name == "Andreas": + echo("What a nice name!") + elif name == "": + echo("Don't you have a name?") + else: + echo("Boring name...") + +The ``if`` statement is a simple way to make a branch in the control flow: +The expression after the keyword ``if`` is evaluated, if it is true +the corresponding statements after the ``:`` are executed. Otherwise +the expression after the ``elif`` is evaluated (if there is an +``elif`` branch), if it is true the corresponding statements after +the ``:`` are executed. This goes on until the last ``elif``. If all +conditions fail, the ``else`` part is executed. If there is no ``else`` +part, execution continues with the statement after the ``if`` statement. + +The scoping for an ``if`` statement is slightly subtle to support an important +use case. A new scope starts for the ``if``/``elif`` condition and ends after +the corresponding *then* block: + +.. code-block:: nim + if {| (let m = input =~ re"(\w+)=\w+"; m.isMatch): + echo "key ", m[0], " value ", m[1] |} + elif {| (let m = input =~ re""; m.isMatch): + echo "new m in this scope" |} + else: + # 'm' not declared here + +In the example the scopes have been enclosed in ``{| |}``. + + +Case statement +-------------- + +Example: + +.. code-block:: nim + + case readline(stdin) + of "delete-everything", "restart-computer": + echo("permission denied") + of "go-for-a-walk": echo("please yourself") + else: echo("unknown command") + + # indentation of the branches is also allowed; and so is an optional colon + # after the selecting expression: + case readline(stdin): + of "delete-everything", "restart-computer": + echo("permission denied") + of "go-for-a-walk": echo("please yourself") + else: echo("unknown command") + + +The ``case`` statement is similar to the if statement, but it represents +a multi-branch selection. The expression after the keyword ``case`` is +evaluated and if its value is in a *slicelist* the corresponding statements +(after the ``of`` keyword) are executed. If the value is not in any +given *slicelist* the ``else`` part is executed. If there is no ``else`` +part and not all possible values that ``expr`` can hold occur in a +``slicelist``, a static error occurs. This holds only for expressions of +ordinal types. "All possible values" of ``expr`` are determined by ``expr``'s +type. To suppress the static error an ``else`` part with an +empty ``discard`` statement should be used. + +For non ordinal types it is not possible to list every possible value and so +these always require an ``else`` part. + +As a special semantic extension, an expression in an ``of`` branch of a case +statement may evaluate to a set or array constructor; the set or array is then +expanded into a list of its elements: + +.. code-block:: nim + const + SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} + + proc classify(s: string) = + case s[0] + of SymChars, '_': echo "an identifier" + of '0'..'9': echo "a number" + else: echo "other" + + # is equivalent to: + proc classify(s: string) = + case s[0] + of 'a'..'z', 'A'..'Z', '\x80'..'\xFF', '_': echo "an identifier" + of '0'..'9': echo "a number" + else: echo "other" + + +When statement +-------------- + +Example: + +.. code-block:: nim + + when sizeof(int) == 2: + echo("running on a 16 bit system!") + elif sizeof(int) == 4: + echo("running on a 32 bit system!") + elif sizeof(int) == 8: + echo("running on a 64 bit system!") + else: + echo("cannot happen!") + +The ``when`` statement is almost identical to the ``if`` statement with some +exceptions: + +* Each condition (``expr``) has to be a constant expression (of type ``bool``). +* The statements do not open a new scope. +* The statements that belong to the expression that evaluated to true are + translated by the compiler, the other statements are not checked for + semantics! However, each condition is checked for semantics. + +The ``when`` statement enables conditional compilation techniques. As +a special syntactic extension, the ``when`` construct is also available +within ``object`` definitions. + + +Return statement +---------------- + +Example: + +.. code-block:: nim + return 40+2 + +The ``return`` statement ends the execution of the current procedure. +It is only allowed in procedures. If there is an ``expr``, this is syntactic +sugar for: + +.. code-block:: nim + result = expr + return result + + +``return`` without an expression is a short notation for ``return result`` if +the proc has a return type. The `result`:idx: variable is always the return +value of the procedure. It is automatically declared by the compiler. As all +variables, ``result`` is initialized to (binary) zero: + +.. code-block:: nim + proc returnZero(): int = + # implicitly returns 0 + + +Yield statement +--------------- + +Example: + +.. code-block:: nim + yield (1, 2, 3) + +The ``yield`` statement is used instead of the ``return`` statement in +iterators. It is only valid in iterators. Execution is returned to the body +of the for loop that called the iterator. Yield does not end the iteration +process, but execution is passed back to the iterator if the next iteration +starts. See the section about iterators (`Iterators and the for statement`_) +for further information. + + +Block statement +--------------- + +Example: + +.. code-block:: nim + var found = false + block myblock: + for i in 0..3: + for j in 0..3: + if a[j][i] == 7: + found = true + break myblock # leave the block, in this case both for-loops + echo(found) + +The block statement is a means to group statements to a (named) ``block``. +Inside the block, the ``break`` statement is allowed to leave the block +immediately. A ``break`` statement can contain a name of a surrounding +block to specify which block is to leave. + + +Break statement +--------------- + +Example: + +.. code-block:: nim + break + +The ``break`` statement is used to leave a block immediately. If ``symbol`` +is given, it is the name of the enclosing block that is to leave. If it is +absent, the innermost block is left. + + +While statement +--------------- + +Example: + +.. code-block:: nim + echo("Please tell me your password: \n") + var pw = readLine(stdin) + while pw != "12345": + echo("Wrong password! Next try: \n") + pw = readLine(stdin) + + +The ``while`` statement is executed until the ``expr`` evaluates to false. +Endless loops are no error. ``while`` statements open an `implicit block`, +so that they can be left with a ``break`` statement. + + +Continue statement +------------------ + +A ``continue`` statement leads to the immediate next iteration of the +surrounding loop construct. It is only allowed within a loop. A continue +statement is syntactic sugar for a nested block: + +.. code-block:: nim + while expr1: + stmt1 + continue + stmt2 + +Is equivalent to: + +.. code-block:: nim + while expr1: + block myBlockName: + stmt1 + break myBlockName + stmt2 + + +Assembler statement +------------------- + +The direct embedding of assembler code into Nim code is supported +by the unsafe ``asm`` statement. Identifiers in the assembler code that refer to +Nim identifiers shall be enclosed in a special character which can be +specified in the statement's pragmas. The default special character is ``'`'``: + +.. code-block:: nim + {.push stackTrace:off.} + proc addInt(a, b: int): int = + # a in eax, and b in edx + asm """ + mov eax, `a` + add eax, `b` + jno theEnd + call `raiseOverflow` + theEnd: + """ + {.pop.} + +If the GNU assembler is used, quotes and newlines are inserted automatically: + +.. code-block:: nim + proc addInt(a, b: int): int = + asm """ + addl %%ecx, %%eax + jno 1 + call `raiseOverflow` + 1: + :"=a"(`result`) + :"a"(`a`), "c"(`b`) + """ + +Instead of: + +.. code-block:: nim + proc addInt(a, b: int): int = + asm """ + "addl %%ecx, %%eax\n" + "jno 1\n" + "call `raiseOverflow`\n" + "1: \n" + :"=a"(`result`) + :"a"(`a`), "c"(`b`) + """ + +Using statement +--------------- + +**Warning**: The ``using`` statement is highly experimental! + +The using statement provides syntactic convenience for procs that +heavily use a single contextual parameter. When applied to a variable or a +constant, it will instruct Nim to automatically consider the used symbol as +a hidden leading parameter for any procedure calls, following the using +statement in the current scope. Thus, it behaves much like the hidden `this` +parameter available in some object-oriented programming languages. + +.. code-block:: nim + + var s = socket() + using s + + connect(host, port) + send(data) + + while true: + let line = readLine(timeout) + ... + + +When applied to a callable symbol, it brings the designated symbol in the +current scope. Thus, it can be used to disambiguate between imported symbols +from different modules having the same name. + +.. code-block:: nim + import windows, sdl + using sdl.SetTimer + +Note that ``using`` only *adds* to the current context, it doesn't remove or +replace, **neither** does it create a new scope. What this means is that if one +applies this to multiple variables the compiler will find conflicts in what +variable to use: + +.. code-block:: nim + var a, b = "kill it" + using a + add(" with fire") + using b + add(" with water") + echo a + echo b + +When the compiler reaches the second ``add`` call, both ``a`` and ``b`` could +be used with the proc, so one gets ``Error: expression '(a|b)' has no type (or +is ambiguous)``. To solve this one would need to nest ``using`` with a +``block`` statement so as to control the reach of the ``using`` statement. + +If expression +------------- + +An `if expression` is almost like an if statement, but it is an expression. +Example: + +.. code-block:: nim + var y = if x > 8: 9 else: 10 + +An if expression always results in a value, so the ``else`` part is +required. ``Elif`` parts are also allowed. + +When expression +--------------- + +Just like an `if expression`, but corresponding to the when statement. + +Case expression +--------------- + +The `case expression` is again very similar to the case statement: + +.. code-block:: nim + var favoriteFood = case animal + of "dog": "bones" + of "cat": "mice" + elif animal.endsWith"whale": "plankton" + else: + echo "I'm not sure what to serve, but everybody loves ice cream" + "ice cream" + +As seen in the above example, the case expression can also introduce side +effects. When multiple statements are given for a branch, Nim will use +the last expression as the result value, much like in an `expr` template. + +Table constructor +----------------- + +A table constructor is syntactic sugar for an array constructor: + +.. code-block:: nim + {"key1": "value1", "key2", "key3": "value2"} + + # is the same as: + [("key1", "value1"), ("key2", "value2"), ("key3", "value2")] + + +The empty table can be written ``{:}`` (in contrast to the empty set +which is ``{}``) which is thus another way to write as the empty array +constructor ``[]``. This slightly unusal way of supporting tables +has lots of advantages: + +* The order of the (key,value)-pairs is preserved, thus it is easy to + support ordered dicts with for example ``{key: val}.newOrderedTable``. +* A table literal can be put into a ``const`` section and the compiler + can easily put it into the executable's data section just like it can + for arrays and the generated data section requires a minimal amount + of memory. +* Every table implementation is treated equal syntactically. +* Apart from the minimal syntactic sugar the language core does not need to + know about tables. + + +Type conversions +---------------- +Syntactically a `type conversion` is like a procedure call, but a +type name replaces the procedure name. A type conversion is always +safe in the sense that a failure to convert a type to another +results in an exception (if it cannot be determined statically). + + +Type casts +---------- +Example: + +.. code-block:: nim + cast[int](x) + +Type casts are a crude mechanism to interpret the bit pattern of +an expression as if it would be of another type. Type casts are +only needed for low-level programming and are inherently unsafe. + + +The addr operator +----------------- +The ``addr`` operator returns the address of an l-value. If the type of the +location is ``T``, the `addr` operator result is of the type ``ptr T``. An +address is always an untraced reference. Taking the address of an object that +resides on the stack is **unsafe**, as the pointer may live longer than the +object on the stack and can thus reference a non-existing object. One can get +the address of variables, but one can't use it on variables declared through +``let`` statements: + +.. code-block:: nim + + let t1 = "Hello" + var + t2 = t1 + t3 : pointer = addr(t2) + echo repr(addr(t2)) + # --> ref 0x7fff6b71b670 --> 0x10bb81050"Hello" + echo cast[ptr string](t3)[] + # --> Hello + # The following line doesn't compile: + echo repr(addr(t1)) + # Error: expression has no address diff --git a/doc/manual/syntax.txt b/doc/manual/syntax.txt new file mode 100644 index 000000000..0ae353edd --- /dev/null +++ b/doc/manual/syntax.txt @@ -0,0 +1,112 @@ +Syntax +====== + +This section lists Nim's standard syntax. How the parser handles +the indentation is already described in the `Lexical Analysis`_ section. + +Nim allows user-definable operators. +Binary operators have 10 different levels of precedence. + +Relevant character +------------------ + +An operator symbol's *relevant character* is its first +character unless the first character is ``\`` and its length is greater than 1 +then it is the second character. + +This rule allows to escape operator symbols with ``\`` and keeps the operator's +precedence and associativity; this is useful for meta programming. + + +Associativity +------------- + +Binary operators whose relevant character is ``^`` are right-associative, all +other binary operators are left-associative. + +Precedence +---------- + +Unary operators always bind stronger than any binary +operator: ``$a + b`` is ``($a) + b`` and not ``$(a + b)``. + +If an unary operator's relevant character is ``@`` it is a `sigil-like`:idx: +operator which binds stronger than a ``primarySuffix``: ``@x.abc`` is parsed +as ``(@x).abc`` whereas ``$x.abc`` is parsed as ``$(x.abc)``. + + +For binary operators that are not keywords the precedence is determined by the +following rules: + +If the operator ends with ``=`` and its relevant character is none of +``<``, ``>``, ``!``, ``=``, ``~``, ``?``, it is an *assignment operator* which +has the lowest precedence. + +Otherwise precedence is determined by the relevant character. + +================ =============================================== ================== =============== +Precedence level Operators Relevant character Terminal symbol +================ =============================================== ================== =============== + 9 (highest) ``$ ^`` OP9 + 8 ``* / div mod shl shr %`` ``* % \ /`` OP8 + 7 ``+ -`` ``+ ~ |`` OP7 + 6 ``&`` ``&`` OP6 + 5 ``..`` ``.`` OP5 + 4 ``== <= < >= > != in notin is isnot not of`` ``= < > !`` OP4 + 3 ``and`` OP3 + 2 ``or xor`` OP2 + 1 ``@ : ?`` OP1 + 0 (lowest) *assignment operator* (like ``+=``, ``*=``) OP0 +================ =============================================== ================== =============== + + +Strong spaces +------------- + +The number of spaces preceeding 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`` +is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``: + +.. code-block:: nim + #! strongSpaces + if foo+4 * 4 == 8 and b&c | 9 ++ + bar: + echo "" + # is parsed as + if ((foo+4)*4 == 8) and (((b&c) | 9) ++ bar): echo "" + + +Furthermore whether an operator is used a prefix operator is affected by the +number of spaces: + +.. code-block:: nim + #! strongSpaces + echo $foo + # is parsed as + echo($foo) + +This also affects whether ``[]``, ``{}``, ``()`` are parsed as constructors +or as accessors: + +.. code-block:: nim + #! strongSpaces + echo (1,2) + # is parsed as + echo((1,2)) + +Only 0, 1, 2, 4 or 8 spaces are allowed to specify precedence and it is +enforced that infix operators have the same amount of spaces before and after +them. This rules does not apply when a newline follows after the operator, +then only the preceding spaces are considered. + + +Grammar +------- + +The grammar's start symbol is ``module``. + +.. include:: grammar.txt + :literal: + diff --git a/doc/manual/taint.txt b/doc/manual/taint.txt new file mode 100644 index 000000000..84f0c68b1 --- /dev/null +++ b/doc/manual/taint.txt @@ -0,0 +1,20 @@ +Taint mode +========== + +The Nim compiler and most parts of the standard library support +a taint mode. Input strings are declared with the `TaintedString`:idx: +string type declared in the ``system`` module. + +If the taint mode is turned on (via the ``--taintMode:on`` command line +option) it is a distinct string type which helps to detect input +validation errors: + +.. code-block:: nim + echo "your name: " + var name: TaintedString = stdin.readline + # it is safe here to output the name without any input validation, so + # we simply convert `name` to string to make the compiler happy: + echo "hi, ", name.string + +If the taint mode is turned off, ``TaintedString`` is simply an alias for +``string``. diff --git a/doc/manual/templates.txt b/doc/manual/templates.txt new file mode 100644 index 000000000..d63f61f54 --- /dev/null +++ b/doc/manual/templates.txt @@ -0,0 +1,404 @@ +Templates +========= + +A template is a simple form of a macro: It is a simple substitution +mechanism that operates on Nim's abstract syntax trees. It is processed in +the semantic pass of the compiler. + +The syntax to *invoke* a template is the same as calling a procedure. + +Example: + +.. code-block:: nim + template `!=` (a, b: expr): expr = + # this definition exists in the System module + not (a == b) + + assert(5 != 6) # the compiler rewrites that to: assert(not (5 == 6)) + +The ``!=``, ``>``, ``>=``, ``in``, ``notin``, ``isnot`` operators are in fact +templates: + +| ``a > b`` is transformed into ``b < a``. +| ``a in b`` is transformed into ``contains(b, a)``. +| ``notin`` and ``isnot`` have the obvious meanings. + +The "types" of templates can be the symbols ``expr`` (stands for *expression*), +``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type +description*). These are "meta types", they can only be used in certain +contexts. Real types can be used too; this implies that expressions are +expected. + + +Ordinary vs immediate templates +------------------------------- + +There are two different kinds of templates: immediate templates and +ordinary templates. Ordinary templates take part in overloading resolution. As +such their arguments need to be type checked before the template is invoked. +So ordinary templates cannot receive undeclared identifiers: + +.. code-block:: nim + + template declareInt(x: expr) = + var x: int + + declareInt(x) # error: unknown identifier: 'x' + +An ``immediate`` template does not participate in overload resolution and so +its arguments are not checked for semantics before invocation. So they can +receive undeclared identifiers: + +.. code-block:: nim + + template declareInt(x: expr) {.immediate.} = + var x: int + + declareInt(x) # valid + + +Passing a code block to a template +---------------------------------- + +If there is a ``stmt`` parameter it should be the last in the template +declaration, because statements are passed to a template via a +special ``:`` syntax: + +.. code-block:: nim + + template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} = + var f: TFile + if open(f, fn, mode): + try: + actions + finally: + close(f) + else: + quit("cannot open: " & fn) + + withFile(txt, "ttempl3.txt", fmWrite): + txt.writeln("line 1") + txt.writeln("line 2") + +In the example the two ``writeln`` statements are bound to the ``actions`` +parameter. + + +Symbol binding in templates +--------------------------- + +A template is a `hygienic`:idx: macro and so opens a new scope. Most symbols are +bound from the definition scope of the template: + +.. code-block:: nim + # Module A + var + lastId = 0 + + template genId*: expr = + inc(lastId) + lastId + +.. code-block:: nim + # Module B + import A + + echo genId() # Works as 'lastId' has been bound in 'genId's defining scope + +As in generics symbol binding can be influenced via ``mixin`` or ``bind`` +statements. + + + +Identifier construction +----------------------- + +In templates identifiers can be constructed with the backticks notation: + +.. code-block:: nim + + template typedef(name: expr, typ: typedesc) {.immediate.} = + type + `T name`* {.inject.} = typ + `P name`* {.inject.} = ref `T name` + + typedef(myint, int) + var x: PMyInt + +In the example ``name`` is instantiated with ``myint``, so \`T name\` becomes +``Tmyint``. + + +Lookup rules for template parameters +------------------------------------ + +A parameter ``p`` in a template is even substituted in the expression ``x.p``. +Thus template arguments can be used as field names and a global symbol can be +shadowed by the same argument name even when fully qualified: + +.. code-block:: nim + # module 'm' + + type + TLev = enum + levA, levB + + var abclev = levB + + template tstLev(abclev: TLev) = + echo abclev, " ", m.abclev + + tstLev(levA) + # produces: 'levA levA' + +But the global symbol can properly be captured by a ``bind`` statement: + +.. code-block:: nim + # module 'm' + + type + TLev = enum + levA, levB + + var abclev = levB + + template tstLev(abclev: TLev) = + bind m.abclev + echo abclev, " ", m.abclev + + tstLev(levA) + # produces: 'levA levB' + + +Hygiene in templates +-------------------- + +Per default templates are `hygienic`:idx:\: Local identifiers declared in a +template cannot be accessed in the instantiation context: + +.. code-block:: nim + + template newException*(exceptn: typedesc, message: string): expr = + var + e: ref exceptn # e is implicitly gensym'ed here + new(e) + e.msg = message + e + + # so this works: + let e = "message" + raise newException(EIO, e) + + +Whether a symbol that is declared in a template is exposed to the instantiation +scope is controlled by the `inject`:idx: and `gensym`:idx: pragmas: gensym'ed +symbols are not exposed but inject'ed are. + +The default for symbols of entity ``type``, ``var``, ``let`` and ``const`` +is ``gensym`` and for ``proc``, ``iterator``, ``converter``, ``template``, +``macro`` is ``inject``. However, if the name of the entity is passed as a +template parameter, it is an inject'ed symbol: + +.. code-block:: nim + template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} = + block: + var f: TFile # since 'f' is a template param, it's injected implicitly + ... + + withFile(txt, "ttempl3.txt", fmWrite): + txt.writeln("line 1") + txt.writeln("line 2") + + +The ``inject`` and ``gensym`` pragmas are second class annotations; they have +no semantics outside of a template definition and cannot be abstracted over: + +.. code-block:: nim + {.pragma myInject: inject.} + + template t() = + var x {.myInject.}: int # does NOT work + + +To get rid of hygiene in templates, one can use the `dirty`:idx: pragma for +a template. ``inject`` and ``gensym`` have no effect in ``dirty`` templates. + + + +Macros +====== + +A macro is a special kind of low level template. Macros can be used +to implement `domain specific languages`:idx:. Like templates, macros come in +the 2 flavors *immediate* and *ordinary*. + +While macros enable advanced compile-time code transformations, they +cannot change Nim's syntax. However, this is no real restriction because +Nim's syntax is flexible enough anyway. + +To write macros, one needs to know how the Nim concrete syntax is converted +to an abstract syntax tree. + +There are two ways to invoke a macro: +(1) invoking a macro like a procedure call (`expression macros`) +(2) invoking a macro with the special ``macrostmt`` syntax (`statement macros`) + + +Expression Macros +----------------- + +The following example implements a powerful ``debug`` command that accepts a +variable number of arguments: + +.. code-block:: nim + # to work with Nim syntax trees, we need an API that is defined in the + # ``macros`` module: + import macros + + macro debug(n: varargs[expr]): stmt = + # `n` is a Nim AST that contains the whole macro invocation + # this macro returns a list of statements: + result = newNimNode(nnkStmtList, n) + # iterate over any argument that is passed to this macro: + for i in 0..n.len-1: + # add a call to the statement list that writes the expression; + # `toStrLit` converts an AST to its string representation: + add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i]))) + # add a call to the statement list that writes ": " + add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": "))) + # add a call to the statement list that writes the expressions value: + add(result, newCall("writeln", newIdentNode("stdout"), n[i])) + + var + a: array [0..10, int] + x = "some string" + a[0] = 42 + a[1] = 45 + + debug(a[0], a[1], x) + +The macro call expands to: + +.. code-block:: nim + write(stdout, "a[0]") + write(stdout, ": ") + writeln(stdout, a[0]) + + write(stdout, "a[1]") + write(stdout, ": ") + writeln(stdout, a[1]) + + write(stdout, "x") + write(stdout, ": ") + writeln(stdout, x) + + +Arguments that are passed to a ``varargs`` parameter are wrapped in an array +constructor expression. This is why ``debug`` iterates over all of ``n``'s +children. + + +BindSym +------- + +The above ``debug`` macro relies on the fact that ``write``, ``writeln`` and +``stdout`` are declared in the system module and thus visible in the +instantiating context. There is a way to use bound identifiers +(aka `symbols`:idx:) instead of using unbound identifiers. The ``bindSym`` +builtin can be used for that: + +.. code-block:: nim + import macros + + macro debug(n: varargs[expr]): stmt = + result = newNimNode(nnkStmtList, n) + for i in 0..n.len-1: + # we can bind symbols in scope via 'bindSym': + add(result, newCall(bindSym"write", bindSym"stdout", toStrLit(n[i]))) + add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": "))) + add(result, newCall(bindSym"writeln", bindSym"stdout", n[i])) + + var + a: array [0..10, int] + x = "some string" + a[0] = 42 + a[1] = 45 + + debug(a[0], a[1], x) + +The macro call expands to: + +.. code-block:: nim + write(stdout, "a[0]") + write(stdout, ": ") + writeln(stdout, a[0]) + + write(stdout, "a[1]") + write(stdout, ": ") + writeln(stdout, a[1]) + + write(stdout, "x") + write(stdout, ": ") + writeln(stdout, x) + +However, the symbols ``write``, ``writeln`` and ``stdout`` are already bound +and are not looked up again. As the example shows, ``bindSym`` does work with +overloaded symbols implicitly. + + +Statement Macros +---------------- + +Statement macros are defined just as expression macros. However, they are +invoked by an expression following a colon. + +The following example outlines a macro that generates a lexical analyzer from +regular expressions: + +.. code-block:: nim + import macros + + macro case_token(n: stmt): stmt = + # creates a lexical analyzer from regular expressions + # ... (implementation is an exercise for the reader :-) + discard + + case_token: # this colon tells the parser it is a macro statement + of r"[A-Za-z_]+[A-Za-z_0-9]*": + return tkIdentifier + of r"0-9+": + return tkInteger + of r"[\+\-\*\?]+": + return tkOperator + else: + return tkUnknown + + +**Style note**: For code readability, it is the best idea to use the least +powerful programming construct that still suffices. So the "check list" is: + +(1) Use an ordinary proc/iterator, if possible. +(2) Else: Use a generic proc/iterator, if possible. +(3) Else: Use a template, if possible. +(4) Else: Use a macro. + + +Macros as pragmas +----------------- + +Whole routines (procs, iterators etc.) can also be passed to a template or +a macro via the pragma notation: + +.. code-block:: nim + template m(s: stmt) = discard + + proc p() {.m.} = discard + +This is a simple syntactic transformation into: + +.. code-block:: nim + template m(s: stmt) = discard + + m: + proc p() = discard + diff --git a/doc/manual/threads.txt b/doc/manual/threads.txt new file mode 100644 index 000000000..d29cab6ca --- /dev/null +++ b/doc/manual/threads.txt @@ -0,0 +1,209 @@ +Threads +======= + +To enable thread support the ``--threads:on`` command line switch needs to +be used. The ``system`` module then contains several threading primitives. +See the `threads <threads.html>`_ and `channels <channels.html>`_ modules +for the low level thread API. There are also high level parallelism constructs +available. See `spawn`_ for further details. + +Nim's memory model for threads is quite different than that of other common +programming languages (C, Pascal, Java): Each thread has its own (garbage +collected) heap and sharing of memory is restricted to global variables. This +helps to prevent race conditions. GC efficiency is improved quite a lot, +because the GC never has to stop other threads and see what they reference. +Memory allocation requires no lock at all! This design easily scales to massive +multicore processors that are becoming the norm. + + +Thread pragma +------------- + +A proc that is executed as a new thread of execution should be marked by the +``thread`` pragma for reasons of readability. The compiler checks for +violations of the `no heap sharing restriction`:idx:\: This restriction implies +that it is invalid to construct a data structure that consists of memory +allocated from different (thread local) heaps. + +A thread proc is passed to ``createThread`` or ``spawn`` and invoked +indirectly; so the ``thread`` pragma implies ``procvar``. + + +GC safety +--------- + +We call a proc ``p`` `GC safe`:idx: when it doesn't access any global variable +that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either +directly or indirectly through a call to a GC unsafe proc. + +The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe, +otherwise this property is inferred by the compiler. Note that ``noSideEfect`` +implies ``gcsafe``. The only way to create a thread is via ``spawn`` or +``createThead``. ``spawn`` is usually the preferable method. Either way +the invoked proc must not use ``var`` parameters nor must any of its parameters +contain a ``ref`` or ``closure`` type. This enforces +the *no heap sharing restriction*. + +Routines that are imported from C are always assumed to be ``gcsafe``. +To enable the GC-safety checking the ``--threadAnalysis:on`` command line +switch must be used. This is a temporary workaround to ease the porting effort +from old code to the new threading model. In the future the thread analysis +will always be performed. + + +Future directions: + +- A shared GC'ed heap might be provided. + + +Threadvar pragma +---------------- + +A global variable can be marked with the ``threadvar`` pragma; it is +a `thread-local`:idx: variable then: + +.. code-block:: nim + var checkpoints* {.threadvar.}: seq[string] + +Due to implementation restrictions thread local variables cannot be +initialized within the ``var`` section. (Every thread local variable needs to +be replicated at thread creation.) + + +Threads and exceptions +---------------------- + +The interaction between threads and exceptions is simple: A *handled* exception +in one thread cannot affect any other thread. However, an *unhandled* +exception in one thread terminates the whole *process*! + + + +Parallel & Spawn +================ + +Nim has two flavors of parallelism: +1) `Structured`:idx: parallelism via the ``parallel`` statement. +2) `Unstructured`:idx: parallelism via the standalone ``spawn`` statement. + +Nim has a builtin thread pool that can be used for CPU intensive tasks. For +IO intensive tasks the ``async`` and ``await`` features should be +used instead. Both parallel and spawn need the `threadpool <threadpool.html>`_ +module to work. + +Somewhat confusingly, ``spawn`` is also used in the ``parallel`` statement +with slightly different semantics. ``spawn`` always takes a call expression of +the form ``f(a, ...)``. Let ``T`` be ``f``'s return type. If ``T`` is ``void`` +then ``spawn``'s return type is also ``void``. Within a ``parallel`` section +``spawn``'s return type is ``T``, otherwise it is ``FlowVar[T]``. + +The compiler can ensure the location in ``location = spawn f(...)`` is not +read prematurely within a ``parallel`` section and so there is no need for +the overhead of an indirection via ``FlowVar[T]`` to ensure correctness. + +**Note**: Currently exceptions are not propagated between ``spawn``ed tasks! + + +Spawn statement +--------------- + +`spawn`:idx: can be used to pass a task to the thread pool: + +.. code-block:: nim + import threadpool + + proc processLine(line: string) = + discard "do some heavy lifting here" + + for x in lines("myinput.txt"): + spawn processLine(x) + sync() + +For reasons of type safety and implementation simplicity the expression +that ``spawn`` takes is restricted: + +* It must be a call expression ``f(a, ...)``. +* ``f`` must be ``gcsafe``. +* ``f`` must not have the calling convention ``closure``. +* ``f``'s parameters may not be of type ``var``. + This means one has to use raw ``ptr``'s for data passing reminding the + programmer to be careful. +* ``ref`` parameters are deeply copied which is a subtle semantic change and + can cause performance problems but ensures memory safety. This deep copy + is performed via ``system.deepCopy`` and so can be overriden. +* For *safe* data exchange between ``f`` and the caller a global ``TChannel`` + needs to be used. However, since spawn can return a result, often no further + communication is required. + + +``spawn`` executes the passed expression on the thread pool and returns +a `data flow variable`:idx: ``FlowVar[T]`` that can be read from. The reading +with the ``^`` operator is **blocking**. However, one can use ``awaitAny`` to +wait on multiple flow variables at the same time: + +.. code-block:: nim + import threadpool, ... + + # wait until 2 out of 3 servers received the update: + proc main = + var responses = newSeq[RawFlowVar](3) + for i in 0..2: + responses[i] = spawn tellServer(Update, "key", "value") + var index = awaitAny(responses) + assert index >= 0 + responses.del(index) + discard awaitAny(responses) + +Data flow variables ensure that no data races +are possible. Due to technical limitations not every type ``T`` is possible in +a data flow variable: ``T`` has to be of the type ``ref``, ``string``, ``seq`` +or of a type that doesn't contain a type that is garbage collected. This +restriction will be removed in the future. + + + +Parallel statement +------------------ + +Example: + +.. code-block:: nim + # Compute PI in an inefficient way + import strutils, math, threadpool + + proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1) + + proc pi(n: int): float = + var ch = newSeq[float](n+1) + parallel: + for k in 0..ch.high: + ch[k] = spawn term(float(k)) + for k in 0..ch.high: + result += ch[k] + + echo formatFloat(pi(5000)) + + +The parallel statement is the preferred mechanism to introduce parallelism +in a Nim program. A subset of the Nim language is valid within a +``parallel`` section. This subset is checked to be free of data races at +compile time. A sophisticated `disjoint checker`:idx: ensures that no data +races are possible even though shared memory is extensively supported! + +The subset is in fact the full language with the following +restrictions / changes: + +* ``spawn`` within a ``parallel`` section has special semantics. +* Every location of the form ``a[i]`` and ``a[i..j]`` and ``dest`` where + ``dest`` is part of the pattern ``dest = spawn f(...)`` has to be + provably disjoint. This is called the *disjoint check*. +* Every other complex location ``loc`` that is used in a spawned + proc (``spawn f(loc)``) has to be immutable for the duration of + the ``parallel`` section. This is called the *immutability check*. Currently + it is not specified what exactly "complex location" means. We need to make + this an optimization! +* Every array access has to be provably within bounds. This is called + the *bounds check*. +* Slices are optimized so that no copy is performed. This optimization is not + yet performed for ordinary slices outside of a ``parallel`` section. Slices + are also special in that they currently do not support negative indexes! diff --git a/doc/manual/trmacros.txt b/doc/manual/trmacros.txt new file mode 100644 index 000000000..715c9f850 --- /dev/null +++ b/doc/manual/trmacros.txt @@ -0,0 +1,361 @@ +Term rewriting macros +===================== + +Term rewriting macros are macros or templates that have not only +a *name* but also a *pattern* that is searched for after the semantic checking +phase of the compiler: This means they provide an easy way to enhance the +compilation pipeline with user defined optimizations: + +.. code-block:: nim + template optMul{`*`(a, 2)}(a: int): int = a+a + + let x = 3 + echo x * 2 + +The compiler now rewrites ``x * 2`` as ``x + x``. The code inside the +curlies is the pattern to match against. The operators ``*``, ``**``, +``|``, ``~`` have a special meaning in patterns if they are written in infix +notation, so to match verbatim against ``*`` the ordinary function call syntax +needs to be used. + + +Unfortunately optimizations are hard to get right and even the tiny example +is **wrong**: + +.. code-block:: nim + template optMul{`*`(a, 2)}(a: int): int = a+a + + proc f(): int = + echo "side effect!" + result = 55 + + echo f() * 2 + +We cannot duplicate 'a' if it denotes an expression that has a side effect! +Fortunately Nim supports side effect analysis: + +.. code-block:: nim + template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a + + proc f(): int = + echo "side effect!" + result = 55 + + echo f() * 2 # not optimized ;-) + +So what about ``2 * a``? We should tell the compiler ``*`` is commutative. We +cannot really do that however as the following code only swaps arguments +blindly: + +.. code-block:: nim + template mulIsCommutative{`*`(a, b)}(a, b: int): int = b*a + +What optimizers really need to do is a *canonicalization*: + +.. code-block:: nim + template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b*a + +The ``int{lit}`` parameter pattern matches against an expression of +type ``int``, but only if it's a literal. + + + +Parameter constraints +--------------------- + +The `parameter constraint`:idx: expression can use the operators ``|`` (or), +``&`` (and) and ``~`` (not) and the following predicates: + +=================== ===================================================== +Predicate Meaning +=================== ===================================================== +``atom`` The matching node has no children. +``lit`` The matching node is a literal like "abc", 12. +``sym`` The matching node must be a symbol (a bound + identifier). +``ident`` The matching node must be an identifier (an unbound + identifier). +``call`` The matching AST must be a call/apply expression. +``lvalue`` The matching AST must be an lvalue. +``sideeffect`` The matching AST must have a side effect. +``nosideeffect`` The matching AST must have no side effect. +``param`` A symbol which is a parameter. +``genericparam`` A symbol which is a generic parameter. +``module`` A symbol which is a module. +``type`` A symbol which is a type. +``var`` A symbol which is a variable. +``let`` A symbol which is a ``let`` variable. +``const`` A symbol which is a constant. +``result`` The special ``result`` variable. +``proc`` A symbol which is a proc. +``method`` A symbol which is a method. +``iterator`` A symbol which is an iterator. +``converter`` A symbol which is a converter. +``macro`` A symbol which is a macro. +``template`` A symbol which is a template. +``field`` A symbol which is a field in a tuple or an object. +``enumfield`` A symbol which is a field in an enumeration. +``forvar`` A for loop variable. +``label`` A label (used in ``block`` statements). +``nk*`` The matching AST must have the specified kind. + (Example: ``nkIfStmt`` denotes an ``if`` statement.) +``alias`` States that the marked parameter needs to alias + with *some* other parameter. +``noalias`` States that *every* other parameter must not alias + with the marked parameter. +=================== ===================================================== + +The ``alias`` and ``noalias`` predicates refer not only to the matching AST, +but also to every other bound parameter; syntactially they need to occur after +the ordinary AST predicates: + +.. code-block:: nim + template ex{a = b + c}(a: int{noalias}, b, c: int) = + # this transformation is only valid if 'b' and 'c' do not alias 'a': + a = b + inc a, c + + +Pattern operators +----------------- + +The operators ``*``, ``**``, ``|``, ``~`` have a special meaning in patterns +if they are written in infix notation. + + +The ``|`` operator +~~~~~~~~~~~~~~~~~~ + +The ``|`` operator if used as infix operator creates an ordered choice: + +.. code-block:: nim + template t{0|1}(): expr = 3 + let a = 1 + # outputs 3: + echo a + +The matching is performed after the compiler performed some optimizations like +constant folding, so the following does not work: + +.. code-block:: nim + template t{0|1}(): expr = 3 + # outputs 1: + echo 1 + +The reason is that the compiler already transformed the 1 into "1" for +the ``echo`` statement. However, a term rewriting macro should not change the +semantics anyway. In fact they can be deactived with the ``--patterns:off`` +command line option or temporarily with the ``patterns`` pragma. + + +The ``{}`` operator +~~~~~~~~~~~~~~~~~~~ + +A pattern expression can be bound to a pattern parameter via the ``expr{param}`` +notation: + +.. code-block:: nim + template t{(0|1|2){x}}(x: expr): expr = x+1 + let a = 1 + # outputs 2: + echo a + + +The ``~`` operator +~~~~~~~~~~~~~~~~~~ + +The ``~`` operator is the **not** operator in patterns: + +.. code-block:: nim + template t{x = (~x){y} and (~x){z}}(x, y, z: bool): stmt = + x = y + if x: x = z + + var + a = false + b = true + c = false + a = b and c + echo a + + +The ``*`` operator +~~~~~~~~~~~~~~~~~~ + +The ``*`` operator can *flatten* a nested binary expression like ``a & b & c`` +to ``&(a, b, c)``: + +.. code-block:: nim + var + calls = 0 + + proc `&&`(s: varargs[string]): string = + result = s[0] + for i in 1..len(s)-1: result.add s[i] + inc calls + + template optConc{ `&&` * a }(a: string): expr = &&a + + let space = " " + echo "my" && (space & "awe" && "some " ) && "concat" + + # check that it's been optimized properly: + doAssert calls == 1 + + +The second operator of `*` must be a parameter; it is used to gather all the +arguments. The expression ``"my" && (space & "awe" && "some " ) && "concat"`` +is passed to ``optConc`` in ``a`` as a special list (of kind ``nkArgList``) +which is flattened into a call expression; thus the invocation of ``optConc`` +produces: + +.. code-block:: nim + `&&`("my", space & "awe", "some ", "concat") + + +The ``**`` operator +~~~~~~~~~~~~~~~~~~~ + +The ``**`` is much like the ``*`` operator, except that it gathers not only +all the arguments, but also the matched operators in reverse polish notation: + +.. code-block:: nim + import macros + + type + TMatrix = object + dummy: int + + proc `*`(a, b: TMatrix): TMatrix = discard + proc `+`(a, b: TMatrix): TMatrix = discard + proc `-`(a, b: TMatrix): TMatrix = discard + proc `$`(a: TMatrix): string = result = $a.dummy + proc mat21(): TMatrix = + result.dummy = 21 + + macro optM{ (`+`|`-`|`*`) ** a }(a: TMatrix): expr = + echo treeRepr(a) + result = newCall(bindSym"mat21") + + var x, y, z: TMatrix + + echo x + y * z - x + +This passes the expression ``x + y * z - x`` to the ``optM`` macro as +an ``nnkArgList`` node containing:: + + Arglist + Sym "x" + Sym "y" + Sym "z" + Sym "*" + Sym "+" + Sym "x" + Sym "-" + +(Which is the reverse polish notation of ``x + y * z - x``.) + + +Parameters +---------- + +Parameters in a pattern are type checked in the matching process. If a +parameter is of the type ``varargs`` it is treated specially and it can match +0 or more arguments in the AST to be matched against: + +.. code-block:: nim + template optWrite{ + write(f, x) + ((write|writeln){w})(f, y) + }(x, y: varargs[expr], f: TFile, w: expr) = + w(f, x, y) + + + +Example: Partial evaluation +--------------------------- + +The following example shows how some simple partial evaluation can be +implemented with term rewriting: + +.. code-block:: nim + proc p(x, y: int; cond: bool): int = + result = if cond: x + y else: x - y + + template optP1{p(x, y, true)}(x, y: expr): expr = x + y + template optP2{p(x, y, false)}(x, y: expr): expr = x - y + + +Example: Hoisting +----------------- + +The following example shows how some form of hoisting can be implemented: + +.. code-block:: nim + import pegs + + template optPeg{peg(pattern)}(pattern: string{lit}): TPeg = + var gl {.global, gensym.} = peg(pattern) + gl + + for i in 0 .. 3: + echo match("(a b c)", peg"'(' @ ')'") + echo match("W_HI_Le", peg"\y 'while'") + +The ``optPeg`` template optimizes the case of a peg constructor with a string +literal, so that the pattern will only be parsed once at program startup and +stored in a global ``gl`` which is then re-used. This optimization is called +hoisting because it is comparable to classical loop hoisting. + + +AST based overloading +===================== + +Parameter constraints can also be used for ordinary routine parameters; these +constraints affect ordinary overloading resolution then: + +.. code-block:: nim + proc optLit(a: string{lit|`const`}) = + echo "string literal" + proc optLit(a: string) = + echo "no string literal" + + const + constant = "abc" + + var + variable = "xyz" + + optLit("literal") + optLit(constant) + optLit(variable) + +However, the constraints ``alias`` and ``noalias`` are not available in +ordinary routines. + + +Move optimization +----------------- + +The ``call`` constraint is particularly useful to implement a move +optimization for types that have copying semantics: + +.. code-block:: nim + proc `[]=`*(t: var TTable, key: string, val: string) = + ## puts a (key, value)-pair into `t`. The semantics of string require + ## a copy here: + let idx = findInsertionPosition(key) + t[idx] = key + t[idx] = val + + proc `[]=`*(t: var TTable, key: string{call}, val: string{call}) = + ## puts a (key, value)-pair into `t`. Optimized version that knows that + ## the strings are unique and thus don't need to be copied: + let idx = findInsertionPosition(key) + shallowCopy t[idx], key + shallowCopy t[idx], val + + var t: TTable + # overloading resolution ensures that the optimized []= is called here: + t[f()] = g() + diff --git a/doc/manual/type_bound_ops.txt b/doc/manual/type_bound_ops.txt new file mode 100644 index 000000000..64c6c325d --- /dev/null +++ b/doc/manual/type_bound_ops.txt @@ -0,0 +1,112 @@ +Type bound operations +===================== + +There are 3 operations that are bound to a type: + +1. Assignment +2. Destruction +3. Deep copying for communication between threads + +These operations can be *overriden* instead of *overloaded*. This means the +implementation is automatically lifted to structured types. For instance if type +``T`` has an overriden assignment operator ``=`` this operator is also used +for assignments of the type ``seq[T]``. Since these operations are bound to a +type they have to be bound to a nominal type for reasons of simplicity of +implementation: This means an overriden ``deepCopy`` for ``ref T`` is really +bound to ``T`` and not to ``ref T``. This also means that one cannot override +``deepCopy`` for both ``ptr T`` and ``ref T`` at the same time; instead a +helper distinct or object type has to be used for one pointer type. + + +operator `=` +------------ + +This operator is the assignment operator. Note that in the contexts +like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for +parameter passing no assignment is performed. The ``override`` pragma is +optional for overriding ``=``. + +**Note**: Overriding of operator ``=`` is not yet implemented. + + +destructors +----------- + +A destructor must have a single parameter with a concrete type (the name of a +generic type is allowed too). The name of the destructor has to be ``destroy`` +and it need to be annotated with the ``override`` pragma. + +``destroy(v)`` will be automatically invoked for every local stack +variable ``v`` that goes out of scope. + +If a structured type features a field with destructable type and +the user has not provided an explicit implementation, a destructor for the +structured type will be automatically generated. Calls to any base class +destructors in both user-defined and generated destructors will be inserted. + +A destructor is attached to the type it destructs; expressions of this type +can then only be used in *destructible contexts* and as parameters: + +.. code-block:: nim + type + TMyObj = object + x, y: int + p: pointer + + proc destroy(o: var TMyObj) {.override.} = + if o.p != nil: dealloc o.p + + proc open: TMyObj = + result = TMyObj(x: 1, y: 2, p: alloc(3)) + + proc work(o: TMyObj) = + echo o.x + # No destructor invoked here for 'o' as 'o' is a parameter. + + proc main() = + # destructor automatically invoked at the end of the scope: + var x = open() + # valid: pass 'x' to some other proc: + work(x) + + # Error: usage of a type with a destructor in a non destructible context + echo open() + +A destructible context is currently only the following: + +1. The ``expr`` in ``var x = expr``. +2. The ``expr`` in ``let x = expr``. +3. The ``expr`` in ``return expr``. +4. The ``expr`` in ``result = expr`` where ``result`` is the special symbol + introduced by the compiler. + +These rules ensure that the construction is tied to a variable and can easily +be destructed at its scope exit. Later versions of the language will improve +the support of destructors. + +Be aware that destructors are not called for objects allocated with ``new``. +This may change in future versions of language, but for now the ``finalizer`` +parameter to ``new`` has to be used. + +**Note**: Destructors are still experimental and the spec might change +significantly in order to incorporate an escape analysis. + + +deepCopy +-------- + +``deepCopy`` is a builtin that is invoked whenever data is passed to +a ``spawn``'ed proc to ensure memory safety. The programmer can override its +behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the +language may weaken this restriction.) + +The signature has to be: + +.. code-block:: nim + proc deepCopy(x: T): T {.override.} + +This mechanism is used by most data structures that support shared memory like +channels to implement thread safe automatic memory management. + +The builtin ``deepCopy`` can even clone closures and their environments. See +the documentation of `spawn`_ for details. diff --git a/doc/manual/type_rel.txt b/doc/manual/type_rel.txt new file mode 100644 index 000000000..74539f907 --- /dev/null +++ b/doc/manual/type_rel.txt @@ -0,0 +1,191 @@ +Type relations +============== + +The following section defines several relations on types that are needed to +describe the type checking done by the compiler. + + +Type equality +------------- +Nim uses structural type equivalence for most types. Only for objects, +enumerations and distinct types name equivalence is used. The following +algorithm (in pseudo-code) determines type equality: + +.. code-block:: nim + proc typeEqualsAux(a, b: PType, + s: var set[PType * PType]): bool = + if (a,b) in s: return true + incl(s, (a,b)) + if a.kind == b.kind: + case a.kind + of int, intXX, float, floatXX, char, string, cstring, pointer, + bool, nil, void: + # leaf type: kinds identical; nothing more to check + result = true + of ref, ptr, var, set, seq, openarray: + result = typeEqualsAux(a.baseType, b.baseType, s) + of range: + result = typeEqualsAux(a.baseType, b.baseType, s) and + (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB) + of array: + result = typeEqualsAux(a.baseType, b.baseType, s) and + typeEqualsAux(a.indexType, b.indexType, s) + of tuple: + if a.tupleLen == b.tupleLen: + for i in 0..a.tupleLen-1: + if not typeEqualsAux(a[i], b[i], s): return false + result = true + of object, enum, distinct: + result = a == b + of proc: + result = typeEqualsAux(a.parameterTuple, b.parameterTuple, s) and + typeEqualsAux(a.resultType, b.resultType, s) and + a.callingConvention == b.callingConvention + + proc typeEquals(a, b: PType): bool = + var s: set[PType * PType] = {} + result = typeEqualsAux(a, b, s) + +Since types are graphs which can have cycles, the above algorithm needs an +auxiliary set ``s`` to detect this case. + + +Type equality modulo type distinction +------------------------------------- + +The following algorithm (in pseudo-code) determines whether two types +are equal with no respect to ``distinct`` types. For brevity the cycle check +with an auxiliary set ``s`` is omitted: + +.. code-block:: nim + proc typeEqualsOrDistinct(a, b: PType): bool = + if a.kind == b.kind: + case a.kind + of int, intXX, float, floatXX, char, string, cstring, pointer, + bool, nil, void: + # leaf type: kinds identical; nothing more to check + result = true + of ref, ptr, var, set, seq, openarray: + result = typeEqualsOrDistinct(a.baseType, b.baseType) + of range: + result = typeEqualsOrDistinct(a.baseType, b.baseType) and + (a.rangeA == b.rangeA) and (a.rangeB == b.rangeB) + of array: + result = typeEqualsOrDistinct(a.baseType, b.baseType) and + typeEqualsOrDistinct(a.indexType, b.indexType) + of tuple: + if a.tupleLen == b.tupleLen: + for i in 0..a.tupleLen-1: + if not typeEqualsOrDistinct(a[i], b[i]): return false + result = true + of distinct: + result = typeEqualsOrDistinct(a.baseType, b.baseType) + of object, enum: + result = a == b + of proc: + result = typeEqualsOrDistinct(a.parameterTuple, b.parameterTuple) and + typeEqualsOrDistinct(a.resultType, b.resultType) and + a.callingConvention == b.callingConvention + elif a.kind == distinct: + result = typeEqualsOrDistinct(a.baseType, b) + elif b.kind == distinct: + result = typeEqualsOrDistinct(a, b.baseType) + + +Subtype relation +---------------- +If object ``a`` inherits from ``b``, ``a`` is a subtype of ``b``. This subtype +relation is extended to the types ``var``, ``ref``, ``ptr``: + +.. code-block:: nim + proc isSubtype(a, b: PType): bool = + if a.kind == b.kind: + case a.kind + of object: + var aa = a.baseType + while aa != nil and aa != b: aa = aa.baseType + result = aa == b + of var, ref, ptr: + result = isSubtype(a.baseType, b.baseType) + +.. XXX nil is a special value! + + +Convertible relation +-------------------- +A type ``a`` is **implicitly** convertible to type ``b`` iff the following +algorithm returns true: + +.. code-block:: nim + # XXX range types? + proc isImplicitlyConvertible(a, b: PType): bool = + case a.kind + of int: result = b in {int8, int16, int32, int64, uint, uint8, uint16, + uint32, uint64, float, float32, float64} + of int8: result = b in {int16, int32, int64, int} + of int16: result = b in {int32, int64, int} + of int32: result = b in {int64, int} + of uint: result = b in {uint32, uint64} + of uint8: result = b in {uint16, uint32, uint64} + of uint16: result = b in {uint32, uint64} + of uint32: result = b in {uint64} + of float: result = b in {float32, float64} + of float32: result = b in {float64, float} + of float64: result = b in {float32, float} + of seq: + result = b == openArray and typeEquals(a.baseType, b.baseType) + of array: + result = b == openArray and typeEquals(a.baseType, b.baseType) + if a.baseType == char and a.indexType.rangeA == 0: + result = b = cstring + of cstring, ptr: + result = b == pointer + of string: + result = b == cstring + +A type ``a`` is **explicitly** convertible to type ``b`` iff the following +algorithm returns true: + +.. code-block:: nim + proc isIntegralType(t: PType): bool = + result = isOrdinal(t) or t.kind in {float, float32, float64} + + proc isExplicitlyConvertible(a, b: PType): bool = + result = false + if isImplicitlyConvertible(a, b): return true + if typeEqualsOrDistinct(a, b): return true + if isIntegralType(a) and isIntegralType(b): return true + if isSubtype(a, b) or isSubtype(b, a): return true + +The convertible relation can be relaxed by a user-defined type +`converter`:idx:. + +.. code-block:: nim + converter toInt(x: char): int = result = ord(x) + + var + x: int + chr: char = 'a' + + # implicit conversion magic happens here + x = chr + echo x # => 97 + # you can use the explicit form too + x = chr.toInt + echo x # => 97 + +The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and +``typeEqualsOrDistinct(T, type(a))`` holds. + + +Assignment compatibility +------------------------ + +An expression ``b`` can be assigned to an expression ``a`` iff ``a`` is an +`l-value` and ``isImplicitlyConvertible(b.typ, a.typ)`` holds. + + +Overloading resolution +---------------------- + +To be written. diff --git a/doc/manual/type_sections.txt b/doc/manual/type_sections.txt new file mode 100644 index 000000000..5413e896e --- /dev/null +++ b/doc/manual/type_sections.txt @@ -0,0 +1,23 @@ +Type sections +============= + +Example: + +.. code-block:: nim + type # example demonstrating mutually recursive types + PNode = ref TNode # a traced pointer to a TNode + TNode = object + le, ri: PNode # left and right subtrees + sym: ref TSym # leaves contain a reference to a TSym + + TSym = object # a symbol + name: string # the symbol's name + line: int # the line the symbol was declared in + code: PNode # the symbol's abstract syntax tree + +A type section begins with the ``type`` keyword. It contains multiple +type definitions. A type definition binds a type to a name. Type definitions +can be recursive or even mutually recursive. Mutually recursive types are only +possible within a single ``type`` section. Nominal types like ``objects`` +or ``enums`` can only be defined in a ``type`` section. + diff --git a/doc/manual/typedesc.txt b/doc/manual/typedesc.txt new file mode 100644 index 000000000..d1d8bc87a --- /dev/null +++ b/doc/manual/typedesc.txt @@ -0,0 +1,146 @@ +Special Types +============= + +static[T] +--------- + +**Note**: static[T] is still in development. + +As their name suggests, static params must be known at compile-time: + +.. code-block:: nim + + proc precompiledRegex(pattern: static[string]): TRegEx = + var res {.global.} = re(pattern) + return res + + precompiledRegex("/d+") # Replaces the call with a precompiled + # regex, stored in a global variable + + precompiledRegex(paramStr(1)) # Error, command-line options + # are not known at compile-time + + +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 +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: + +.. code-block:: nim + + # The following proc will be compiled once for each unique static + # value and also once for the case handling all run-time values: + + proc re(pattern: semistatic[string]): TRegEx = + when isStatic(pattern): + result = precompiledRegex(pattern) + else: + result = compile(pattern) + +Static params can also appear in the signatures of generic types: + +.. code-block:: nim + + type + Matrix[M,N: static[int]; T: Number] = array[0..(M*N - 1), T] + # Note how `Number` is just a type constraint here, while + # `static[int]` requires us to supply a compile-time int value + + AffineTransform2D[T] = Matrix[3, 3, T] + AffineTransform3D[T] = Matrix[4, 4, T] + + var m1: AffineTransform3D[float] # OK + var m2: AffineTransform2D[string] # Error, `string` is not a `Number` + + +typedesc +-------- + +`typedesc` is a special type allowing one to treat types as compile-time values +(i.e. if types are compile-time values and all values have a type, then +typedesc must be their type). + +When used as a regular proc param, typedesc acts as a type class. The proc +will be instantiated for each unique type parameter and one can refer to the +instantiation type using the param name: + +.. code-block:: nim + + proc new(T: typedesc): ref T = + echo "allocating ", T.name + new(result) + + var n = TNode.new + var tree = new(TBinaryTree[int]) + +When multiple typedesc params are present, they act like a distinct type class +(i.e. they will bind freely to different types). To force a bind-once behavior +one can use a named alias or an explicit `typedesc` generic param: + +.. code-block:: nim + + # `type1` and `type2` are aliases for typedesc available from system.nim + proc acceptOnlyTypePairs(A, B: type1; C, D: type2) + proc acceptOnlyTypePairs[T: typedesc, U: typedesc](A, B: T; C, D: U) + +Once bound, typedesc params can appear in the rest of the proc signature: + +.. code-block:: nim + + template declareVariableWithType(T: typedesc, value: T) = + var x: T = value + + declareVariableWithType int, 42 + +When used with macros and .compileTime. procs on the other hand, the compiler +does not need to instantiate the code multiple times, because types then can be +manipulated using the unified internal symbol representation. In such context +typedesc acts as any other type. One can create variables, store typedesc +values inside containers and so on. For example, here is how one can create +a type-safe wrapper for the unsafe `printf` function from C: + +.. code-block:: nim + macro safePrintF(formatString: string{lit}, args: varargs[expr]): expr = + var i = 0 + for c in formatChars(formatString): + var expectedType = case c + of 'c': char + of 'd', 'i', 'x', 'X': int + of 'f', 'e', 'E', 'g', 'G': float + of 's': string + of 'p': pointer + else: EOutOfRange + + var actualType = args[i].getType + inc i + + if expectedType == EOutOfRange: + error c & " is not a valid format character" + elif expectedType != actualType: + error "type mismatch for argument ", i, ". expected type: ", + expectedType.name, ", actual type: ", actualType.name + + # keep the original callsite, but use cprintf instead + result = callsite() + result[0] = newIdentNode(!"cprintf") + + +Overload resolution can be further influenced by constraining the set of +types that will match the typedesc param: + +.. code-block:: nim + + template maxval(T: typedesc[int]): int = high(int) + template maxval(T: typedesc[float]): float = Inf + + var i = int.maxval + var f = float.maxval + var s = string.maxval # error, maxval is not implemented for string + +The constraint can be a concrete type or a type class. + + diff --git a/doc/manual/types.txt b/doc/manual/types.txt new file mode 100644 index 000000000..b8cde8c37 --- /dev/null +++ b/doc/manual/types.txt @@ -0,0 +1,1163 @@ +Types +===== + +All expressions have a type which is known at compile time. Nim +is statically typed. One can declare new types, which is in essence defining +an identifier that can be used to denote this custom type. + +These are the major type classes: + +* ordinal types (consist of integer, bool, character, enumeration + (and subranges thereof) types) +* floating point types +* string type +* structured types +* reference (pointer) type +* procedural type +* generic type + + +Ordinal types +------------- +Ordinal types have the following characteristics: + +- Ordinal types are countable and ordered. This property allows + the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to + be defined. +- Ordinal values have a smallest possible value. Trying to count further + down than the smallest value gives a checked runtime or static error. +- Ordinal values have a largest possible value. Trying to count further + than the largest value gives a checked runtime or static error. + +Integers, bool, characters and enumeration types (and subranges of these +types) belong to ordinal types. For reasons of simplicity of implementation +the types ``uint`` and ``uint64`` are not ordinal types. + + +Pre-defined integer types +------------------------- +These integer types are pre-defined: + +``int`` + the generic signed integer type; its size is platform dependent and has the + same size as a pointer. This type should be used in general. An integer + literal that has no type suffix is of this type. + +intXX + additional signed integer types of XX bits use this naming scheme + (example: int16 is a 16 bit wide integer). + The current implementation supports ``int8``, ``int16``, ``int32``, ``int64``. + Literals of these types have the suffix 'iXX. + +``uint`` + the generic `unsigned integer`:idx: type; its size is platform dependent and + has the same size as a pointer. An integer literal with the type + suffix ``'u`` is of this type. + +uintXX + additional signed integer types of XX bits use this naming scheme + (example: uint16 is a 16 bit wide unsigned integer). + The current implementation supports ``uint8``, ``uint16``, ``uint32``, + ``uint64``. Literals of these types have the suffix 'uXX. + Unsigned operations all wrap around; they cannot lead to over- or + underflow errors. + + +In addition to the usual arithmetic operators for signed and unsigned integers +(``+ - *`` etc.) there are also operators that formally work on *signed* +integers but treat their arguments as *unsigned*: They are mostly provided +for backwards compatibility with older versions of the language that lacked +unsigned integer types. These unsigned operations for signed integers use +the ``%`` suffix as convention: + + +====================== ====================================================== +operation meaning +====================== ====================================================== +``a +% b`` unsigned integer addition +``a -% b`` unsigned integer subtraction +``a *% b`` unsigned integer multiplication +``a /% b`` unsigned integer division +``a %% b`` unsigned integer modulo operation +``a <% b`` treat ``a`` and ``b`` as unsigned and compare +``a <=% b`` treat ``a`` and ``b`` as unsigned and compare +``ze(a)`` extends the bits of ``a`` with zeros until it has the + width of the ``int`` type +``toU8(a)`` treats ``a`` as unsigned and converts it to an + unsigned integer of 8 bits (but still the + ``int8`` type) +``toU16(a)`` treats ``a`` as unsigned and converts it to an + unsigned integer of 16 bits (but still the + ``int16`` type) +``toU32(a)`` treats ``a`` as unsigned and converts it to an + unsigned integer of 32 bits (but still the + ``int32`` type) +====================== ====================================================== + +`Automatic type conversion`:idx: is performed in expressions where different +kinds of integer types are used: the smaller type is converted to the larger. + +A `narrowing type conversion`:idx: converts a larger to a smaller type (for +example ``int32 -> int16``. A `widening type conversion`:idx: converts a +smaller type to a larger type (for example ``int16 -> int32``). In Nim only +widening type conversions are *implicit*: + +.. code-block:: nim + var myInt16 = 5i16 + var myInt: int + myInt16 + 34 # of type ``int16`` + myInt16 + myInt # of type ``int`` + myInt16 + 2i32 # of type ``int32`` + +However, ``int`` literals are implicitly convertible to a smaller integer type +if the literal's value fits this smaller type and such a conversion is less +expensive than other implicit conversions, so ``myInt16 + 34`` produces +an ``int16`` result. + +For further details, see `Convertible relation`_. + + +Subrange types +-------------- +A subrange type is a range of values from an ordinal type (the base +type). To define a subrange type, one must specify it's limiting values: the +lowest and highest value of the type: + +.. code-block:: nim + type + Subrange = range[0..5] + + +``Subrange`` is a subrange of an integer which can only hold the values 0 +to 5. Assigning any other value to a variable of type ``Subrange`` is a +checked runtime error (or static error if it can be statically +determined). Assignments from the base type to one of its subrange types +(and vice versa) are allowed. + +A subrange type has the same size as its base type (``int`` in the example). + +Nim requires `interval arithmetic`:idx: for subrange types over a set +of built-in operators that involve constants: ``x %% 3`` is of +type ``range[0..2]``. The following built-in operators for integers are +affected by this rule: ``-``, ``+``, ``*``, ``min``, ``max``, ``succ``, +``pred``, ``mod``, ``div``, ``%%``, ``and`` (bitwise ``and``). + +Bitwise ``and`` only produces a ``range`` if one of its operands is a +constant *x* so that (x+1) is a number of two. +(Bitwise ``and`` is then a ``%%`` operation.) + +This means that the following code is accepted: + +.. code-block:: nim + case (x and 3) + 7 + of 7: echo "A" + of 8: echo "B" + of 9: echo "C" + of 10: echo "D" + # note: no ``else`` required as (x and 3) + 7 has the type: range[7..10] + + +Pre-defined floating point types +-------------------------------- + +The following floating point types are pre-defined: + +``float`` + the generic floating point type; its size is platform dependent + (the compiler chooses the processor's fastest floating point type). + This type should be used in general. + +floatXX + an implementation may define additional floating point types of XX bits using + this naming scheme (example: float64 is a 64 bit wide float). The current + implementation supports ``float32`` and ``float64``. Literals of these types + have the suffix 'fXX. + + +Automatic type conversion in expressions with different kinds +of floating point types is performed: See `Convertible relation`_ for further +details. Arithmetic performed on floating point types follows the IEEE +standard. Integer types are not converted to floating point types automatically +and vice versa. + +The IEEE standard defines five types of floating-point exceptions: + +* Invalid: operations with mathematically invalid operands, + for example 0.0/0.0, sqrt(-1.0), and log(-37.8). +* Division by zero: divisor is zero and dividend is a finite nonzero number, + for example 1.0/0.0. +* Overflow: operation produces a result that exceeds the range of the exponent, + for example MAXDOUBLE+0.0000000000001e308. +* Underflow: operation produces a result that is too small to be represented + as a normal number, for example, MINDOUBLE * MINDOUBLE. +* Inexact: operation produces a result that cannot be represented with infinite + precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input. + +The IEEE exceptions are either ignored at runtime or mapped to the +Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:, +`FloatOverflowError`:idx:, `FloatUnderflowError`:idx:, +and `FloatInexactError`:idx:. +These exceptions inherit from the `FloatingPointError`:idx: base class. + +Nim provides the pragmas `NaNChecks`:idx: and `InfChecks`:idx: to control +whether the IEEE exceptions are ignored or trap a Nim exception: + +.. code-block:: nim + {.NanChecks: on, InfChecks: on.} + var a = 1.0 + var b = 0.0 + echo b / b # raises FloatInvalidOpError + echo a / b # raises FloatOverflowError + +In the current implementation ``FloatDivByZeroError`` and ``FloatInexactError`` +are never raised. ``FloatOverflowError`` is raised instead of +``FloatDivByZeroError``. +There is also a `floatChecks`:idx: pragma that is a short-cut for the +combination of ``NaNChecks`` and ``InfChecks`` pragmas. ``floatChecks`` are +turned off as default. + +The only operations that are affected by the ``floatChecks`` pragma are +the ``+``, ``-``, ``*``, ``/`` operators for floating point types. + +An implementation should always use the maximum precision available to evaluate +floating pointer values at compile time; this means expressions like +``0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64`` are true. + + +Boolean type +------------ +The boolean type is named `bool`:idx: in Nim and can be one of the two +pre-defined values ``true`` and ``false``. Conditions in while, +if, elif, when statements need to be of type bool. + +This condition holds:: + + ord(false) == 0 and ord(true) == 1 + +The operators ``not, and, or, xor, <, <=, >, >=, !=, ==`` are defined +for the bool type. The ``and`` and ``or`` operators perform short-cut +evaluation. Example: + +.. code-block:: nim + + while p != nil and p.name != "xyz": + # p.name is not evaluated if p == nil + p = p.next + + +The size of the bool type is one byte. + + +Character type +-------------- +The character type is named ``char`` in Nim. Its size is one byte. +Thus it cannot represent an UTF-8 character, but a part of it. +The reason for this is efficiency: for the overwhelming majority of use-cases, +the resulting programs will still handle UTF-8 properly as UTF-8 was specially +designed for this. +Another reason is that Nim can support ``array[char, int]`` or +``set[char]`` efficiently as many algorithms rely on this feature. The +`TRune` type is used for Unicode characters, it can represent any Unicode +character. ``TRune`` is declared in the `unicode module <unicode.html>`_. + + + + +Enumeration types +----------------- +Enumeration types define a new type whose values consist of the ones +specified. The values are ordered. Example: + +.. code-block:: nim + + type + Direction = enum + north, east, south, west + + +Now the following holds:: + + ord(north) == 0 + ord(east) == 1 + ord(south) == 2 + ord(west) == 3 + +Thus, north < east < south < west. The comparison operators can be used +with enumeration types. + +For better interfacing to other programming languages, the fields of enum +types can be assigned an explicit ordinal value. However, the ordinal values +have to be in ascending order. A field whose ordinal value is not +explicitly given is assigned the value of the previous field + 1. + +An explicit ordered enum can have *holes*: + +.. code-block:: nim + type + TokenType = enum + a = 2, b = 4, c = 89 # holes are valid + +However, it is then not an ordinal anymore, so it is not possible to use these +enums as an index type for arrays. The procedures ``inc``, ``dec``, ``succ`` +and ``pred`` are not available for them either. + + +The compiler supports the built-in stringify operator ``$`` for enumerations. +The stringify's result can be controlled by explicitly giving the string +values to use: + +.. code-block:: nim + + type + MyEnum = enum + valueA = (0, "my value A"), + valueB = "value B", + valueC = 2, + valueD = (3, "abc") + +As can be seen from the example, it is possible to both specify a field's +ordinal value and its string value by using a tuple. It is also +possible to only specify one of them. + +An enum can be marked with the ``pure`` pragma so that it's fields are not +added to the current scope, so they always need to be accessed +via ``MyEnum.value``: + +.. code-block:: nim + + type + MyEnum {.pure.} = enum + valueA, valueB, valueC, valueD + + echo valueA # error: Unknown identifier + echo MyEnum.valueA # works + + +String type +----------- +All string literals are of the type ``string``. A string in Nim is very +similar to a sequence of characters. However, strings in Nim are both +zero-terminated and have a length field. One can retrieve the length with the +builtin ``len`` procedure; the length never counts the terminating zero. +The assignment operator for strings always copies the string. +The ``&`` operator concatenates strings. + +Strings are compared by their lexicographical order. All comparison operators +are available. Strings can be indexed like arrays (lower bound is 0). Unlike +arrays, they can be used in case statements: + +.. code-block:: nim + + case paramStr(i) + of "-v": incl(options, optVerbose) + of "-h", "-?": incl(options, optHelp) + else: write(stdout, "invalid command line option!\n") + +Per convention, all strings are UTF-8 strings, but this is not enforced. For +example, when reading strings from binary files, they are merely a sequence of +bytes. The index operation ``s[i]`` means the i-th *char* of ``s``, not the +i-th *unichar*. The iterator ``runes`` from the `unicode module +<unicode.html>`_ can be used for iteration over all Unicode characters. + + +cstring type +------------ +The ``cstring`` type represents a pointer to a zero-terminated char array +compatible to the type ``char*`` in Ansi C. Its primary purpose lies in easy +interfacing with C. The index operation ``s[i]`` means the i-th *char* of +``s``; however no bounds checking for ``cstring`` is performed making the +index operation unsafe. + +A Nim ``string`` is implicitly convertible +to ``cstring`` for convenience. If a Nim string is passed to a C-style +variadic proc, it is implicitly converted to ``cstring`` too: + +.. code-block:: nim + proc printf(formatstr: cstring) {.importc: "printf", varargs, + header: "<stdio.h>".} + + printf("This works %s", "as expected") + +Even though the conversion is implicit, it is not *safe*: The garbage collector +does not consider a ``cstring`` to be a root and may collect the underlying +memory. However in practice this almost never happens as the GC considers +stack roots conservatively. One can use the builtin procs ``GC_ref`` and +``GC_unref`` to keep the string data alive for the rare cases where it does +not work. + +A `$` proc is defined for cstrings that returns a string. Thus to get a nim +string from a cstring: + +.. code-block:: nim + var str: string = "Hello!" + var cstr: cstring = s + var newstr: string = $cstr + + +Structured types +---------------- +A variable of a structured type can hold multiple values at the same +time. Structured types can be nested to unlimited levels. Arrays, sequences, +tuples, objects and sets belong to the structured types. + +Array and sequence types +------------------------ +Arrays are a homogeneous type, meaning that each element in the array +has the same type. Arrays always have a fixed length which is specified at +compile time (except for open arrays). They can be indexed by any ordinal type. +A parameter ``A`` may be an *open array*, in which case it is indexed by +integers from 0 to ``len(A)-1``. An array expression may be constructed by the +array constructor ``[]``. + +Sequences are similar to arrays but of dynamic length which may change +during runtime (like strings). Sequences are implemented as growable arrays, +allocating pieces of memory as items are added. A sequence ``S`` is always +indexed by integers from 0 to ``len(S)-1`` and its bounds are checked. +Sequences can be constructed by the array constructor ``[]`` in conjunction +with the array to sequence operator ``@``. Another way to allocate space for a +sequence is to call the built-in ``newSeq`` procedure. + +A sequence may be passed to a parameter that is of type *open array*. + +Example: + +.. code-block:: nim + + type + IntArray = array[0..5, int] # an array that is indexed with 0..5 + IntSeq = seq[int] # a sequence of integers + var + x: IntArray + y: IntSeq + x = [1, 2, 3, 4, 5, 6] # [] is the array constructor + y = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence + +The lower bound of an array or sequence may be received by the built-in proc +``low()``, the higher bound by ``high()``. The length may be +received by ``len()``. ``low()`` for a sequence or an open array always returns +0, as this is the first valid index. +One can append elements to a sequence with the ``add()`` proc or the ``&`` +operator, and remove (and get) the last element of a sequence with the +``pop()`` proc. + +The notation ``x[i]`` can be used to access the i-th element of ``x``. + +Arrays are always bounds checked (at compile-time or at runtime). These +checks can be disabled via pragmas or invoking the compiler with the +``--boundChecks:off`` command line switch. + + +Open arrays +----------- + +Often fixed size arrays turn out to be too inflexible; procedures should +be able to deal with arrays of different sizes. The `openarray`:idx: type +allows this; it can only be used for parameters. Openarrays are always +indexed with an ``int`` starting at position 0. The ``len``, ``low`` +and ``high`` operations are available for open arrays too. Any array with +a compatible base type can be passed to an openarray parameter, the index +type does not matter. In addition to arrays sequences can also be passed +to an open array parameter. + +The openarray type cannot be nested: multidimensional openarrays are not +supported because this is seldom needed and cannot be done efficiently. + + +Varargs +------- + +A ``varargs`` parameter is an openarray parameter that additionally +allows to pass a variable number of arguments to a procedure. The compiler +converts the list of arguments to an array implicitly: + +.. code-block:: nim + proc myWriteln(f: File, a: varargs[string]) = + for s in items(a): + write(f, s) + write(f, "\n") + + myWriteln(stdout, "abc", "def", "xyz") + # is transformed to: + myWriteln(stdout, ["abc", "def", "xyz"]) + +This transformation is only done if the varargs parameter is the +last parameter in the procedure header. It is also possible to perform +type conversions in this context: + +.. code-block:: nim + proc myWriteln(f: File, a: varargs[string, `$`]) = + for s in items(a): + write(f, s) + write(f, "\n") + + myWriteln(stdout, 123, "abc", 4.0) + # is transformed to: + myWriteln(stdout, [$123, $"def", $4.0]) + +In this example ``$`` is applied to any argument that is passed to the +parameter ``a``. (Note that ``$`` applied to strings is a nop.) + + + +Tuples and object types +----------------------- +A variable of a tuple or object type is a heterogeneous storage +container. +A tuple or object defines various named *fields* of a type. A tuple also +defines an *order* of the fields. Tuples are meant for heterogeneous storage +types with no overhead and few abstraction possibilities. The constructor ``()`` +can be used to construct tuples. The order of the fields in the constructor +must match the order of the tuple's definition. Different tuple-types are +*equivalent* if they specify the same fields of the same type in the same +order. The *names* of the fields also have to be identical but this might +change in a future version of the language. + +The assignment operator for tuples copies each component. +The default assignment operator for objects copies each component. Overloading +of the assignment operator for objects is not possible, but this will change +in future versions of the compiler. + +.. code-block:: nim + + type + Person = tuple[name: string, age: int] # type representing a person: + # a person consists of a name + # and an age + var + person: Person + person = (name: "Peter", age: 30) + # the same, but less readable: + person = ("Peter", 30) + +The implementation aligns the fields for best access performance. The alignment +is compatible with the way the C compiler does it. + +For consistency with ``object`` declarations, tuples in a ``type`` section +can also be defined with indentation instead of ``[]``: + +.. code-block:: nim + type + Person = tuple # type representing a person + name: string # a person consists of a name + age: natural # and an age + +Objects provide many features that tuples do not. Object provide inheritance +and information hiding. Objects have access to their type at runtime, so that +the ``of`` operator can be used to determine the object's type. + +.. code-block:: nim + type + Person {.inheritable.} = object + name*: string # the * means that `name` is accessible from other modules + age: int # no * means that the field is hidden + + Student = object of Person # a student is a person + id: int # with an id field + + var + student: Student + person: Person + assert(student of Student) # is true + +Object fields that should be visible from outside the defining module, have to +be marked by ``*``. In contrast to tuples, different object types are +never *equivalent*. Objects that have no ancestor are implicitly ``final`` +and thus have no hidden type field. One can use the ``inheritable`` pragma to +introduce new object roots apart from ``system.RootObj``. + + +Object construction +------------------- + +Objects can also be created with an `object construction expression`:idx: that +has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is +an ``object`` type or a ``ref object`` type: + +.. code-block:: nim + var student = Student(name: "Anton", age: 5, id: 3) + +For a ``ref object`` type ``system.new`` is invoked implicitly. + + +Object variants +--------------- +Often an object hierarchy is overkill in certain situations where simple +variant types are needed. + +An example: + +.. code-block:: nim + + # This is an example how an abstract syntax tree could be modelled in Nim + type + TNodeKind = enum # the different node types + nkInt, # a leaf with an integer value + nkFloat, # a leaf with a float value + nkString, # a leaf with a string value + nkAdd, # an addition + nkSub, # a subtraction + nkIf # an if statement + PNode = ref TNode + TNode = object + case kind: TNodeKind # the ``kind`` field is the discriminator + of nkInt: intVal: int + of nkFloat: floatVal: float + of nkString: strVal: string + of nkAdd, nkSub: + leftOp, rightOp: PNode + of nkIf: + condition, thenPart, elsePart: PNode + + # create a new case object: + var n = PNode(kind: nkIf, condition: nil) + # accessing n.thenPart is valid because the ``nkIf`` branch is active: + n.thenPart = PNode(kind: nkFloat, floatVal: 2.0) + + # the following statement raises an `EInvalidField` exception, because + # n.kind's value does not fit and the ``nkString`` branch is not active: + n.strVal = "" + + # invalid: would change the active object branch: + n.kind = nkInt + + var x = PNode(kind: nkAdd, leftOp: PNode(kind: nkInt, intVal: 4), + rightOp: PNode(kind: nkInt, intVal: 2)) + # valid: does not change the active object branch: + x.kind = nkSub + +As can been seen from the example, an advantage to an object hierarchy is that +no casting between different object types is needed. Yet, access to invalid +object fields raises an exception. + +The syntax of ``case`` in an object declaration follows closely the syntax of +the ``case`` statement: The branches in a ``case`` section may be indented too. + +In the example the ``kind`` field is called the `discriminator`:idx:\: For +safety its address cannot be taken and assignments to it are restricted: The +new value must not lead to a change of the active object branch. For an object +branch switch ``system.reset`` has to be used. + + +Set type +-------- + +.. include:: sets_fragment.txt + +Reference and pointer types +--------------------------- +References (similar to pointers in other programming languages) are a +way to introduce many-to-one relationships. This means different references can +point to and modify the same location in memory (also called `aliasing`:idx:). + +Nim distinguishes between `traced`:idx: and `untraced`:idx: references. +Untraced references are also called *pointers*. Traced references point to +objects of a garbage collected heap, untraced references point to +manually allocated objects or to objects somewhere else in memory. Thus +untraced references are *unsafe*. However for certain low-level operations +(accessing the hardware) untraced references are unavoidable. + +Traced references are declared with the **ref** keyword, untraced references +are declared with the **ptr** keyword. + +An empty subscript ``[]`` notation can be used to derefer a reference, +the ``addr`` procedure returns the address of an item. An address is always +an untraced reference. +Thus the usage of ``addr`` is an *unsafe* feature. + +The ``.`` (access a tuple/object field operator) +and ``[]`` (array/string/sequence index operator) operators perform implicit +dereferencing operations for reference types: + +.. code-block:: nim + + type + PNode = ref TNode + TNode = object + le, ri: PNode + data: int + + var + n: PNode + new(n) + n.data = 9 + # no need to write n[].data; in fact n[].data is highly discouraged! + +In order to simplify structural type checking, recursive tuples are not valid: + +.. code-block:: nim + # invalid recursion + type MyTuple = tuple[a: ref MyTuple] + +Likewise ``T = ref T`` is an invalid type. + +As a syntactical extension ``object`` types can be anonymous if +declared in a type section via the ``ref object`` or ``ptr object`` notations. +This feature is useful if an object should only gain reference semantics: + +.. code-block:: nim + + type + Node = ref object + le, ri: Node + data: int + + +To allocate a new traced object, the built-in procedure ``new`` has to be used. +To deal with untraced memory, the procedures ``alloc``, ``dealloc`` and +``realloc`` can be used. The documentation of the system module contains +further information. + +If a reference points to *nothing*, it has the value ``nil``. + +Special care has to be taken if an untraced object contains traced objects like +traced references, strings or sequences: in order to free everything properly, +the built-in procedure ``GCunref`` has to be called before freeing the untraced +memory manually: + +.. code-block:: nim + type + TData = tuple[x, y: int, s: string] + + # allocate memory for TData on the heap: + var d = cast[ptr TData](alloc0(sizeof(TData))) + + # create a new string on the garbage collected heap: + d.s = "abc" + + # tell the GC that the string is not needed anymore: + GCunref(d.s) + + # free the memory: + dealloc(d) + +Without the ``GCunref`` call the memory allocated for the ``d.s`` string would +never be freed. The example also demonstrates two important features for low +level programming: the ``sizeof`` proc returns the size of a type or value +in bytes. The ``cast`` operator can circumvent the type system: the compiler +is forced to treat the result of the ``alloc0`` call (which returns an untyped +pointer) as if it would have the type ``ptr TData``. Casting should only be +done if it is unavoidable: it breaks type safety and bugs can lead to +mysterious crashes. + +**Note**: The example only works because the memory is initialized to zero +(``alloc0`` instead of ``alloc`` does this): ``d.s`` is thus initialized to +``nil`` which the string assignment can handle. One needs to know low level +details like this when mixing garbage collected data with unmanaged memory. + +.. XXX finalizers for traced objects + + +Not nil annotation +------------------ + +All types for that ``nil`` is a valid value can be annotated to +exclude ``nil`` as a valid value with the ``not nil`` annotation: + +.. code-block:: nim + type + PObject = ref TObj not nil + TProc = (proc (x, y: int)) not nil + + proc p(x: PObject) = + echo "not nil" + + # compiler catches this: + p(nil) + + # and also this: + var x: PObject + p(x) + +The compiler ensures that every code path initializes variables which contain +not nilable pointers. The details of this analysis are still to be specified +here. + + +Memory regions +-------------- + +The types ``ref`` and ``ptr`` can get an optional ``region`` annotation. +A region has to be an object type. + +Regions are very useful to separate user space and kernel memory in the +development of OS kernels: + +.. code-block:: nim + type + Kernel = object + Userspace = object + + var a: Kernel ptr Stat + var b: Userspace ptr Stat + + # the following does not compile as the pointer types are incompatible: + a = b + +As the example shows ``ptr`` can also be used as a binary +operator, ``region ptr T`` is a shortcut for ``ptr[region, T]``. + +In order to make generic code easier to write ``ptr T`` is a subtype +of ``ptr[R, T]`` for any ``R``. + +Furthermore the subtype relation of the region object types is lifted to +the pointer types: If ``A <: B`` then ``ptr[A, T] <: ptr[B, T]``. This can be +used to model subregions of memory. As a special typing rule ``ptr[R, T]`` is +not compatible to ``pointer`` to prevent the following from compiling: + +.. code-block:: nim + # from system + proc dealloc(p: pointer) + + # wrap some scripting language + type + PythonsHeap = object + PyObjectHeader = object + rc: int + typ: pointer + PyObject = ptr[PythonsHeap, PyObjectHeader] + + proc createPyObject(): PyObject {.importc: "...".} + proc destroyPyObject(x: PyObject) {.importc: "...".} + + var foo = createPyObject() + # type error here, how convenient: + dealloc(foo) + + +Future directions: + +* Memory regions might become available for ``string`` and ``seq`` too. +* Builtin regions like ``private``, ``global`` and ``local`` will + prove very useful for the upcoming OpenCL target. +* Builtin "regions" can model ``lent`` and ``unique`` pointers. + + + +Procedural type +--------------- +A procedural type is internally a pointer to a procedure. ``nil`` is +an allowed value for variables of a procedural type. Nim uses procedural +types to achieve `functional`:idx: programming techniques. + +Examples: + +.. code-block:: nim + + proc printItem(x: int) = ... + + proc forEach(c: proc (x: int) {.cdecl.}) = + ... + + forEach(printItem) # this will NOT compile because calling conventions differ + + +.. code-block:: nim + + type + TOnMouseMove = proc (x, y: int) {.closure.} + + proc onMouseMove(mouseX, mouseY: int) = + # has default calling convention + echo "x: ", mouseX, " y: ", mouseY + + proc setOnMouseMove(mouseMoveEvent: TOnMouseMove) = discard + + # ok, 'onMouseMove' has the default calling convention, which is compatible + # to 'closure': + setOnMouseMove(onMouseMove) + + +A subtle issue with procedural types is that the calling convention of the +procedure influences the type compatibility: procedural types are only +compatible if they have the same calling convention. As a special extension, +a procedure of the calling convention ``nimcall`` can be passed to a parameter +that expects a proc of the calling convention ``closure``. + +Nim supports these `calling conventions`:idx:\: + +`nimcall`:idx: + is the default convention used for a Nim **proc**. It is the + same as ``fastcall``, but only for C compilers that support ``fastcall``. + +`closure`:idx: + is the default calling convention for a **procedural type** that lacks + any pragma annotations. It indicates that the procedure has a hidden + implicit parameter (an *environment*). Proc vars that have the calling + convention ``closure`` take up two machine words: One for the proc pointer + and another one for the pointer to implicitly passed environment. + +`stdcall`:idx: + This the stdcall convention as specified by Microsoft. The generated C + procedure is declared with the ``__stdcall`` keyword. + +`cdecl`:idx: + The cdecl convention means that a procedure shall use the same convention + as the C compiler. Under windows the generated C procedure is declared with + the ``__cdecl`` keyword. + +`safecall`:idx: + This is the safecall convention as specified by Microsoft. The generated C + procedure is declared with the ``__safecall`` keyword. The word *safe* + refers to the fact that all hardware registers shall be pushed to the + hardware stack. + +`inline`:idx: + The inline convention means the the caller should not call the procedure, + but inline its code directly. Note that Nim does not inline, but leaves + this to the C compiler; it generates ``__inline`` procedures. This is + only a hint for the compiler: it may completely ignore it and + it may inline procedures that are not marked as ``inline``. + +`fastcall`:idx: + Fastcall means different things to different C compilers. One gets whatever + the C ``__fastcall`` means. + +`syscall`:idx: + The syscall convention is the same as ``__syscall`` in C. It is used for + interrupts. + +`noconv`:idx: + The generated C code will not have any explicit calling convention and thus + use the C compiler's default calling convention. This is needed because + Nim's default calling convention for procedures is ``fastcall`` to + improve speed. + +Most calling conventions exist only for the Windows 32-bit platform. + +Assigning/passing a procedure to a procedural variable is only allowed if one +of the following conditions hold: +1) The procedure that is accessed resides in the current module. +2) The procedure is marked with the ``procvar`` pragma (see `procvar pragma`_). +3) The procedure has a calling convention that differs from ``nimcall``. +4) The procedure is anonymous. + +The rules' purpose is to prevent the case that extending a non-``procvar`` +procedure with default parameters breaks client code. + +The default calling convention is ``nimcall``, unless it is an inner proc (a +proc inside of a proc). For an inner proc an analysis is performed whether it +accesses its environment. If it does so, it has the calling convention +``closure``, otherwise it has the calling convention ``nimcall``. + + +Distinct type +------------- + +A ``distinct`` type is new type derived from a `base type`:idx: that is +incompatible with its base type. In particular, it is an essential property +of a distinct type that it **does not** imply a subtype relation between it +and its base type. Explicit type conversions from a distinct type to its +base type and vice versa are allowed. + + +Modelling currencies +~~~~~~~~~~~~~~~~~~~~ + +A distinct type can be used to model different physical `units`:idx: with a +numerical base type, for example. The following example models currencies. + +Different currencies should not be mixed in monetary calculations. Distinct +types are a perfect tool to model different currencies: + +.. code-block:: nim + type + TDollar = distinct int + TEuro = distinct int + + var + d: TDollar + e: TEuro + + echo d + 12 + # Error: cannot add a number with no unit and a ``TDollar`` + +Unfortunately, ``d + 12.TDollar`` is not allowed either, +because ``+`` is defined for ``int`` (among others), not for ``TDollar``. So +a ``+`` for dollars needs to be defined: + +.. code-block:: + proc `+` (x, y: TDollar): TDollar = + result = TDollar(int(x) + int(y)) + +It does not make sense to multiply a dollar with a dollar, but with a +number without unit; and the same holds for division: + +.. code-block:: + proc `*` (x: TDollar, y: int): TDollar = + result = TDollar(int(x) * y) + + proc `*` (x: int, y: TDollar): TDollar = + result = TDollar(x * int(y)) + + proc `div` ... + +This quickly gets tedious. The implementations are trivial and the compiler +should not generate all this code only to optimize it away later - after all +``+`` for dollars should produce the same binary code as ``+`` for ints. +The pragma `borrow`:idx: has been designed to solve this problem; in principle +it generates the above trivial implementations: + +.. code-block:: nim + proc `*` (x: TDollar, y: int): TDollar {.borrow.} + proc `*` (x: int, y: TDollar): TDollar {.borrow.} + proc `div` (x: TDollar, y: int): TDollar {.borrow.} + +The ``borrow`` pragma makes the compiler use the same implementation as +the proc that deals with the distinct type's base type, so no code is +generated. + +But it seems all this boilerplate code needs to be repeated for the ``TEuro`` +currency. This can be solved with templates_. + +.. code-block:: nim + template additive(typ: typedesc): stmt = + proc `+` *(x, y: typ): typ {.borrow.} + proc `-` *(x, y: typ): typ {.borrow.} + + # unary operators: + proc `+` *(x: typ): typ {.borrow.} + proc `-` *(x: typ): typ {.borrow.} + + template multiplicative(typ, base: typedesc): stmt = + proc `*` *(x: typ, y: base): typ {.borrow.} + proc `*` *(x: base, y: typ): typ {.borrow.} + proc `div` *(x: typ, y: base): typ {.borrow.} + proc `mod` *(x: typ, y: base): typ {.borrow.} + + template comparable(typ: typedesc): stmt = + proc `<` * (x, y: typ): bool {.borrow.} + proc `<=` * (x, y: typ): bool {.borrow.} + proc `==` * (x, y: typ): bool {.borrow.} + + template defineCurrency(typ, base: expr): stmt = + type + typ* = distinct base + additive(typ) + multiplicative(typ, base) + comparable(typ) + + defineCurrency(TDollar, int) + defineCurrency(TEuro, int) + + +The borrow pragma can also be used to annotate the distinct type to allow +certain builtin operations to be lifted: + +.. code-block:: nim + type + Foo = object + a, b: int + s: string + + Bar {.borrow: `.`.} = distinct Foo + + var bb: ref Bar + new bb + # field access now valid + bb.a = 90 + bb.s = "abc" + +Currently only the dot accessor can be borrowed in this way. + + +Avoiding SQL injection attacks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +An SQL statement that is passed from Nim to an SQL database might be +modelled as a string. However, using string templates and filling in the +values is vulnerable to the famous `SQL injection attack`:idx:\: + +.. code-block:: nim + import strutils + + proc query(db: TDbHandle, statement: string) = ... + + var + username: string + + db.query("SELECT FROM users WHERE name = '$1'" % username) + # Horrible security hole, but the compiler does not mind! + +This can be avoided by distinguishing strings that contain SQL from strings +that don't. Distinct types provide a means to introduce a new string type +``TSQL`` that is incompatible with ``string``: + +.. code-block:: nim + type + TSQL = distinct string + + proc query(db: TDbHandle, statement: TSQL) = ... + + var + username: string + + db.query("SELECT FROM users WHERE name = '$1'" % username) + # Error at compile time: `query` expects an SQL string! + + +It is an essential property of abstract types that they **do not** imply a +subtype relation between the abtract type and its base type. Explict type +conversions from ``string`` to ``TSQL`` are allowed: + +.. code-block:: nim + import strutils, sequtils + + proc properQuote(s: string): TSQL = + # quotes a string properly for an SQL statement + return TSQL(s) + + proc `%` (frmt: TSQL, values: openarray[string]): TSQL = + # quote each argument: + let v = values.mapIt(TSQL, properQuote(it)) + # we need a temporary type for the type conversion :-( + type TStrSeq = seq[string] + # call strutils.`%`: + result = TSQL(string(frmt) % TStrSeq(v)) + + db.query("SELECT FROM users WHERE name = '$1'".TSQL % [username]) + +Now we have compile-time checking against SQL injection attacks. Since +``"".TSQL`` is transformed to ``TSQL("")`` no new syntax is needed for nice +looking ``TSQL`` string literals. The hypothetical ``TSQL`` type actually +exists in the library as the `TSqlQuery type <db_sqlite.html#TSqlQuery>`_ of +modules like `db_sqlite <db_sqlite.html>`_. + + +Void type +--------- + +The ``void`` type denotes the absense 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: + +.. code-block:: nim + proc nothing(x, y: void): void = + echo "ha" + + nothing() # writes "ha" to stdout + +The ``void`` type is particularly useful for generic code: + +.. code-block:: nim + proc callProc[T](p: proc (x: T), x: T) = + when T is void: + p() + else: + p(x) + + proc intProc(x: int) = discard + proc emptyProc() = discard + + callProc[int](intProc, 12) + callProc[void](emptyProc) + +However, a ``void`` type cannot be inferred in generic code: + +.. code-block:: nim + callProc(emptyProc) + # Error: type mismatch: got (proc ()) + # but expected one of: + # callProc(p: proc (T), x: T) + +The ``void`` type is only valid for parameters and return types; other symbols +cannot have the type ``void``. diff --git a/doc/nimrodc.txt b/doc/nimc.txt index 016f0ed50..8af045e2e 100644 --- a/doc/nimrodc.txt +++ b/doc/nimc.txt @@ -1,9 +1,9 @@ =================================== - Nimrod Compiler User Guide + Nim Compiler User Guide =================================== :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: @@ -15,11 +15,11 @@ Introduction ============ -This document describes the usage of the *Nimrod compiler* -on the different supported platforms. It is not a definition of the Nimrod +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>`_). -Nimrod is free software; it is licensed under the +Nim is free software; it is licensed under the `MIT License <http://www.opensource.org/licenses/mit-license.php>`_. @@ -107,14 +107,14 @@ Configuration files passed as a command line argument to the compiler. -The ``nimrod`` executable processes configuration files in the following +The ``nim`` executable processes configuration files in the following directories (in this order; later files overwrite previous settings): -1) ``$nimrod/config/nimrod.cfg``, ``/etc/nimrod.cfg`` (UNIX) or ``%NIMROD%/config/nimrod.cfg`` (Windows). This file can be skipped with the ``--skipCfg`` command line option. -2) ``/home/$user/.config/nimrod.cfg`` (UNIX) or ``%APPDATA%/nimrod.cfg`` (Windows). This file can be skipped with the ``--skipUserCfg`` command line option. -3) ``$parentDir/nimrod.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/nimrod.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.nimrod.cfg`` that resides in the same directory as ``$project.nim``. This file can be skipped with the ``--skipProjCfg`` command line option. +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. @@ -122,17 +122,17 @@ 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:: - nimrod c -d:release myproject.nim + nim c -d:release myproject.nim Search path handling -------------------- -Nimrod has the concept of a global search path (PATH) that is queried to +Nim has the concept of a global search path (PATH) that is queried to determine where to find imported modules or include files. If multiple files are found an ambiguity error is produced. -``nimrod dump`` shows the contents of the PATH. +``nim dump`` shows the contents of the PATH. However before the PATH is used the current directory is checked for the file's existance. So if PATH contains ``$lib`` and ``$lib/bar`` and the @@ -152,10 +152,10 @@ the first matching file is used. Generated C code directory -------------------------- -The generated files that Nimrod produces all go into a subdirectory called +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 `Nimrod Backend Integration document +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 @@ -190,14 +190,14 @@ Cross compilation To cross compile, use for example:: - nimrod c --cpu:i386 --os:linux --compile_only --gen_script myproject.nim + 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 Nimrod invoke a cross compiler toolchain:: +Another way is to make Nim invoke a cross compiler toolchain:: - nimrod c --cpu:arm --os:linux myproject.nim + 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 @@ -212,16 +212,16 @@ configuration file should contain something like:: DLL generation ============== -Nimrod supports the generation of DLLs. However, there must be only one +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 Nimrod DLL depends +``nimrtl.dll``. This means that every generated Nim DLL depends on ``nimrtl.dll``. To generate the "nimrtl.dll" file, use the command:: - nimrod c -d:release lib/nimrtl.nim + nim c -d:release lib/nimrtl.nim To link against ``nimrtl.dll`` use the command:: - nimrod c -d:useNimRtl myprog.nim + 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! @@ -243,9 +243,9 @@ Define Effect version. ``useFork`` Makes ``osproc`` use ``fork`` instead of ``posix_spawn``. ``useNimRtl`` Compile and link against ``nimrtl.dll``. -``useMalloc`` Makes Nimrod use C's `malloc`:idx: instead of Nimrod'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 Nimrod's GC for *soft* realtime +``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``. @@ -258,8 +258,8 @@ Define Effect Additional Features =================== -This section describes Nimrod's additional features that are not listed in the -Nimrod manual. Some of the features here only make sense for the C code +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. @@ -267,13 +267,13 @@ 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 Nimrod that it should not generate a declaration for the symbol in +It tells Nim that it should not generate a declaration for the symbol in the C code. For example: -.. code-block:: Nimrod +.. code-block:: Nim var EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as - # Nimrod does not know its value + # Nim does not know its value However, the ``header`` pragma is often the better alternative. @@ -286,14 +286,14 @@ 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:: Nimrod +.. code-block:: Nim type PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer - # import C's FILE* type; Nimrod will treat it as a new pointer type + # 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, Nimrod +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. @@ -304,7 +304,7 @@ IncompleteStruct pragma The ``incompleteStruct`` pragma tells the compiler to not use the underlying C ``struct`` in a ``sizeof`` expression: -.. code-block:: Nimrod +.. code-block:: Nim type TDIR* {.importc: "DIR", header: "<dirent.h>", final, pure, incompleteStruct.} = object @@ -315,10 +315,10 @@ Compile pragma The ``compile`` pragma can be used to compile and link a C/C++ source file with the project: -.. code-block:: Nimrod +.. code-block:: Nim {.compile: "myfile.cpp".} -**Note**: Nimrod computes a CRC checksum and only recompiles the file if it +**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. @@ -327,7 +327,7 @@ Link pragma ----------- The ``link`` pragma can be used to link an additional file with the project: -.. code-block:: Nimrod +.. code-block:: Nim {.link: "myfile.o".} @@ -336,13 +336,13 @@ PassC pragma The ``passC`` pragma can be used to pass additional parameters to the C compiler like you would using the commandline switch ``--passC``: -.. code-block:: Nimrod +.. code-block:: Nim {.passC: "-Wall -Werror".} Note that you can use ``gorge`` from the `system module <system.html>`_ to embed parameters from an external command at compile time: -.. code-block:: Nimrod +.. code-block:: Nim {.passC: gorge("pkg-config --cflags sdl").} PassL pragma @@ -350,13 +350,13 @@ PassL pragma The ``passL`` pragma can be used to pass additional parameters to the linker like you would using the commandline switch ``--passL``: -.. code-block:: Nimrod +.. code-block:: Nim {.passL: "-lSDLmain -lSDL".} Note that you can use ``gorge`` from the `system module <system.html>`_ to embed parameters from an external command at compile time: -.. code-block:: Nimrod +.. code-block:: Nim {.passL: gorge("pkg-config --libs sdl").} @@ -369,16 +369,16 @@ extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code. Example: -.. code-block:: Nimrod +.. code-block:: Nim {.emit: """ static int cvariable = 420; """.} {.push stackTrace:off.} proc embedsC() = - var nimrodVar = 89 - # use backticks to access Nimrod symbols within an emit section: - {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimrodVar`);""".} + var nimVar = 89 + # use backticks to access Nim symbols within an emit section: + {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".} {.pop.} embedsC() @@ -392,7 +392,7 @@ code then uses the C++ method calling syntax: ``obj->method(arg)``. In addition with the ``header`` and ``emit`` pragmas this allows *sloppy* interfacing with libraries written in C++: -.. code-block:: Nimrod +.. code-block:: Nim # Horrible example of how to interface with a C++ engine ... ;-) {.link: "/usr/lib/libIrrlicht.so".} @@ -431,7 +431,7 @@ 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:: Nimrod +.. code-block:: Nim # horrible example of how to interface with GNUStep ... {.passL: "-lobjc".} @@ -475,11 +475,11 @@ emits Objective C code. CodegenDecl pragma ------------------ -The ``codegenDecl`` pragma can be used to directly influence Nimrod's code +The ``codegenDecl`` pragma can be used to directly influence Nim's code generator. It receives a format string that determines how the variable or proc is declared in the generated code: -.. code-block:: nimrod +.. code-block:: nim var a {.codegenDecl: "$# progmem $#".}: int @@ -494,7 +494,7 @@ The ``injectStmt`` pragma can be used to inject a statement before every other statement in the current module. It is only supposed to be used for debugging: -.. code-block:: nimrod +.. code-block:: nim {.injectStmt: gcInvariants().} # ... complex code here that produces crashes ... @@ -523,7 +523,7 @@ is raised. Debugger option --------------- -The ``debugger`` option enables or disables the *Embedded Nimrod Debugger*. +The ``debugger`` option enables or disables the *Embedded Nim Debugger*. See the documentation of endb_ for further information. @@ -545,11 +545,11 @@ in C/C++). Source code style ================= -Nimrod allows you to `mix freely case and underscores as identifier separators +Nim allows you to `mix freely case and underscores as identifier separators <manual.html#identifiers-keywords>`_, so variables named ``MyPrecioussInt`` and ``my_preciouss_int`` are equivalent: -.. code-block:: Nimrod +.. code-block:: Nim var MyPrecioussInt = 3 # Following line compiles fine! echo my_preciouss_int @@ -557,16 +557,16 @@ Nimrod allows you to `mix freely case and underscores as identifier separators Since this can lead to many variants of the same source code (you can use `nimgrep <nimgrep.html>`_ instead of your typical ``grep`` to ignore style problems) the compiler provides the command ``pretty`` to help unifying the -style of source code. Running ``nimrod pretty ugly_test.nim`` with this +style of source code. Running ``nim pretty ugly_test.nim`` with this example will generate a secondary file named ``ugly_test.pretty.nim`` with the following content: -.. code-block:: Nimrod +.. code-block:: Nim var MyPrecioussInt = 3 # Following line compiles fine! echo MyPrecioussInt -During execution the ``pretty`` command will also run on Nimrod's standard +During execution the ``pretty`` command will also run on Nim's standard library, since it doesn't differentiate the standard library as something special, and hence will warn of many *errors* which are out of your hand to fix, creating respective ``.pretty.nim`` files all the way. You can ignore @@ -583,11 +583,11 @@ important changes for you to review. In this case the command is warning that a variable name should not start with a capital letter, which is usually reserved to `object types <tut2.html#objects>`_. To learn about the accepted `camel case style <https://en.wikipedia.org/wiki/Camelcase>`_ read `Coding Guidelines in -the Internals of Nimrod Compiler <intern.html#coding-guidelines>`_ or `Coding -Guidelines <https://github.com/Araq/Nimrod/wiki/Coding-Guidelines>`_ and `NEP 1 -: Style Guide for Nimrod Code -<https://github.com/Araq/Nimrod/wiki/NEP-1-:-Style-Guide-for-Nimrod-Code>`_ -from the Nimrod `GitHub wiki<https://github.com/Araq/Nimrod/wiki>`_. +the Internals of Nim Compiler <intern.html#coding-guidelines>`_ or `Coding +Guidelines <https://github.com/Araq/Nim/wiki/Coding-Guidelines>`_ and `NEP 1 +: Style Guide for Nim Code +<https://github.com/Araq/Nim/wiki/NEP-1-:-Style-Guide-for-Nim-Code>`_ +from the Nim `GitHub wiki<https://github.com/Araq/Nim/wiki>`_. This command is safe to run because it will never attempt to overwrite your existing sources, but the respective ``.pretty.nim`` files **will** be @@ -597,14 +597,14 @@ overwritten without notice. DynlibOverride ============== -By default Nimrod'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 against. For instance, to link statically against Lua this command might work on Linux:: - nimrod c --dynlibOverride:lua --passL:liblua.lib program.nim + nim c --dynlibOverride:lua --passL:liblua.lib program.nim Backend language options @@ -614,32 +614,32 @@ The typical compiler usage involves using the ``compile`` or ``c`` command to transform a ``.nim`` file into one or more ``.c`` files which are then compiled with the platform's C compiler into a static binary. However there are other commands to compile to C++, Objective-C or Javascript. More details -can be read in the `Nimrod Backend Integration document <backends.html>`_. +can be read in the `Nim Backend Integration document <backends.html>`_. -Nimrod documentation tools -========================== +Nim documentation tools +======================= -Nimrod provides the `doc`:idx: and `doc2`:idx: commands to generate HTML +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>`_. -Nimrod idetools integration -=========================== +Nim idetools integration +======================== -Nimrod provides language integration with external IDEs through the +Nim provides language integration with external IDEs through the idetools command. See the documentation of `idetools <idetools.html>`_ for further information. -Nimrod interactive mode -======================= +Nim interactive mode +==================== -The Nimrod compiler supports an interactive mode. This is also known as -a `REPL`:idx: (*read eval print loop*). If Nimrod has been built with the +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 Nimrod in interactive mode use the command -``nimrod i``. To quit use the ``quit()`` command. To determine whether an input +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). @@ -648,8 +648,8 @@ line is an incomplete statement to be continued these rules are used: does not work if the line contains more than one ``"""``. -Nimrod for embedded systems -=========================== +Nim for embedded systems +======================== The standard library can be avoided to a point where C code generation for 16bit micro controllers is feasible. Use the `standalone`:idx: target @@ -661,7 +661,7 @@ target. For example, to generate code for an `AVR`:idx: processor use this command:: - nimrod c --cpu:avr --os:standalone --deadCodeElim:on --genScript x.nim + nim c --cpu:avr --os:standalone --deadCodeElim:on --genScript x.nim For the ``standalone`` target you need to provide a file ``panicoverride.nim``. @@ -669,27 +669,27 @@ See ``tests/manyloc/standalone/panicoverride.nim`` for an example implementation. -Nimrod for realtime systems -=========================== +Nim for realtime systems +======================== -See the documentation of Nimrod's soft realtime `GC <gc.html>`_ for further +See the documentation of Nim's soft realtime `GC <gc.html>`_ for further information. -Debugging with Nimrod -===================== +Debugging with Nim +================== -Nimrod comes with its own *Embedded Nimrod Debugger*. See +Nim comes with its own *Embedded Nim Debugger*. See the documentation of endb_ for further information. -Optimizing for Nimrod -===================== +Optimizing for Nim +================== -Nimrod has no separate optimizer, but the C code that is produced is very +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. Nimrod has been designed to encourage -efficient code: The most readable code in Nimrod is often the most efficient +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: @@ -706,32 +706,32 @@ This section can only help you with the last item. Optimizing string handling -------------------------- -String assignments are sometimes expensive in Nimrod: They are required to +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:: Nimrod +.. 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:: Nimrod +.. 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:: Nimrod +.. 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:: Nimrod +.. code-block:: Nim var s = "abc" shallow(s) # mark 's' as shallow string var x = s # now might not copy the string! @@ -744,7 +744,7 @@ 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:: Nimrod +.. code-block:: Nim case normalize(k.key) of "name": c.name = v of "displayname": c.displayName = v diff --git a/doc/nimgrep.txt b/doc/nimgrep.txt index 67aaa427e..e2f7b228f 100644 --- a/doc/nimgrep.txt +++ b/doc/nimgrep.txt @@ -10,7 +10,7 @@ Nimgrep is a command line tool for search&replace tasks. It can search for regex or peg patterns and can search whole directories at once. User confirmation for every single replace operation can be requested. -Nimgrep has particularly good support for Nimrod's +Nimgrep has particularly good support for Nim's eccentric *style insensitivity*. Apart from that it is a generic text manipulation tool. @@ -20,7 +20,7 @@ Installation Compile nimgrep with the command:: - nimrod c -d:release tools/nimgrep.nim + nim c -d:release tools/nimgrep.nim And copy the executable somewhere in your ``$PATH``. diff --git a/doc/niminst.txt b/doc/niminst.txt index 8d95d01c9..d743c5187 100644 --- a/doc/niminst.txt +++ b/doc/niminst.txt @@ -3,14 +3,14 @@ ========================= :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: Introduction ============ -niminst is a tool to generate an installer for a Nimrod program. Currently +niminst is a tool to generate an installer for a Nim program. Currently it can create an installer for Windows via `Inno Setup <http://www.jrsoftware.org/isinfo.php>`_ as well as installation/deinstallation scripts for UNIX. Later versions will support @@ -24,7 +24,7 @@ systems. Configuration file ================== -niminst uses the Nimrod `parsecfg <parsecfg.html>`_ module to parse the +niminst uses the Nim `parsecfg <parsecfg.html>`_ module to parse the configuration file. Here's an example of how the syntax looks like: .. include:: doc/mytest.cfg @@ -187,9 +187,9 @@ Key description Real world example ================== -The installers for the Nimrod compiler itself are generated by niminst. Have a +The installers for the Nim compiler itself are generated by niminst. Have a look at its configuration file: -.. include:: compiler/nimrod.ini +.. include:: compiler/nim.ini :literal: diff --git a/doc/overview.txt b/doc/overview.txt index 242039086..5b41752ae 100644 --- a/doc/overview.txt +++ b/doc/overview.txt @@ -1,9 +1,9 @@ ============================= -Nimrod Documentation Overview +Nim Documentation Overview ============================= :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| .. include:: ../doc/docs.txt diff --git a/doc/pegdocs.txt b/doc/pegdocs.txt index eb7f4562f..d22d81a5a 100644 --- a/doc/pegdocs.txt +++ b/doc/pegdocs.txt @@ -171,7 +171,7 @@ The PEG parser implements this grammar (written in PEG syntax):: expression, identifiers are not interpreted as non-terminals, but are interpreted as verbatim string: -.. code-block:: nimrod +.. code-block:: nim abc =~ peg"abc" # is true So it is not necessary to write ``peg" 'abc' "`` in the above example. @@ -180,19 +180,19 @@ So it is not necessary to write ``peg" 'abc' "`` in the above example. Examples -------- -Check if `s` matches Nimrod's "while" keyword: +Check if `s` matches Nim's "while" keyword: -.. code-block:: nimrod +.. code-block:: nim s =~ peg" y'while'" Exchange (key, val)-pairs: -.. code-block:: nimrod +.. code-block:: nim "key: val; key2: val2".replace(peg"{\ident} \s* ':' \s* {\ident}", "$2: $1") Determine the ``#include``'ed files of a C file: -.. code-block:: nimrod +.. code-block:: nim for line in lines("myfile.c"): if line =~ peg"""s <- ws '#include' ws '"' {[^"]+} '"' ws comment <- '/*' @ '*/' / '//' .* @@ -212,7 +212,7 @@ example ``*`` should not be greedy, so ``\[.*?\]`` should be used instead. PEG construction ---------------- -There are two ways to construct a PEG in Nimrod code: +There are two ways to construct a PEG in Nim code: (1) Parsing a string into an AST which consists of `TPeg` nodes with the `peg` proc. (2) Constructing the AST directly with proc calls. This method does not diff --git a/doc/readme.txt b/doc/readme.txt index 7f509bd39..e5d9e2c27 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -1,7 +1,7 @@ ============================ -Nimrod's documenation system +Nim's documenation system ============================ -This folder contains Nimrod's documentation. The documentation +This folder contains Nim's documentation. The documentation is written in a format called *reStructuredText*, a markup language that reads like ASCII and can be converted to HTML automatically! diff --git a/doc/regexprs.txt b/doc/regexprs.txt index 930352948..d912c623e 100644 --- a/doc/regexprs.txt +++ b/doc/regexprs.txt @@ -44,9 +44,9 @@ As the regular expressions supported by this module are enormous, the reader is referred to http://perldoc.perl.org/perlre.html for the full documentation of Perl's regular expressions. -Because the backslash ``\`` is a meta character both in the Nimrod +Because the backslash ``\`` is a meta character both in the Nim programming language and in regular expressions, it is strongly -recommended that one uses the *raw* strings of Nimrod, so that +recommended that one uses the *raw* strings of Nim, so that backslashes are interpreted by the regular expression engine:: r"\S" # matches any character that is not whitespace diff --git a/doc/rst.txt b/doc/rst.txt index 4199598d1..1e858d617 100644 --- a/doc/rst.txt +++ b/doc/rst.txt @@ -1,9 +1,9 @@ =========================================================================== - Nimrod's implementation of |rst| + Nim's implementation of |rst| =========================================================================== :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: @@ -11,15 +11,15 @@ Introduction ============ This document describes the subset of `Docutils`_' `reStructuredText`_ as it -has been implemented in the Nimrod compiler for generating documentation. +has been implemented in the Nim compiler for generating documentation. Elements of |rst| that are not listed here have not been implemented. -Unfortunately, the specification of |rst| is quite vague, so Nimrod is not as +Unfortunately, the specification of |rst| is quite vague, so Nim is not as compatible to the original implementation as one would like. -Even though Nimrod's |rst| parser does not parse all constructs, it is pretty +Even though Nim's |rst| parser does not parse all constructs, it is pretty usable. The missing features can easily be circumvented. An indication of this -fact is that Nimrod's *whole* documentation itself (including this document) is -processed by Nimrod's |rst| parser. (Which is an order of magnitude faster than +fact is that Nim's *whole* documentation itself (including this document) is +processed by Nim's |rst| parser. (Which is an order of magnitude faster than Docutils' parser.) @@ -65,19 +65,19 @@ Definition lists Save this code to the file "greeting.nim". Now compile and run it: - ``nimrod run greeting.nim`` + ``nim run greeting.nim`` -As you see, with the ``run`` command Nimrod executes the file automatically +As you see, with the ``run`` command Nim executes the file automatically after compilation. You can even give your program command line arguments by appending them after the filename that is to be compiled and run: - ``nimrod run greeting.nim arg1 arg2`` + ``nim run greeting.nim arg1 arg2`` Tables ====== -Nimrod only implements simple tables of the form:: +Nim only implements simple tables of the form:: ================== =============== =================== header 1 header 2 header n diff --git a/doc/sets_fragment.txt b/doc/sets_fragment.txt index fba355269..32dbac1c2 100644 --- a/doc/sets_fragment.txt +++ b/doc/sets_fragment.txt @@ -6,7 +6,7 @@ Sets can be constructed via the set constructor: ``{}`` is the empty set. The empty set is type compatible with any concrete set type. The constructor can also be used to include elements (and ranges of elements): -.. code-block:: nimrod +.. code-block:: nim type TCharSet = set[char] var diff --git a/doc/spawn.txt b/doc/spawn.txt index c5c96ecf8..fb2f851c7 100644 --- a/doc/spawn.txt +++ b/doc/spawn.txt @@ -2,7 +2,7 @@ Parallel & Spawn ========================================================== -Nimrod has two flavors of parallelism: +Nim has two flavors of parallelism: 1) `Structured`:idx parallelism via the ``parallel`` statement. 2) `Unstructured`:idx: parallelism via the standalone ``spawn`` statement. @@ -19,12 +19,42 @@ read prematurely within a ``parallel`` section and so there is no need for the overhead of an indirection via ``FlowVar[T]`` to ensure correctness. +Spawn statement +=============== + +A standalone ``spawn`` statement is a simple construct. It executes +the passed expression on the thread pool and returns a `data flow variable`:idx: +``FlowVar[T]`` that can be read from. The reading with the ``^`` operator is +**blocking**. However, one can use ``awaitAny`` to wait on multiple flow +variables at the same time: + +.. code-block:: nim + import threadpool, ... + + # wait until 2 out of 3 servers received the update: + proc main = + var responses = newSeq[RawFlowVar](3) + for i in 0..2: + responses[i] = spawn tellServer(Update, "key", "value") + var index = awaitAny(responses) + assert index >= 0 + responses.del(index) + discard awaitAny(responses) + +Data flow variables ensure that no data races +are possible. Due to technical limitations not every type ``T`` is possible in +a data flow variable: ``T`` has to be of the type ``ref``, ``string``, ``seq`` +or of a type that doesn't contain a type that is garbage collected. This +restriction will be removed in the future. + + + Parallel statement ================== Example: -.. code-block:: nimrod +.. code-block:: nim # Compute PI in an inefficient way import strutils, math, threadpool @@ -42,7 +72,7 @@ Example: The parallel statement is the preferred mechanism to introduce parallelism -in a Nimrod program. A subset of the Nimrod language is valid within a +in a Nim program. A subset of the Nim language is valid within a ``parallel`` section. This subset is checked to be free of data races at compile time. A sophisticated `disjoint checker`:idx: ensures that no data races are possible even though shared memory is extensively supported! @@ -64,35 +94,3 @@ restrictions / changes: * Slices are optimized so that no copy is performed. This optimization is not yet performed for ordinary slices outside of a ``parallel`` section. Slices are also special in that they currently do not support negative indexes! - - - - -Spawn statement -=============== - -A standalone ``spawn`` statement is a simple construct. It executes -the passed expression on the thread pool and returns a `data flow variable`:idx: -``FlowVar[T]`` that can be read from. The reading with the ``^`` operator is -**blocking**. However, one can use ``awaitAny`` to wait on multiple flow -variables at the same time: - -.. code-block:: nimrod - import threadpool, ... - - # wait until 2 out of 3 servers received the update: - proc main = - var responses = newSeq[RawFlowVar](3) - for i in 0..2: - responses[i] = spawn tellServer(Update, "key", "value") - var index = awaitAny(responses) - assert index >= 0 - responses.del(index) - discard awaitAny(responses) - -Like the ``parallel`` statement data flow variables ensure that no data races -are possible. Due to technical limitations not every type ``T`` is possible in -a data flow variable: ``T`` has to be of the type ``ref``, ``string``, ``seq`` -or of a type that doesn't contain a type that is garbage collected. This -restriction will be removed in the future. - diff --git a/doc/subexes.txt b/doc/subexes.txt index 3b688fd0a..decf30eef 100644 --- a/doc/subexes.txt +++ b/doc/subexes.txt @@ -16,10 +16,12 @@ Notation meaning ``$name`` use named argument, you can wrap the named argument in curly braces (eg. ``${name}``) to separate it from the next characters. +``$$`` produces a single ``$`` ``$1`` use first argument ``$-1`` use last argument ``${1..3}`` use arguments 1 to 3 ``${..}`` use all arguments +``$*`` use all arguments (same as ``${..}``) ``${#..}`` use all remaining arguments ``${..-2}`` use all arguments except the last argument ``${$1}`` use argument X where ``X = parseInt(arg[1])`` @@ -45,7 +47,7 @@ Notation meaning Examples ======== -.. code-block:: nimrod +.. code-block:: nim subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)" diff --git a/doc/tools.txt b/doc/tools.txt index 0127bc4a8..0b39762c6 100644 --- a/doc/tools.txt +++ b/doc/tools.txt @@ -1,20 +1,20 @@ -=========================== -Tools available with Nimrod -=========================== +======================== +Tools available with Nim +======================== The standard distribution ships with the following tools: -- | `Nimrod Installation Generator <niminst.html>`_ - | How to generate a nice installer for your Nimrod program. +- | `Nim Installation Generator <niminst.html>`_ + | How to generate a nice installer for your Nim program. - | `C2nim <c2nim.html>`_ - | C to Nimrod source converter. Translates C header files to Nimrod. + | C to Nim source converter. Translates C header files to Nim. - | `nimgrep <nimgrep.html>`_ - | Nimrod search and replace utility. + | Nim search and replace utility. - | `endb <endb.html>`_ - | Nimrod's slow platform independent embedded debugger. + | Nim's slow platform independent embedded debugger. - | `estp <estp.html>`_ - | Nimrod's slow platform independent embedded stack trace profiler. + | Nim's slow platform independent embedded stack trace profiler. diff --git a/doc/tut1.txt b/doc/tut1.txt index ee642ce17..950f758f1 100644 --- a/doc/tut1.txt +++ b/doc/tut1.txt @@ -1,9 +1,9 @@ -======================== -Nimrod Tutorial (Part I) -======================== +===================== +Nim Tutorial (Part I) +===================== :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: @@ -16,7 +16,7 @@ Introduction </p></blockquote> -This document is a tutorial for the programming language *Nimrod*. +This document is a tutorial for the programming language *Nim*. This tutorial assumes that you are familiar with basic programming concepts like variables, types or statements but is kept very basic. The `manual <manual.html>`_ contains many more examples of the advanced language features. @@ -28,7 +28,7 @@ The first program We start the tour with a modified "hello world" program: -.. code-block:: Nimrod +.. code-block:: Nim # This is a comment echo("What's your name? ") var name: string = readLine(stdin) @@ -37,47 +37,47 @@ We start the tour with a modified "hello world" program: Save this code to the file "greetings.nim". Now compile and run it:: - nimrod compile --run greetings.nim + nim compile --run greetings.nim -With the ``--run`` `switch <nimrodc.html#command-line-switches>`_ Nimrod +With the ``--run`` `switch <nimc.html#command-line-switches>`_ Nim executes the file automatically after compilation. You can give your program command line arguments by appending them after the filename:: - nimrod compile --run greetings.nim arg1 arg2 + nim compile --run greetings.nim arg1 arg2 Commonly used commands and switches have abbreviations, so you can also use:: - nimrod c -r greetings.nim + nim c -r greetings.nim To compile a release version use:: - nimrod c -d:release greetings.nim + nim c -d:release greetings.nim -By default the Nimrod compiler generates a large amount of runtime checks +By default the Nim compiler generates a large amount of runtime checks aiming for your debugging pleasure. With ``-d:release`` these checks are `turned off and optimizations are turned on -<nimrodc.html#compile-time-symbols>`_. +<nimc.html#compile-time-symbols>`_. Though it should be pretty obvious what the program does, I will explain the syntax: statements which are not indented are executed when the program -starts. Indentation is Nimrod's way of grouping statements. Indentation is +starts. Indentation is Nim's way of grouping statements. Indentation is done with spaces only, tabulators are not allowed. String literals are enclosed in double quotes. The ``var`` statement declares a new variable named ``name`` of type ``string`` with the value that is -returned by the `readLine <system.html#readLine,TFile>`_ procedure. Since the -compiler knows that `readLine <system.html#readLine,TFile>`_ returns a string, +returned by the `readLine <system.html#readLine,File>`_ procedure. Since the +compiler knows that `readLine <system.html#readLine,File>`_ returns a string, you can leave out the type in the declaration (this is called `local type inference`:idx:). So this will work too: -.. code-block:: Nimrod +.. code-block:: Nim var name = readLine(stdin) Note that this is basically the only form of type inference that exists in -Nimrod: it is a good compromise between brevity and readability. +Nim: it is a good compromise between brevity and readability. The "hello world" program contains several identifiers that are already known -to the compiler: ``echo``, `readLine <system.html#readLine,TFile>`_, etc. +to the compiler: ``echo``, `readLine <system.html#readLine,File>`_, etc. These built-ins are declared in the system_ module which is implicitly imported by any other module. @@ -85,8 +85,8 @@ imported by any other module. Lexical elements ================ -Let us look at Nimrod's lexical elements in more detail: like other -programming languages Nimrod consists of (string) literals, identifiers, +Let us look at Nim's lexical elements in more detail: like other +programming languages Nim consists of (string) literals, identifiers, keywords, comments, operators, and other punctuation marks. @@ -97,7 +97,7 @@ String literals are enclosed in double quotes; character literals in single quotes. Special characters are escaped with ``\``: ``\n`` means newline, ``\t`` means tabulator, etc. There are also *raw* string literals: -.. code-block:: Nimrod +.. code-block:: Nim r"C:\program files\nim" In raw literals the backslash is not an escape character. @@ -112,54 +112,23 @@ Comments -------- Comments start anywhere outside a string or character literal with the -hash character ``#``. Documentation comments start with ``##``. Multiline -comments need to be aligned at the same column: - -.. code-block:: nimrod - - i = 0 # This is a single comment over multiple lines belonging to the - # assignment statement. - # This is a new comment belonging to the current block, but to no particular - # statement. - i = i + 1 # This a new comment that is NOT - echo(i) # continued here, because this comment refers to the echo statement - - -The alignment requirement does not hold if the preceding comment piece ends in -a backslash: +hash character ``#``. Documentation comments start with ``##``: -.. code-block:: nimrod - type - TMyObject {.final, pure, acyclic.} = object # comment continues: \ - # we have lots of space here to comment 'TMyObject'. - # This line belongs to the comment as it's properly aligned. - - -Comments are tokens; they are only allowed at certain places in the input file -as they belong to the syntax tree! This feature enables perfect source-to-source -transformations (such as pretty-printing) and simpler documentation generators. -A nice side-effect is that the human reader of the code always knows exactly -which code snippet the comment refers to. Since comments are a proper part of -the syntax, watch their indentation: +.. code-block:: nim + # A comment. + + var myVariable: int ## a documentation comment -.. code-block:: - echo("Hello!") - # comment has the same indentation as above statement -> fine - echo("Hi!") - # comment has not the correct indentation level -> syntax error! - -**Note**: To comment out a large piece of code, it is often better to use a -``when false:`` statement. -.. code-block:: nimrod - when false: - brokenCode() +Documentation comments are tokens; they are only allowed at certain places in +the input file as they belong to the syntax tree! This feature enables simpler +documentation generators. -Another option is to use the `discard statement`_ together with *long string +You can also use the `discard statement`_ together with *long string literals* to create block comments: -.. code-block:: nimrod - discard """ You can have any Nimrod code text commented +.. code-block:: nim + discard """ You can have any Nim code text commented out inside this with no indentation restrictions. yes("May I ask a pointless question?") """ @@ -204,7 +173,7 @@ to a storage location: ``=`` is the *assignment operator*. The assignment operator cannot be overloaded, overwritten or forbidden, but this might change in a future version -of Nimrod. You can declare multiple variables with a single assignment +of Nim. You can declare multiple variables with a single assignment statement and all the variables will have the same value: .. code-block:: @@ -229,7 +198,7 @@ Constants are symbols which are bound to a value. The constant's value cannot change. The compiler must be able to evaluate the expression in a constant declaration at compile time: -.. code-block:: nimrod +.. code-block:: nim const x = "abc" # the constant x contains the string "abc" Indentation can be used after the ``const`` keyword to list a whole section of @@ -277,7 +246,7 @@ If statement The if statement is one way to branch the control flow: -.. code-block:: nimrod +.. code-block:: nim let name = readLine(stdin) if name == "": echo("Poor soul, you lost your name?") @@ -298,7 +267,7 @@ Case statement Another way to branch is provided by the case statement. A case statement is a multi-branch: -.. code-block:: nimrod +.. code-block:: nim let name = readLine(stdin) case name of "": @@ -317,7 +286,7 @@ The case statement can deal with integers, other ordinal types and strings. (What an ordinal type is will be explained soon.) For integers or other ordinal types value ranges are also possible: -.. code-block:: nimrod +.. code-block:: nim # this statement will be explained later: from strutils import parseInt @@ -333,7 +302,7 @@ every value that ``n`` may contain, but the code only handles the values (though it is possible thanks to the range notation), we fix this by telling the compiler that for every other value nothing should be done: -.. code-block:: nimrod +.. code-block:: nim ... case n of 0..2, 4..7: echo("The number is in the set: {0, 1, 2, 4, 5, 6, 7}") @@ -343,7 +312,7 @@ the compiler that for every other value nothing should be done: The empty `discard statement`_ is a *do nothing* statement. The compiler knows that a case statement with an else part cannot fail and thus the error disappears. Note that it is impossible to cover all possible string values: -that is why there is no such check for string cases. +that is why string cases always need an ``else`` branch. In general the case statement is used for subrange types or enumerations where it is of great help that the compiler checks that you covered any possible @@ -355,7 +324,7 @@ While statement The while statement is a simple looping construct: -.. code-block:: nimrod +.. code-block:: nim echo("What's your name? ") var name = readLine(stdin) @@ -375,7 +344,7 @@ The ``for`` statement is a construct to loop over any element an *iterator* provides. The example uses the built-in `countup <system.html#countup>`_ iterator: -.. code-block:: nimrod +.. code-block:: nim echo("Counting to ten: ") for i in countup(1, 10): echo($i) @@ -387,7 +356,7 @@ other types into a string. The variable ``i`` is implicitly declared by the <system.html#countup>`_ returns. ``i`` runs through the values 1, 2, .., 10. Each value is ``echo``-ed. This code does the same: -.. code-block:: nimrod +.. code-block:: nim echo("Counting to 10: ") var i = 1 while i <= 10: @@ -397,16 +366,16 @@ Each value is ``echo``-ed. This code does the same: Counting down can be achieved as easily (but is less often needed): -.. code-block:: nimrod +.. code-block:: nim echo("Counting down from 10 to 1: ") for i in countdown(10, 1): echo($i) # --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines -Since counting up occurs so often in programs, Nimrod also has a `.. +Since counting up occurs so often in programs, Nim also has a `.. <system.html#...i,S,T>`_ iterator that does the same: -.. code-block:: nimrod +.. code-block:: nim for i in 1..10: ... @@ -417,7 +386,7 @@ Control flow statements have a feature not covered yet: they open a new scope. This means that in the following example, ``x`` is not accessible outside the loop: -.. code-block:: nimrod +.. code-block:: nim while false: var x = "hi" echo(x) # does not work @@ -426,7 +395,7 @@ A while (for) statement introduces an implicit block. Identifiers are only visible within the block they have been declared. The ``block`` statement can be used to open a new block explicitly: -.. code-block:: nimrod +.. code-block:: nim block myblock: var x = "hi" echo(x) # does not work either @@ -440,7 +409,7 @@ A block can be left prematurely with a ``break`` statement. The break statement can leave a ``while``, ``for``, or a ``block`` statement. It leaves the innermost construct, unless a label of a block is given: -.. code-block:: nimrod +.. code-block:: nim block myblock: echo("entering block") while true: @@ -461,7 +430,7 @@ Continue statement Like in many other programming languages, a ``continue`` statement starts the next iteration immediately: -.. code-block:: nimrod +.. code-block:: nim while true: let x = readLine(stdin) if x == "": continue @@ -473,7 +442,7 @@ When statement Example: -.. code-block:: nimrod +.. code-block:: nim when system.hostOS == "windows": echo("running on Windows!") @@ -504,17 +473,17 @@ possible. Statements and indentation ========================== -Now that we covered the basic control flow statements, let's return to Nimrod +Now that we covered the basic control flow statements, let's return to Nim indentation rules. -In Nimrod there is a distinction between *simple statements* and *complex +In Nim there is a distinction between *simple statements* and *complex statements*. *Simple statements* cannot contain other statements: Assignment, procedure calls or the ``return`` statement belong to the simple statements. *Complex statements* like ``if``, ``when``, ``for``, ``while`` can contain other statements. To avoid ambiguities, complex statements always have to be indented, but single simple statements do not: -.. code-block:: nimrod +.. code-block:: nim # no indentation needed for single assignment statement: if x: x = false @@ -535,7 +504,7 @@ to be indented, but single simple statements do not: condition in an if statement is an example for an expression. Expressions can contain indentation at certain places for better readability: -.. code-block:: nimrod +.. code-block:: nim if thisIsaLongCondition() and thisIsAnotherLongCondition(1, @@ -548,7 +517,7 @@ an open parenthesis and after commas. With parenthesis and semicolons ``(;)`` you can use statements where only an expression is allowed: -.. code-block:: nimrod +.. code-block:: nim # computes fac(4) at compile time: const fac4 = (var x = 1; for i in 1..4: x *= i; x) @@ -557,11 +526,11 @@ Procedures ========== To define new commands like `echo <system.html#echo>`_ and `readLine -<system.html#readLine,TFile>`_ in the examples, the concept of a `procedure` -is needed. (Some languages call them *methods* or *functions*.) In Nimrod new +<system.html#readLine,File>`_ in the examples, the concept of a `procedure` +is needed. (Some languages call them *methods* or *functions*.) In Nim new procedures are defined with the ``proc`` keyword: -.. code-block:: nimrod +.. code-block:: nim proc yes(question: string): bool = echo(question, " (y/n)") while true: @@ -597,7 +566,7 @@ shorthand for ``return result``. The ``result`` value is always returned automatically at the end a procedure if there is no ``return`` statement at the exit. -.. code-block:: nimrod +.. code-block:: nim proc sumTillNegative(x: varargs[int]): int = for i in x: if i < 0: @@ -624,7 +593,7 @@ most efficient way. If a mutable variable is needed inside the procedure, it has to be declared with ``var`` in the procedure body. Shadowing the parameter name is possible, and actually an idiom: -.. code-block:: nimrod +.. code-block:: nim proc printSeq(s: seq, nprinted: int = -1) = var nprinted = if nprinted == -1: s.len else: min(nprinted, s.len) for i in 0 .. <nprinted: @@ -633,7 +602,7 @@ is possible, and actually an idiom: If the procedure needs to modify the argument for the caller, a ``var`` parameter can be used: -.. code-block:: nimrod +.. code-block:: nim proc divmod(a, b: int; res, remainder: var int) = res = a div b # integer division remainder = a mod b # integer modulo operation @@ -653,17 +622,17 @@ a tuple as a return value instead of using var parameters. Discard statement ----------------- To call a procedure that returns a value just for its side effects and ignoring -its return value, a ``discard`` statement **has** to be used. Nimrod does not +its return value, a ``discard`` statement **has** to be used. Nim does not allow to silently throw away a return value: -.. code-block:: nimrod +.. code-block:: nim discard yes("May I ask a pointless question?") The return value can be ignored implicitly if the called proc/iterator has been declared with the ``discardable`` pragma: -.. code-block:: nimrod +.. code-block:: nim proc p(x, y: int): int {.discardable.} = return x + y @@ -681,7 +650,7 @@ parameters appear. This is especially true for procedures that construct a complex data type. Therefore the arguments to a procedure can be named, so that it is clear which argument belongs to which parameter: -.. code-block:: nimrod +.. code-block:: nim proc createWindow(x, y, width, height: int; title: string; show: bool): Window = ... @@ -693,7 +662,7 @@ Now that we use named arguments to call ``createWindow`` the argument order does not matter anymore. Mixing named arguments with ordered arguments is also possible, but not very readable: -.. code-block:: nimrod +.. code-block:: nim var w = createWindow(0, 0, title = "My Application", height = 600, width = 800, true) @@ -706,7 +675,7 @@ To make the ``createWindow`` proc easier to use it should provide `default values`, these are values that are used as arguments if the caller does not specify them: -.. code-block:: nimrod +.. code-block:: nim proc createWindow(x = 0, y = 0, width = 500, height = 700, title = "unknown", show = true): Window = @@ -723,9 +692,9 @@ no need to write ``title: string = "unknown"``, for example. Overloaded procedures --------------------- -Nimrod provides the ability to overload procedures similar to C++: +Nim provides the ability to overload procedures similar to C++: -.. code-block:: nimrod +.. code-block:: nim proc toString(x: int): string = ... proc toString(x: bool): string = if x: result = "true" @@ -735,7 +704,7 @@ Nimrod provides the ability to overload procedures similar to C++: echo(toString(true)) # calls the toString(x: bool) proc (Note that ``toString`` is usually the `$ <system.html#$>`_ operator in -Nimrod.) The compiler chooses the most appropriate proc for the ``toString`` +Nim.) The compiler chooses the most appropriate proc for the ``toString`` calls. How this overloading resolution algorithm works exactly is not discussed here (it will be specified in the manual soon). However, it does not lead to nasty surprises and is based on a quite simple unification @@ -744,13 +713,13 @@ algorithm. Ambiguous calls are reported as errors. Operators --------- -The Nimrod library makes heavy use of overloading - one reason for this is that +The Nim library makes heavy use of overloading - one reason for this is that each operator like ``+`` is a just an overloaded proc. The parser lets you use operators in `infix notation` (``a + b``) or `prefix notation` (``+ a``). An infix operator always receives two arguments, a prefix operator always one. Postfix operators are not possible, because this would be ambiguous: does ``a @ @ b`` mean ``(a) @ (@b)`` or ``(a@) @ (b)``? It always means -``(a) @ (@b)``, because there are no postfix operators in Nimrod. +``(a) @ (@b)``, because there are no postfix operators in Nim. Apart from a few built-in keyword operators such as ``and``, ``or``, ``not``, operators always consist of these characters: @@ -764,7 +733,7 @@ can be found in the manual. To define a new operator enclose the operator in backticks "``": -.. code-block:: nimrod +.. code-block:: nim proc `$` (x: myDataType): string = ... # now the $ operator also works with myDataType, overloading resolution # ensures that $ works for built-in types just like before @@ -772,7 +741,7 @@ To define a new operator enclose the operator in backticks "``": The "``" notation can also be used to call an operator just like any other procedure: -.. code-block:: nimrod +.. code-block:: nim if `==`( `+`(3, 4), 7): echo("True") @@ -783,7 +752,7 @@ Every variable, procedure, etc. needs to be declared before it can be used. (The reason for this is compilation efficiency.) However, this cannot be done for mutually recursive procedures: -.. code-block:: nimrod +.. code-block:: nim # forward declaration: proc even(n: int): bool @@ -810,7 +779,7 @@ Iterators Let's return to the boring counting example: -.. code-block:: nimrod +.. code-block:: nim echo("Counting to ten: ") for i in countup(1, 10): echo($i) @@ -818,7 +787,7 @@ Let's return to the boring counting example: Can a `countup <system.html#countup>`_ proc be written that supports this loop? Lets try: -.. code-block:: nimrod +.. code-block:: nim proc countup(a, b: int): int = var res = a while res <= b: @@ -831,7 +800,7 @@ finished. This *return and continue* is called a `yield` statement. Now the only thing left to do is to replace the ``proc`` keyword by ``iterator`` and there it is - our first iterator: -.. code-block:: nimrod +.. code-block:: nim iterator countup(a, b: int): int = var res = a while res <= b: @@ -868,7 +837,7 @@ that are available for them in detail. Booleans -------- -The boolean type is named ``bool`` in Nimrod and consists of the two +The boolean type is named ``bool`` in Nim and consists of the two pre-defined values ``true`` and ``false``. Conditions in while, if, elif, when statements need to be of type bool. @@ -876,7 +845,7 @@ The operators ``not, and, or, xor, <, <=, >, >=, !=, ==`` are defined for the bool type. The ``and`` and ``or`` operators perform short-cut evaluation. Example: -.. code-block:: nimrod +.. code-block:: nim while p != nil and p.name != "xyz": # p.name is not evaluated if p == nil @@ -885,7 +854,7 @@ evaluation. Example: Characters ---------- -The `character type` is named ``char`` in Nimrod. Its size is one byte. +The `character type` is named ``char`` in Nim. Its size is one byte. Thus it cannot represent an UTF-8 character, but a part of it. The reason for this is efficiency: for the overwhelming majority of use-cases, the resulting programs will still handle UTF-8 properly as UTF-8 was specially @@ -900,13 +869,13 @@ Converting from an integer to a ``char`` is done with the ``chr`` proc. Strings ------- -String variables in Nimrod are **mutable**, so appending to a string -is quite efficient. Strings in Nimrod are both zero-terminated and have a +String variables in Nim are **mutable**, so appending to a string +is quite efficient. Strings in Nim are both zero-terminated and have a length field. One can retrieve a string's length with the builtin ``len`` procedure; the length never counts the terminating zero. Accessing the terminating zero is no error and often leads to simpler code: -.. code-block:: nimrod +.. code-block:: nim if s[i] == 'a' and s[i+1] == 'b': # no need to check whether ``i < len(s)``! ... @@ -929,14 +898,14 @@ object on the heap, so there is a trade-off to be made here. Integers -------- -Nimrod has these integer types built-in: +Nim has these integer types built-in: ``int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64``. The default integer type is ``int``. Integer literals can have a *type suffix* to mark them to be of another integer type: -.. code-block:: nimrod +.. code-block:: nim let x = 0 # x is of type ``int`` y = 0'i8 # y is of type ``int8`` @@ -964,7 +933,7 @@ cannot be detected at compile time). Floats ------ -Nimrod has these floating point types built-in: ``float float32 float64``. +Nim has these floating point types built-in: ``float float32 float64``. The default float type is ``float``. In the current implementation, ``float`` is always 64 bit wide. @@ -972,7 +941,7 @@ The default float type is ``float``. In the current implementation, Float literals can have a *type suffix* to mark them to be of another float type: -.. code-block:: nimrod +.. code-block:: nim var x = 0.0 # x is of type ``float`` y = 0.0'f32 # y is of type ``float32`` @@ -1001,11 +970,11 @@ having to write its ``$`` operator. You can use then the `repr graphs with cycles. The following example shows that even for basic types there is a difference between the ``$`` and ``repr`` outputs: -.. code-block:: nimrod +.. code-block:: nim var myBool = true myCharacter = 'n' - myString = "nimrod" + myString = "nim" myInteger = 42 myFloat = 3.14 echo($myBool, ":", repr(myBool)) @@ -1013,7 +982,7 @@ there is a difference between the ``$`` and ``repr`` outputs: echo($myCharacter, ":", repr(myCharacter)) # --> n:'n' echo($myString, ":", repr(myString)) - # --> nimrod:0x10fa8c050"nimrod" + # --> nim:0x10fa8c050"nim" echo($myInteger, ":", repr(myInteger)) # --> 42:42 echo($myFloat, ":", repr(myFloat)) @@ -1023,9 +992,9 @@ there is a difference between the ``$`` and ``repr`` outputs: Advanced types ============== -In Nimrod new types can be defined within a ``type`` statement: +In Nim new types can be defined within a ``type`` statement: -.. code-block:: nimrod +.. code-block:: nim type biggestInt = int64 # biggest integer type that is available biggestFloat = float64 # biggest float type that is available @@ -1041,7 +1010,7 @@ limited set. This set consists of ordered symbols. Each symbol is mapped to an integer value internally. The first symbol is represented at runtime by 0, the second by 1 and so on. Example: -.. code-block:: nimrod +.. code-block:: nim type TDirection = enum @@ -1050,7 +1019,7 @@ at runtime by 0, the second by 1 and so on. Example: var x = south # `x` is of type `TDirection`; its value is `south` echo($x) # writes "south" to `stdout` -(To prefix a new type with the letter ``T`` is a convention in Nimrod.) +(To prefix a new type with the letter ``T`` is a convention in Nim.) All comparison operators can be used with enumeration types. An enumeration's symbol can be qualified to avoid ambiguities: @@ -1066,7 +1035,7 @@ explicitly given is assigned the value of the previous symbol + 1. An explicit ordered enum can have *holes*: -.. code-block:: nimrod +.. code-block:: nim type TMyEnum = enum a = 2, b = 4, c = 89 @@ -1104,7 +1073,7 @@ Subranges A subrange type is a range of values from an integer or enumeration type (the base type). Example: -.. code-block:: nimrod +.. code-block:: nim type TSubrange = range[0..5] @@ -1119,7 +1088,7 @@ type as ``range[0..high(int)]`` (`high <system.html#high>`_ returns the maximal value). Other programming languages mandate the usage of unsigned integers for natural numbers. This is often **wrong**: you don't want unsigned arithmetic (which wraps around) just because the numbers cannot be negative. -Nimrod's ``Natural`` type helps to avoid this common programming error. +Nim's ``Natural`` type helps to avoid this common programming error. Sets @@ -1134,7 +1103,7 @@ the array has the same type. The array's index type can be any ordinal type. Arrays can be constructed via ``[]``: -.. code-block:: nimrod +.. code-block:: nim type TIntArray = array[0..5, int] # an array that is indexed with 0..5 @@ -1149,14 +1118,14 @@ Array access is always bounds checked (at compile-time or at runtime). These checks can be disabled via pragmas or invoking the compiler with the ``--bound_checks:off`` command line switch. -Arrays are value types, like any other Nimrod type. The assignment operator +Arrays are value types, like any other Nim type. The assignment operator copies the whole array contents. The built-in `len <system.html#len,TOpenArray>`_ proc returns the array's length. `low(a) <system.html#low>`_ returns the lowest valid index for the array `a` and `high(a) <system.html#high>`_ the highest valid index. -.. code-block:: nimrod +.. code-block:: nim type TDirection = enum north, east, south, west @@ -1175,13 +1144,13 @@ array `a` and `high(a) <system.html#high>`_ the highest valid index. The syntax for nested arrays (multidimensional) in other languages is a matter of appending more brackets because usually each dimension is restricted to the -same index type as the others. In nimrod you can have different dimensions with +same index type as the others. In Nim you can have different dimensions with different index types, so the nesting syntax is slightly different. Building on the previous example where a level is defined as an array of enums indexed by yet another enum, we can add the following lines to add a light tower type subdivided in height levels accessed through their integer index: -.. code-block:: nimrod +.. code-block:: nim type TLightTower = array[1..10, TLevelSetting] var @@ -1200,14 +1169,14 @@ length. Another way of defining the ``TLightTower`` to show better its nested nature would be to omit the previous definition of the ``TLevelSetting`` type and instead write it embedded directly as the type of the first dimension: -.. code-block:: nimrod +.. code-block:: nim type TLightTower = array[1..10, array[north..west, TBlinkLights]] It is quite frequent to have arrays start at zero, so there's a shortcut syntax to specify a range from zero to the specified index minus one: -.. code-block:: nimrod +.. code-block:: nim type TIntArray = array[0..5, int] # an array that is indexed with 0..5 TQuickArray = array[6, int] # an array that is indexed with 0..5 @@ -1239,7 +1208,7 @@ A sequence may be passed to an openarray parameter. Example: -.. code-block:: nimrod +.. code-block:: nim var x: seq[int] # a sequence of integers @@ -1261,7 +1230,7 @@ value. Here the ``for`` statement is looping over the results from the `pairs() <system.html#pairs.i,seq[T]>`_ iterator from the `system <system.html>`_ module. Examples: -.. code-block:: nimrod +.. code-block:: nim for i in @[3, 4, 5]: echo($i) # --> 3 @@ -1299,8 +1268,8 @@ also a means to implement passing a variable number of arguments to a procedure. The compiler converts the list of arguments to an array automatically: -.. code-block:: nimrod - proc myWriteln(f: TFile, a: varargs[string]) = +.. code-block:: nim + proc myWriteln(f: File, a: varargs[string]) = for s in items(a): write(f, s) write(f, "\n") @@ -1313,8 +1282,8 @@ This transformation is only done if the varargs parameter is the last parameter in the procedure header. It is also possible to perform type conversions in this context: -.. code-block:: nimrod - proc myWriteln(f: TFile, a: varargs[string, `$`]) = +.. code-block:: nim + proc myWriteln(f: File, a: varargs[string, `$`]) = for s in items(a): write(f, s) write(f, "\n") @@ -1336,10 +1305,10 @@ context. A slice is just an object of type TSlice which contains two bounds, `a` and `b`. By itself a slice is not very useful, but other collection types define operators which accept TSlice objects to define ranges. -.. code-block:: nimrod +.. code-block:: nim var - a = "Nimrod is a progamming language" + a = "Nim is a progamming language" b = "Slices are useless." echo a[10..15] # --> 'a prog' @@ -1366,7 +1335,7 @@ The assignment operator for tuples copies each component. The notation ``t[i]`` to access the ``i``'th field. Here ``i`` needs to be a constant integer. -.. code-block:: nimrod +.. code-block:: nim type TPerson = tuple[name: string, age: int] # type representing a person: @@ -1411,19 +1380,19 @@ use parenthesis around the values you want to assign the unpacking to, otherwise you will be assigning the same value to all the individual variables! Example: -.. code-block:: nimrod +.. code-block:: nim import os let - path = "usr/local/nimrodc.html" + path = "usr/local/nimc.html" (dir, name, ext) = splitFile(path) baddir, badname, badext = splitFile(path) echo dir # outputs `usr/local` - echo name # outputs `nimrodc` + echo name # outputs `nimc` echo ext # outputs `.html` # All the following output the same line: - # `(dir: usr/local, name: nimrodc, ext: .html)` + # `(dir: usr/local, name: nimc, ext: .html)` echo baddir echo badname echo badext @@ -1431,12 +1400,12 @@ variables! Example: Tuple unpacking **only** works in ``var`` or ``let`` blocks. The following code won't compile: -.. code-block:: nimrod +.. code-block:: nim import os var - path = "usr/local/nimrodc.html" + path = "usr/local/nimc.html" dir, name, ext = "" (dir, name, ext) = splitFile(path) @@ -1449,7 +1418,7 @@ References (similar to pointers in other programming languages) are a way to introduce many-to-one relationships. This means different references can point to and modify the same location in memory. -Nimrod distinguishes between `traced`:idx: and `untraced`:idx: references. +Nim distinguishes between `traced`:idx: and `untraced`:idx: references. Untraced references are also called *pointers*. Traced references point to objects of a garbage collected heap, untraced references point to manually allocated objects or to objects somewhere else in memory. Thus @@ -1464,7 +1433,7 @@ meaning to retrieve the item the reference points to. The ``.`` (access a tuple/object field operator) and ``[]`` (array/string/sequence index operator) operators perform implicit dereferencing operations for reference types: -.. code-block:: nimrod +.. code-block:: nim type PNode = ref TNode @@ -1489,12 +1458,12 @@ Procedural type --------------- A procedural type is a (somewhat abstract) pointer to a procedure. ``nil`` is an allowed value for a variable of a procedural type. -Nimrod uses procedural types to achieve `functional`:idx: programming +Nim uses procedural types to achieve `functional`:idx: programming techniques. Example: -.. code-block:: nimrod +.. code-block:: nim proc echoItem(x: int) = echo(x) proc forEach(action: proc (x: int)) = @@ -1513,13 +1482,13 @@ listed in the `manual <manual.html>`_. Modules ======= -Nimrod supports splitting a program into pieces with a module concept. +Nim supports splitting a program into pieces with a module concept. Each module is in its own file. Modules enable `information hiding`:idx: and `separate compilation`:idx:. A module may gain access to symbols of another module by the `import`:idx: statement. Only top-level symbols that are marked with an asterisk (``*``) are exported: -.. code-block:: nimrod +.. code-block:: nim # Module A var x*, y: int @@ -1554,7 +1523,7 @@ The algorithm for compiling modules is: This is best illustrated by an example: -.. code-block:: nimrod +.. code-block:: nim # Module A type T1* = int # Module A exports the type ``T1`` @@ -1565,7 +1534,7 @@ This is best illustrated by an example: main() -.. code-block:: nimrod +.. code-block:: nim # Module B import A # A is not parsed here! Only the already known symbols # of A are imported. @@ -1581,15 +1550,15 @@ the symbol is ambiguous, it even *has* to be qualified. A symbol is ambiguous if it is defined in two (or more) different modules and both modules are imported by a third one: -.. code-block:: nimrod +.. code-block:: nim # Module A var x*: string -.. code-block:: nimrod +.. code-block:: nim # Module B var x*: int -.. code-block:: nimrod +.. code-block:: nim # Module C import A, B write(stdout, x) # error: x is ambiguous @@ -1602,15 +1571,15 @@ imported by a third one: But this rule does not apply to procedures or iterators. Here the overloading rules apply: -.. code-block:: nimrod +.. code-block:: nim # Module A proc x*(a: int): string = result = $a -.. code-block:: nimrod +.. code-block:: nim # Module B proc x*(a: string): string = result = $a -.. code-block:: nimrod +.. code-block:: nim # Module C import A, B write(stdout, x(3)) # no error: A.x is called @@ -1627,7 +1596,7 @@ The normal ``import`` statement will bring in all exported symbols. These can be limited by naming symbols which should be excluded with the ``except`` qualifier. -.. code-block:: nimrod +.. code-block:: nim import mymodule except y @@ -1638,19 +1607,19 @@ We have already seen the simple ``import`` statement that just imports all exported symbols. An alternative that only imports listed symbols is the ``from import`` statement: -.. code-block:: nimrod +.. code-block:: nim from mymodule import x, y, z The ``from`` statement can also force namespace qualification on symbols, thereby making symbols available, but needing to be qualified to be used. -.. code-block:: nimrod +.. code-block:: nim from mymodule import x, y, z x() # use x without any qualification -.. code-block:: nimrod +.. code-block:: nim from mymodule import nil mymodule.x() # must qualify x with the module name as prefix @@ -1660,7 +1629,7 @@ to be used. Since module names are generally long to be descriptive, you can also define a shorter alias to use when qualifying symbols. -.. code-block:: nimrod +.. code-block:: nim from mymodule as m import nil m.x() # m is aliasing mymodule @@ -1672,7 +1641,7 @@ The ``include`` statement does something fundamentally different than importing a module: it merely includes the contents of a file. The ``include`` statement is useful to split up a large module into several files: -.. code-block:: nimrod +.. code-block:: nim include fileA, fileB, fileC **Note**: The documentation generator currently does not follow ``include`` @@ -1683,7 +1652,7 @@ generated documentation. Part 2 ====== -So, now that we are done with the basics, let's see what Nimrod offers apart +So, now that we are done with the basics, let's see what Nim offers apart from a nice syntax for procedural programming: `Part II <tut2.html>`_ diff --git a/doc/tut2.txt b/doc/tut2.txt index 2f42bcefc..651c38838 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -1,9 +1,9 @@ -========================= -Nimrod Tutorial (Part II) -========================= +====================== +Nim Tutorial (Part II) +====================== :Author: Andreas Rumpf -:Version: |nimrodversion| +:Version: |nimversion| .. contents:: @@ -15,7 +15,7 @@ Introduction only have originated in California." --Edsger Dijkstra -This document is a tutorial for the advanced constructs of the *Nimrod* +This document is a tutorial for the advanced constructs of the *Nim* programming language. **Note that this document is somewhat obsolete as the** `manual <manual.html>`_ **contains many more examples of the advanced language features.** @@ -24,18 +24,18 @@ features.** Pragmas ======= -Pragmas are Nimrod's method to give the compiler additional information/ +Pragmas are Nim's method to give the compiler additional information/ commands without introducing a massive number of new keywords. Pragmas are enclosed in the special ``{.`` and ``.}`` curly dot brackets. This tutorial does not cover pragmas. See the `manual <manual.html#pragmas>`_ or `user guide -<nimrodc.html#additional-features>`_ for a description of the available +<nimc.html#additional-features>`_ for a description of the available pragmas. Object Oriented Programming =========================== -While Nimrod's support for object oriented programming (OOP) is minimalistic, +While Nim's support for object oriented programming (OOP) is minimalistic, powerful OOP technics 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 @@ -55,7 +55,7 @@ a *constructor*). Objects have access to their type at runtime. There is an ``of`` operator that can be used to check the object's type: -.. code-block:: nimrod +.. code-block:: nim type TPerson = object of TObject name*: string # the * means that `name` is accessible from other modules @@ -86,20 +86,20 @@ in the GTK wrapper for instance.) **Note**: Composition (*has-a* relation) is often preferable to inheritance (*is-a* relation) for simple code reuse. Since objects are value types in -Nimrod, composition is as efficient as inheritance. +Nim, composition is as efficient as inheritance. Mutually recursive types ------------------------ Objects, tuples and references can model quite complex data structures which -depend on each other; they are *mutually recursive*. In Nimrod +depend on each other; they are *mutually recursive*. In Nim these types can only be declared within a single type section. (Anything else would require arbitrary symbol lookahead which slows down compilation.) Example: -.. code-block:: nimrod +.. code-block:: nim type PNode = ref TNode # a traced reference to a TNode TNode = object @@ -114,7 +114,7 @@ Example: Type conversions ---------------- -Nimrod distinguishes between `type casts`:idx: and `type conversions`:idx:. +Nim distinguishes between `type casts`:idx: and `type conversions`:idx:. Casts are done with the ``cast`` operator and force the compiler to interpret a bit pattern to be of another type. @@ -126,11 +126,11 @@ raised. The syntax for type conversions is ``destination_type(expression_to_convert)`` (like an ordinary call): -.. code-block:: nimrod +.. code-block:: nim proc getID(x: TPerson): int = TStudent(x).id -The ``EInvalidObjectConversion`` exception is raised if ``x`` is not a +The ``InvalidObjectConversionError`` exception is raised if ``x`` is not a ``TStudent``. @@ -141,9 +141,9 @@ variant types are needed. An example: -.. code-block:: nimrod +.. code-block:: nim - # This is an example how an abstract syntax tree could be modeled in Nimrod + # This is an example how an abstract syntax tree could be modeled in Nim type TNodeKind = enum # the different node types nkInt, # a leaf with an integer value @@ -164,7 +164,7 @@ An example: condition, thenPart, elsePart: PNode var n = PNode(kind: nkFloat, floatVal: 1.0) - # the following statement raises an `EInvalidField` exception, because + # the following statement raises an `FieldError` exception, because # n.kind's value does not fit: n.strVal = "" @@ -183,8 +183,8 @@ bound to a class. This has disadvantages: * Often it is unclear where the method should belong to: is ``join`` a string method or an array method? -Nimrod avoids these problems by not assigning methods to a class. All methods -in Nimrod are multi-methods. As we will see later, multi-methods are +Nim avoids these problems by not assigning methods to a class. All methods +in Nim are multi-methods. As we will see later, multi-methods are distinguished from procs only for dynamic binding purposes. @@ -199,7 +199,7 @@ If there are no remaining arguments, the parentheses can be omitted: This method call syntax is not restricted to objects, it can be used for any type: -.. code-block:: nimrod +.. code-block:: nim echo("abc".len) # is the same as echo(len("abc")) echo("abc".toUpper()) @@ -211,7 +211,7 @@ postfix notation.) So "pure object oriented" code is easy to write: -.. code-block:: nimrod +.. code-block:: nim import strutils stdout.writeln("Give a list of numbers (separated by spaces): ") @@ -221,12 +221,12 @@ So "pure object oriented" code is easy to write: Properties ---------- -As the above example shows, Nimrod has no need for *get-properties*: +As the above example shows, Nim has no need for *get-properties*: Ordinary get-procedures that are called with the *method call syntax* achieve the same. But setting a value is different; for this a special setter syntax is needed: -.. code-block:: nimrod +.. code-block:: nim type TSocket* = object of TObject @@ -252,7 +252,7 @@ is needed: The ``[]`` array access operator can be overloaded to provide `array properties`:idx:\ : -.. code-block:: nimrod +.. code-block:: nim type TVector* = object x, y, z: float @@ -283,7 +283,7 @@ Dynamic dispatch Procedures always use static dispatch. For dynamic dispatch replace the ``proc`` keyword by ``method``: -.. code-block:: nimrod +.. code-block:: nim type PExpr = ref object of TObject ## abstract base class for an expression PLiteral = ref object of PExpr @@ -311,7 +311,7 @@ requires dynamic binding. In a multi-method all parameters that have an object type are used for the dispatching: -.. code-block:: nimrod +.. code-block:: nim type TThing = object of TObject @@ -336,7 +336,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 ``TUnit, TThing`` is preferred over ``TThing, TUnit``. -**Perfomance note**: Nimrod does not produce a virtual method table, but +**Perfomance 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. @@ -345,10 +345,10 @@ evaluation or dead code elimination do not work with methods. Exceptions ========== -In Nimrod exceptions are objects. By convention, exception types are -prefixed with an 'E', not 'T'. The `system <system.html>`_ module defines an +In Nim exceptions are objects. By convention, exception types are +suffixed with 'Error'. The `system <system.html>`_ module defines an exception hierarchy that you might want to stick to. Exceptions derive from -E_Base, which provides the common interface. +``system.Exception``, which provides the common interface. Exceptions have to be allocated on the heap because their lifetime is unknown. The compiler will prevent you from raising an exception created on the stack. @@ -364,9 +364,9 @@ Raise statement --------------- Raising an exception is done with the ``raise`` statement: -.. code-block:: nimrod +.. code-block:: nim var - e: ref EOS + e: ref OSError new(e) e.msg = "the request to the OS failed" raise e @@ -375,8 +375,8 @@ If the ``raise`` keyword is not followed by an expression, the last exception is *re-raised*. For the purpose of avoiding repeating this common code pattern, the template ``newException`` in the ``system`` module can be used: -.. code-block:: nimrod - raise newException(EOS, "the request to the OS failed") +.. code-block:: nim + raise newException(OSError, "the request to the OS failed") Try statement @@ -384,21 +384,21 @@ Try statement The ``try`` statement handles exceptions: -.. code-block:: nimrod +.. code-block:: nim # read the first two lines of a text file that should contain numbers # and tries to add them var - f: TFile + f: File if open(f, "numbers.txt"): try: let a = readLine(f) let b = readLine(f) echo "sum: ", parseInt(a) + parseInt(b) - except EOverflow: + except OverflowError: echo "overflow!" - except EInvalidValue: + except ValueError: echo "could not convert string to integer" - except EIO: + except IOError: echo "IO error!" except: echo "Unknown exception!" @@ -426,9 +426,9 @@ If you need to *access* the actual exception object or message inside an ``except`` branch you can use the `getCurrentException() <system.html#getCurrentException>`_ and `getCurrentExceptionMsg() <system.html#getCurrentExceptionMsg>`_ procs from the `system <system.html>`_ -module. Example: +module. Example: -.. code-block:: nimrod +.. code-block:: nim try: doSomethingHere() except: @@ -441,9 +441,9 @@ module. Example: Exception hierarchy ------------------- -If you want to create your own exceptions you can inherit from E_Base, but you -can also inherit from one of the existing exceptions if they fit your purpose. -The exception tree is: +If you want to create your own exceptions you can inherit from ``system.Exception``, +but you can also inherit from one of the existing exceptions if they fit your +purpose. The exception tree is: .. include:: exception_hierarchy_fragment.txt @@ -456,12 +456,12 @@ Annotating procs with raised exceptions Through the use of the optional ``{.raises.}`` pragma you can specify that a proc is meant to raise a specific set of exceptions, or none at all. If the ``{.raises.}`` pragma is used, the compiler will verify that this is true. For -instance, if you specify that a proc raises ``EIO``, and at some point it (or -one of the procs it calls) starts raising a new exception the compiler will +instance, if you specify that a proc raises ``IOError``, and at some point it +(or one of the procs it calls) starts raising a new exception the compiler will prevent that proc from compiling. Usage example: -.. code-block:: nimrod - proc complexProc() {.raises: [EIO, EArithmetic].} = +.. code-block:: nim + proc complexProc() {.raises: [IOError, ArithmeticError].} = ... proc simpleProc() {.raises: [].} = @@ -476,21 +476,21 @@ help you locate the offending code which has changed. If you want to add the ``{.raises.}`` pragma to existing code, the compiler can also help you. You can add the ``{.effects.}`` pragma statement to your proc and the compiler will output all inferred effects up to that point (exception -tracking is part of Nimrod's effect system). Another more roundabout way to -find out the list of exceptions raised by a proc is to use the Nimrod ``doc2`` +tracking is part of Nim's effect system). Another more roundabout way to +find out the list of exceptions raised by a proc is to use the Nim ``doc2`` command which generates documentation for a whole module and decorates all -procs with the list of raised exceptions. You can read more about Nimrod's +procs with the list of raised exceptions. You can read more about Nim's `effect system and related pragmas in the manual <manual.html#effect-system>`_. Generics ======== -Generics are Nimrod's means to parametrize procs, iterators or types +Generics are Nim's means to parametrize procs, iterators or types with `type parameters`:idx:. They are most useful for efficient type safe containers: -.. code-block:: nimrod +.. code-block:: nim type TBinaryTree[T] = object # TBinaryTree is a generic type with # with generic param ``T`` @@ -557,7 +557,7 @@ is not hidden and is used in the ``preorder`` iterator. Templates ========= -Templates are a simple substitution mechanism that operates on Nimrod's +Templates are a simple substitution mechanism that operates on Nim's abstract syntax trees. Templates are processed in the semantic pass of the compiler. They integrate well with the rest of the language and share none of C's preprocessor macros flaws. @@ -566,7 +566,7 @@ To *invoke* a template, call it like a procedure. Example: -.. code-block:: nimrod +.. code-block:: nim template `!=` (a, b: expr): expr = # this definition exists in the System module not (a == b) @@ -585,7 +585,7 @@ for IEEE floating point numbers - NaN breaks basic boolean logic.) Templates are especially useful for lazy evaluation purposes. Consider a simple proc for logging: -.. code-block:: nimrod +.. code-block:: nim const debug = true @@ -602,7 +602,7 @@ evaluation for procedures is *eager*). Turning the ``log`` proc into a template solves this problem: -.. code-block:: nimrod +.. code-block:: nim const debug = true @@ -618,37 +618,16 @@ The parameters' types can be ordinary types or the meta types ``expr`` (stands for *type description*). If the template has no explicit return type, ``stmt`` is used for consistency with procs and methods. -The template body does not open a new scope. To open a new scope use a ``block`` -statement: - -.. code-block:: nimrod - template declareInScope(x: expr, t: typeDesc): stmt {.immediate.} = - var x: t - - template declareInNewScope(x: expr, t: typeDesc): stmt {.immediate.} = - # open a new scope: - block: - var x: t - - declareInScope(a, int) - a = 42 # works, `a` is known here - - declareInNewScope(b, int) - b = 42 # does not work, `b` is unknown - -(The `manual explains <manual.html#ordinary-vs-immediate-templates>`_ why the -``immediate`` pragma is needed for these templates.) - If there is a ``stmt`` parameter it should be the last in the template declaration. The reason is that statements can be passed to a template via a special ``:`` syntax: -.. code-block:: nimrod +.. code-block:: nim - template withFile(f: expr, filename: string, mode: TFileMode, + template withFile(f: expr, filename: string, mode: FileMode, body: stmt): stmt {.immediate.} = let fn = filename - var f: TFile + var f: File if open(f, fn, mode): try: body @@ -672,18 +651,18 @@ Macros ====== Macros enable advanced compile-time code transformations, but they cannot -change Nimrod's syntax. However, this is no real restriction because Nimrod's -syntax is flexible enough anyway. Macros have to be implemented in pure Nimrod +change Nim's syntax. However, this is no real restriction because Nim's +syntax is flexible enough anyway. Macros have to be implemented in pure Nim code if `foreign function interface (FFI) <manual.html#foreign-function-interface>`_ is not enabled in the compiler, but other than that restriction (which at some point in the future will go away) -you can write any kind of Nimrod code and the compiler will run it at compile +you can write any kind of Nim code and the compiler will run it at compile time. -There are two ways to write a macro, either *generating* Nimrod source code and +There are two ways to write a macro, either *generating* Nim source code and letting the compiler parse it, or creating manually an abstract syntax tree (AST) which you feed to the compiler. In order to build the AST one needs to -know how the Nimrod concrete syntax is converted to an abstract syntax tree +know how the Nim concrete syntax is converted to an abstract syntax tree (AST). The AST is documented in the `macros <macros.html>`_ module. Once your macro is finished, there are two ways to invoke it: @@ -698,13 +677,13 @@ Expression Macros The following example implements a powerful ``debug`` command that accepts a variable number of arguments: -.. code-block:: nimrod - # to work with Nimrod syntax trees, we need an API that is defined in the +.. code-block:: nim + # to work with Nim syntax trees, we need an API that is defined in the # ``macros`` module: import macros macro debug(n: varargs[expr]): stmt = - # `n` is a Nimrod AST that contains a list of expressions; + # `n` is a Nim AST that contains a list of expressions; # this macro returns a list of statements: result = newNimNode(nnkStmtList, n) # iterate over any argument that is passed to this macro: @@ -727,7 +706,7 @@ variable number of arguments: The macro call expands to: -.. code-block:: nimrod +.. code-block:: nim write(stdout, "a[0]") write(stdout, ": ") writeln(stdout, a[0]) @@ -751,7 +730,7 @@ invoked by an expression following a colon. The following example outlines a macro that generates a lexical analyzer from regular expressions: -.. code-block:: nimrod +.. code-block:: nim macro case_token(n: stmt): stmt = # creates a lexical analyzer from regular expressions @@ -784,11 +763,11 @@ To give a footstart to writing macros we will show now how to turn your typical dynamic code into something that compiles statically. For the exercise we will use the following snippet of code as the starting point: -.. code-block:: nimrod +.. code-block:: nim import strutils, tables - proc readCfgAtRuntime(cfgFilename: string): TTable[string, string] = + proc readCfgAtRuntime(cfgFilename: string): Table[string, string] = let inputString = readFile(cfgFilename) var @@ -822,7 +801,7 @@ to be included along the program containing the license information:: licenseKey,M1Tl3PjBWO2CC48m The ``readCfgAtRuntime`` proc will open the given filename and return a -``TTable`` from the `tables module <tables.html>`_. The parsing of the file is +``Table`` from the `tables module <tables.html>`_. The parsing of the file is done (without much care for handling invalid data or corner cases) using the ``splitLines`` proc from the `strutils module <strutils.html>`_. There are many things which can fail; mind the purpose is explaining how to make this run at @@ -848,7 +827,7 @@ time string with the *generated source code*, which we then pass to the ``parseStmt`` proc from the `macros module <macros.html>`_. Here is the modified source code implementing the macro: -.. code-block:: nimrod +.. code-block:: nim import macros, strutils macro readCfgAndBuildSource(cfgFilename: string): stmt = @@ -879,7 +858,7 @@ The good news is not much has changed! First, we need to change the handling of the input parameter. In the dynamic version the ``readCfgAtRuntime`` proc receives a string parameter. However, in the macro version it is also declared as string, but this is the *outside* interface of the macro. When the macro is -run, it actually gets a ``PNimrodNode`` object instead of a string, and we have +run, it actually gets a ``PNimNode`` object instead of a string, and we have to call the ``strVal`` proc from the `macros module <macros.html>`_ to obtain the string being passed in to the macro. @@ -892,14 +871,14 @@ this limitation by using the ``slurp`` proc from the `system module <system.html>`_, which was precisely made for compilation time (just like ``gorge`` which executes an external program and captures its output). -The interesting thing is that our macro does not return a runtime ``TTable`` -object. Instead, it builds up Nimrod source code into the ``source`` variable. +The interesting thing is that our macro does not return a runtime ``Table`` +object. Instead, it builds up Nim source code into the ``source`` variable. For each line of the configuration file a ``const`` variable will be generated. To avoid conflicts we prefix these variables with ``cfg``. In essence, what the compiler is doing is replacing the line calling the macro with the following snippet of code: -.. code-block:: nimrod +.. code-block:: nim const cfgversion= "1.1" const cfglicenseOwner= "Hyori Lee" const cfglicenseKey= "M1Tl3PjBWO2CC48m" @@ -919,14 +898,14 @@ Generating AST by hand ++++++++++++++++++++++ To generate an AST we would need to intimately know the structures used by the -Nimrod compiler exposed in the `macros module <macros.html>`_, which at first +Nim compiler exposed in the `macros module <macros.html>`_, which at first look seems a daunting task. But we can use as helper shortcut the ``dumpTree`` macro, which is used as a statement macro instead of an expression macro. Since we know that we want to generate a bunch of ``const`` symbols we can create the following source file and compile it to see what the compiler *expects* from us: -.. code-block:: nimrod +.. code-block:: nim import macros dumpTree: @@ -969,7 +948,7 @@ identifier, optionally a type (can be an *empty* node) and the value. Armed with this knowledge, let's look at the finished version of the AST building macro: -.. code-block:: nimrod +.. code-block:: nim import macros, strutils macro readCfgAndBuildAST(cfgFilename: string): stmt = diff --git a/examples/curlex.nim b/examples/curlex.nim index 1d0f18ddd..9dadd9a90 100644 --- a/examples/curlex.nim +++ b/examples/curlex.nim @@ -3,7 +3,7 @@ import var hCurl = easy_init() if hCurl != nil: - discard easy_setopt(hCurl, OPT_VERBOSE, True) + discard easy_setopt(hCurl, OPT_VERBOSE, true) discard easy_setopt(hCurl, OPT_URL, "http://force7.de/nimrod") discard easy_perform(hCurl) easy_cleanup(hCurl) diff --git a/examples/htmlrefs.nim b/examples/htmlrefs.nim index 8b668325f..5364d61b6 100644 --- a/examples/htmlrefs.nim +++ b/examples/htmlrefs.nim @@ -12,10 +12,10 @@ if paramCount() < 1: quit("Usage: htmlrefs filename[.html]") var links = 0 # count the number of links -var filename = addFileExt(ParamStr(1), "html") +var filename = addFileExt(paramStr(1), "html") var s = newFileStream(filename, fmRead) if s == nil: quit("cannot open the file " & filename) -var x: TXmlParser +var x: XmlParser open(x, s, filename) next(x) # get first event block mainLoop: @@ -43,12 +43,12 @@ block mainLoop: while x.kind == xmlCharData: desc.add(x.charData) x.next() - Echo(desc & ": " & link) + echo(desc & ": " & link) else: x.next() of xmlEof: break # end of file reached of xmlError: - Echo(errorMsg(x)) + echo(errorMsg(x)) x.next() else: x.next() # skip other events diff --git a/examples/htmltitle.nim b/examples/htmltitle.nim index a3280bb13..7e66fabaa 100644 --- a/examples/htmltitle.nim +++ b/examples/htmltitle.nim @@ -10,7 +10,7 @@ if paramCount() < 1: var filename = addFileExt(paramStr(1), "html") var s = newFileStream(filename, fmRead) if s == nil: quit("cannot open the file " & filename) -var x: TXmlParser +var x: XmlParser open(x, s, filename) while true: x.next() diff --git a/examples/httpserver2.nim b/examples/httpserver2.nim index 45350ac89..13fea9e21 100644 --- a/examples/httpserver2.nim +++ b/examples/httpserver2.nim @@ -7,19 +7,19 @@ const type TRequestMethod = enum reqGet, reqPost TServer* = object ## contains the current server state - socket: TSocket + s: Socket job: seq[TJob] TJob* = object - client: TSocket - process: PProcess + client: Socket + process: Process # --------------- output messages -------------------------------------------- -proc sendTextContentType(client: TSocket) = +proc sendTextContentType(client: Socket) = send(client, "Content-type: text/html" & wwwNL) send(client, wwwNL) -proc badRequest(client: TSocket) = +proc badRequest(client: Socket) = # Inform the client that a request it has made has a problem. send(client, "HTTP/1.0 400 BAD REQUEST" & wwwNL) sendTextContentType(client) @@ -27,19 +27,19 @@ proc badRequest(client: TSocket) = "such as a POST without a Content-Length.</p>" & wwwNL) -proc cannotExec(client: TSocket) = +proc cannotExec(client: Socket) = send(client, "HTTP/1.0 500 Internal Server Error" & wwwNL) sendTextContentType(client) send(client, "<P>Error prohibited CGI execution.</p>" & wwwNL) -proc headers(client: TSocket, filename: string) = +proc headers(client: Socket, filename: string) = # XXX could use filename to determine file type send(client, "HTTP/1.0 200 OK" & wwwNL) send(client, ServerSig) sendTextContentType(client) -proc notFound(client: TSocket, path: string) = +proc notFound(client: Socket, path: string) = send(client, "HTTP/1.0 404 NOT FOUND" & wwwNL) send(client, ServerSig) sendTextContentType(client) @@ -50,7 +50,7 @@ proc notFound(client: TSocket, path: string) = send(client, "</body></html>" & wwwNL) -proc unimplemented(client: TSocket) = +proc unimplemented(client: Socket) = send(client, "HTTP/1.0 501 Method Not Implemented" & wwwNL) send(client, ServerSig) sendTextContentType(client) @@ -62,24 +62,25 @@ proc unimplemented(client: TSocket) = # ----------------- file serving --------------------------------------------- -proc discardHeaders(client: TSocket) = skip(client) +proc discardHeaders(client: Socket) = skip(client) -proc serveFile(client: TSocket, filename: string) = +proc serveFile(client: Socket, filename: string) = discardHeaders(client) - var f: TFile + var f: File if open(f, filename): headers(client, filename) const bufSize = 8000 # != 8K might be good for memory manager var buf = alloc(bufsize) - while True: + while true: var bytesread = readBuffer(f, buf, bufsize) if bytesread > 0: var byteswritten = send(client, buf, bytesread) if bytesread != bytesWritten: + let err = osLastError() dealloc(buf) close(f) - OSError() + raiseOSError(err) if bytesread != bufSize: break dealloc(buf) close(f) @@ -89,7 +90,7 @@ proc serveFile(client: TSocket, filename: string) = # ------------------ CGI execution ------------------------------------------- -proc executeCgi(server: var TServer, client: TSocket, path, query: string, +proc executeCgi(server: var TServer, client: Socket, path, query: string, meth: TRequestMethod) = var env = newStringTable(modeCaseInsensitive) var contentLength = -1 @@ -131,9 +132,10 @@ proc executeCgi(server: var TServer, client: TSocket, path, query: string, if meth == reqPost: # get from client and post to CGI program: var buf = alloc(contentLength) - if recv(client, buf, contentLength) != contentLength: + if recv(client, buf, contentLength) != contentLength: + let err = osLastError() dealloc(buf) - OSError() + raiseOSError(err) var inp = process.inputStream inp.writeData(buf, contentLength) dealloc(buf) @@ -163,7 +165,7 @@ proc animate(server: var TServer) = # --------------- Server Setup ----------------------------------------------- -proc acceptRequest(server: var TServer, client: TSocket) = +proc acceptRequest(server: var TServer, client: Socket) = var cgi = false var query = "" var buf = "" @@ -197,7 +199,7 @@ proc acceptRequest(server: var TServer, client: TSocket) = if path[path.len-1] == '/' or existsDir(path): path = path / "index.html" - if not ExistsFile(path): + if not existsFile(path): discardHeaders(client) notFound(client, path) client.close() @@ -215,26 +217,24 @@ proc acceptRequest(server: var TServer, client: TSocket) = else: executeCgi(server, client, path, query, meth) - - when isMainModule: var port = 80 var server: TServer server.job = @[] - server.socket = socket(AF_INET) - if server.socket == InvalidSocket: OSError() - server.socket.bindAddr(port=TPort(port)) - listen(server.socket) + server.s = socket(AF_INET) + if server.s == invalidSocket: raiseOSError(osLastError()) + server.s.bindAddr(port=Port(port)) + listen(server.s) echo("server up on port " & $port) while true: # check for new new connection & handle it - var list: seq[TSocket] = @[server.socket] + var list: seq[Socket] = @[server.s] if select(list, 10) > 0: - var client: TSocket + var client: Socket new(client) - accept(server.socket, client) + accept(server.s, client) try: acceptRequest(server, client) except: @@ -244,4 +244,4 @@ when isMainModule: animate(server) # some slack for CPU sleep(10) - server.socket.close() + server.s.close() diff --git a/examples/iupex1.nim b/examples/iupex1.nim index bf7ed2f1c..f768fb23f 100644 --- a/examples/iupex1.nim +++ b/examples/iupex1.nim @@ -1,37 +1,37 @@ # Example IUP program -# IupTabs: Creates a IupTabs control. +# iupTabs: Creates a iupTabs control. import iup -discard iup.Open(nil, nil) +discard iup.open(nil, nil) -var vbox1 = Iup.Vbox(Iup.Label("Inside Tab A"), Iup.Button("Button A", ""), nil) -var vbox2 = Iup.Vbox(Iup.Label("Inside Tab B"), Iup.Button("Button B", ""), nil) +var vbox1 = iup.vbox(iup.label("Inside Tab A"), iup.button("Button A", ""), nil) +var vbox2 = iup.vbox(iup.label("Inside Tab B"), iup.button("Button B", ""), nil) -Iup.SetAttribute(vbox1, "TABTITLE", "Tab A") -Iup.SetAttribute(vbox2, "TABTITLE", "Tab B") +iup.setAttribute(vbox1, "TABTITLE", "Tab A") +iup.setAttribute(vbox2, "TABTITLE", "Tab B") -var tabs1 = Iup.Tabs(vbox1, vbox2, nil) +var tabs1 = iup.tabs(vbox1, vbox2, nil) -vbox1 = Iup.Vbox(Iup.Label("Inside Tab C"), Iup.Button("Button C", ""), nil) -vbox2 = Iup.Vbox(Iup.Label("Inside Tab D"), Iup.Button("Button D", ""), nil) +vbox1 = iup.vbox(iup.label("Inside Tab C"), iup.button("Button C", ""), nil) +vbox2 = iup.vbox(iup.label("Inside Tab D"), iup.button("Button D", ""), nil) -Iup.SetAttribute(vbox1, "TABTITLE", "Tab C") -Iup.SetAttribute(vbox2, "TABTITLE", "Tab D") +iup.setAttribute(vbox1, "TABTITLE", "Tab C") +iup.setAttribute(vbox2, "TABTITLE", "Tab D") -var tabs2 = Iup.Tabs(vbox1, vbox2, nil) -Iup.SetAttribute(tabs2, "TABTYPE", "LEFT") +var tabs2 = iup.tabs(vbox1, vbox2, nil) +iup.setAttribute(tabs2, "TABTYPE", "LEFT") -var box = Iup.Hbox(tabs1, tabs2, nil) -Iup.SetAttribute(box, "MARGIN", "10x10") -Iup.SetAttribute(box, "GAP", "10") +var box = iup.hbox(tabs1, tabs2, nil) +iup.setAttribute(box, "MARGIN", "10x10") +iup.setAttribute(box, "GAP", "10") -var dlg = Iup.Dialog(box) -Iup.SetAttribute(dlg, "TITLE", "IupTabs") -Iup.SetAttribute(dlg, "SIZE", "200x100") +var dlg = iup.dialog(box) +iup.setAttribute(dlg, "TITLE", "iupTabs") +iup.setAttribute(dlg, "SIZE", "200x100") -discard ShowXY(dlg, IUP_CENTER, IUP_CENTER) -discard MainLoop() -Close() +discard showXY(dlg, IUP_CENTER, IUP_CENTER) +discard mainLoop() +close() diff --git a/examples/parsecfgex.nim b/examples/parsecfgex.nim index 618ecadd6..0f37a0378 100644 --- a/examples/parsecfgex.nim +++ b/examples/parsecfgex.nim @@ -4,7 +4,7 @@ import var f = newFileStream(paramStr(1), fmRead) if f != nil: - var p: TCfgParser + var p: CfgParser open(p, f, paramStr(1)) while true: var e = next(p) diff --git a/examples/sdlex.nim b/examples/sdlex.nim index 2c1a413e9..3dd474d8e 100644 --- a/examples/sdlex.nim +++ b/examples/sdlex.nim @@ -12,11 +12,11 @@ var if init(INIT_VIDEO) != 0: quit "SDL failed to initialize!" -screen = SetVideoMode(640, 480, 16, SWSURFACE or ANYFORMAT) +screen = setVideoMode(640, 480, 16, SWSURFACE or ANYFORMAT) if screen.isNil: quit($sdl.getError()) -greeting = IMG_load("tux.png") +greeting = imgLoad("tux.png") if greeting.isNil: echo "Failed to load tux.png" else: @@ -36,7 +36,7 @@ block game_loop: of QUITEV: break game_loop of KEYDOWN: - if EvKeyboard(addr event).keysym.sym == K_ESCAPE: + if evKeyboard(addr event).keysym.sym == K_ESCAPE: break game_loop else: discard @@ -47,6 +47,6 @@ block game_loop: greeting.freeSurface() screen.freeSurface() -sdl.Quit() +sdl.quit() ## fowl wuz here 10/2012 \ No newline at end of file diff --git a/examples/statcsv.nim b/examples/statcsv.nim index 48c4ea0cc..cd1de62af 100644 --- a/examples/statcsv.nim +++ b/examples/statcsv.nim @@ -8,14 +8,14 @@ import os, streams, parsecsv, strutils, math if paramCount() < 1: quit("Usage: statcsv filename[.csv]") -var filename = addFileExt(ParamStr(1), "csv") +var filename = addFileExt(paramStr(1), "csv") var s = newFileStream(filename, fmRead) if s == nil: quit("cannot open the file " & filename) var - x: TCsvParser + x: CsvParser header: seq[string] - res: seq[TRunningStat] + res: seq[RunningStat] open(x, s, filename, separator=';', skipInitialSpace = true) while readRow(x): if processedRows(x) == 1: diff --git a/koch.nim b/koch.nim index dff6ede98..a43701194 100644 --- a/koch.nim +++ b/koch.nim @@ -1,6 +1,6 @@ # # -# Maintenance program for Nimrod +# Maintenance program for Nim # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -26,7 +26,7 @@ when defined(haveZipLib): const HelpText = """ +-----------------------------------------------------------------+ -| Maintenance program for Nimrod | +| Maintenance program for Nim | | Version $1| | (c) 2014 Andreas Rumpf | +-----------------------------------------------------------------+ @@ -38,14 +38,14 @@ Options: --help, -h shows this help and quits Possible Commands: boot [options] bootstraps with given command line options - install [dir] installs to given directory + install [bindir] installs to given directory clean cleans Nimrod project; removes generated files - web generates the website + web [options] generates the website csource [options] builds the C sources for installation zip builds the installation ZIP package inno [options] builds the Inno Setup installer (for Windows) tests [options] run the testsuite - update updates nimrod to the latest version from github + update updates nim to the latest version from github (compile koch with -d:withUpdate to enable) temp options creates a temporary compiler for testing Boot options: @@ -61,13 +61,13 @@ Boot options: proc exe(f: string): string = return addFileExt(f, ExeExt) proc findNim(): string = - var nimrod = "nimrod".exe - result = "bin" / nimrod + var nim = "nim".exe + result = "bin" / nim if existsFile(result): return for dir in split(getEnv("PATH"), PathSep): - if existsFile(dir / nimrod): return dir / nimrod + if existsFile(dir / nim): return dir / nim # assume there is a symlink to the exe or something: - return nimrod + return nim proc exec(cmd: string) = echo(cmd) @@ -81,12 +81,12 @@ const compileNimInst = "-d:useLibzipSrc tools/niminst/niminst" proc csource(args: string) = - exec("$4 cc $1 -r $3 --var:version=$2 csource compiler/nimrod.ini $1" % - [args, NimrodVersion, compileNimInst, findNim()]) + exec("$4 cc $1 -r $3 --var:version=$2 csource compiler/nim.ini $1" % + [args, NimVersion, compileNimInst, findNim()]) proc zip(args: string) = - exec("$3 cc -r $2 --var:version=$1 zip compiler/nimrod.ini" % - [NimrodVersion, compileNimInst, findNim()]) + exec("$3 cc -r $2 --var:version=$1 zip compiler/nim.ini" % + [NimVersion, compileNimInst, findNim()]) proc buildTool(toolname, args: string) = exec("$# cc $# $#" % [findNim(), args, toolname]) @@ -96,50 +96,60 @@ proc inno(args: string) = # make sure we have generated the niminst executables: buildTool("tools/niminst/niminst", args) buildTool("tools/nimgrep", args) - exec("tools" / "niminst" / "niminst --var:version=$# inno compiler/nimrod" % - NimrodVersion) + exec("tools" / "niminst" / "niminst --var:version=$# inno compiler/nim" % + NimVersion) proc install(args: string) = - exec("$# cc -r $# --var:version=$# scripts compiler/nimrod.ini" % - [findNim(), compileNimInst, NimrodVersion]) + exec("$# cc -r $# --var:version=$# scripts compiler/nim.ini" % + [findNim(), compileNimInst, NimVersion]) exec("sh ./install.sh $#" % args) proc web(args: string) = - exec("$# cc -r tools/nimweb.nim web/nimrod --putenv:nimrodversion=$#" % - [findNim(), NimrodVersion]) + exec("$# cc -r tools/nimweb.nim $# web/nim --putenv:nimversion=$#" % + [findNim(), args, NimVersion]) # -------------- boot --------------------------------------------------------- const bootOptions = "" # options to pass to the bootstrap process -proc findStartNimrod: string = +proc findStartNim: string = # we try several things before giving up: + # * bin/nim + # * $PATH/nim # * bin/nimrod # * $PATH/nimrod - # If these fail, we try to build nimrod with the "build.(sh|bat)" script. + # If these fail, we try to build nim with the "build.(sh|bat)" script. + var nim = "nim".exe + result = "bin" / nim + if existsFile(result): return + for dir in split(getEnv("PATH"), PathSep): + if existsFile(dir / nim): return dir / nim + + # try the old "nimrod.exe": var nimrod = "nimrod".exe result = "bin" / nimrod if existsFile(result): return for dir in split(getEnv("PATH"), PathSep): - if existsFile(dir / nimrod): return dir / nimrod + if existsFile(dir / nim): return dir / nimrod + when defined(Posix): const buildScript = "build.sh" if existsFile(buildScript): - if tryExec("./" & buildScript): return "bin" / nimrod + if tryExec("./" & buildScript): return "bin" / nim else: const buildScript = "build.bat" if existsFile(buildScript): - if tryExec(buildScript): return "bin" / nimrod - - echo("Found no nimrod compiler and every attempt to build one failed!") + if tryExec(buildScript): return "bin" / nim + + echo("Found no nim compiler and every attempt to build one failed!") quit("FAILURE") proc safeRemove(filename: string) = if existsFile(filename): removeFile(filename) proc thVersion(i: int): string = - result = ("compiler" / "nimrod" & $i).exe + result = ("compiler" / "nim" & $i).exe proc copyExe(source, dest: string) = safeRemove(dest) @@ -147,13 +157,13 @@ proc copyExe(source, dest: string) = inclFilePermissions(dest, {fpUserExec}) proc boot(args: string) = - var output = "compiler" / "nimrod".exe - var finalDest = "bin" / "nimrod".exe + var output = "compiler" / "nim".exe + var finalDest = "bin" / "nim".exe - copyExe(findStartNimrod(), 0.thVersion) + copyExe(findStartNim(), 0.thVersion) for i in 0..2: echo "iteration: ", i+1 - exec i.thVersion & " c $# $# compiler" / "nimrod.nim" % [bootOptions, args] + exec i.thVersion & " c $# $# compiler" / "nim.nim" % [bootOptions, args] if sameFileContent(output, i.thVersion): copyExe(output, finalDest) echo "executables are equal: SUCCESS!" @@ -171,7 +181,7 @@ const ".idx", ".ilk" ] ignore = [ - ".bzrignore", "nimrod", "nimrod.exe", "koch", "koch.exe", ".gitignore" + ".bzrignore", "nim", "nim.exe", "koch", "koch.exe", ".gitignore" ] proc cleanAux(dir: string) = @@ -275,20 +285,20 @@ template `|`(a, b): expr = (if a.len > 0: a else: b) proc tests(args: string) = # we compile the tester with taintMode:on to have a basic # taint mode test :-) - exec "nimrod cc --taintMode:on tests/testament/tester" + exec "nim cc --taintMode:on tests/testament/tester" let tester = quoteShell(getCurrentDir() / "tests/testament/tester".exe) exec tester & " " & (args|"all") exec tester & " html" proc temp(args: string) = - var output = "compiler" / "nimrod".exe - var finalDest = "bin" / "nimrod_temp".exe - exec("nimrod c compiler" / "nimrod") + var output = "compiler" / "nim".exe + var finalDest = "bin" / "nim_temp".exe + exec("nim c compiler" / "nim") copyExe(output, finalDest) if args.len > 0: exec(finalDest & " " & args) proc showHelp() = - quit(HelpText % [NimrodVersion & repeatChar(44-len(NimrodVersion)), + quit(HelpText % [NimVersion & repeatChar(44-len(NimVersion)), CompileDate, CompileTime]) var op = initOptParser() @@ -296,7 +306,7 @@ op.next() case op.kind of cmdLongOption, cmdShortOption: showHelp() of cmdArgument: - case normalize(op.key) + case normalize(op.key) of "boot": boot(op.cmdLineRest) of "clean": clean(op.cmdLineRest) of "web": web(op.cmdLineRest) @@ -305,7 +315,7 @@ of cmdArgument: of "inno": inno(op.cmdLineRest) of "install": install(op.cmdLineRest) of "test", "tests": tests(op.cmdLineRest) - of "update": + of "update": when defined(withUpdate): update(op.cmdLineRest) else: @@ -313,4 +323,3 @@ of cmdArgument: of "temp": temp(op.cmdLineRest) else: showHelp() of cmdEnd: showHelp() - diff --git a/lib/core/locks.nim b/lib/core/locks.nim index 894965a85..42a3aec7b 100644 --- a/lib/core/locks.nim +++ b/lib/core/locks.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This module contains Nimrod's support for locks and condition vars. +## This module contains Nim's support for locks and condition vars. ## If the symbol ``preventDeadlocks`` is defined ## (compiled with ``-d:preventDeadlocks``) special logic is added to ## every ``acquire``, ``tryAcquire`` and ``release`` action that ensures at @@ -18,17 +18,19 @@ include "system/syslocks" type - TLock* = TSysLock ## Nimrod lock; whether this is re-entrant + TLock* = TSysLock ## Nim lock; whether this is re-entrant ## or not is unspecified! However, compilation ## in preventDeadlocks-mode guarantees re-entrancy. - TCond* = TSysCond ## Nimrod condition variable + TCond* = TSysCond ## Nim condition variable - FLock* = object of TEffect ## effect that denotes that some lock operation - ## is performed - FAquireLock* = object of FLock ## effect that denotes that some lock is - ## aquired - FReleaseLock* = object of FLock ## effect that denotes that some lock is - ## released + LockEffect* = object of RootEffect ## effect that denotes that some lock operation + ## is performed + AquireEffect* = object of LockEffect ## effect that denotes that some lock is + ## aquired + ReleaseEffect* = object of LockEffect ## effect that denotes that some lock is + ## released +{.deprecated: [FLock: LockEffect, FAquireLock: AquireEffect, + FReleaseLock: ReleaseEffect].} const noDeadlocks = defined(preventDeadlocks) @@ -58,7 +60,7 @@ proc deinitLock*(lock: var TLock) {.inline.} = ## Frees the resources associated with the lock. deinitSys(lock) -proc tryAcquire*(lock: var TLock): bool {.tags: [FAquireLock].} = +proc tryAcquire*(lock: var TLock): bool {.tags: [AquireEffect].} = ## Tries to acquire the given lock. Returns `true` on success. result = tryAcquireSys(lock) when noDeadlocks: @@ -90,7 +92,7 @@ proc tryAcquire*(lock: var TLock): bool {.tags: [FAquireLock].} = inc(locksLen) assert orderedLocks() -proc acquire*(lock: var TLock) {.tags: [FAquireLock].} = +proc acquire*(lock: var TLock) {.tags: [AquireEffect].} = ## Acquires the given lock. when nodeadlocks: var p = addr(lock) @@ -135,7 +137,7 @@ proc acquire*(lock: var TLock) {.tags: [FAquireLock].} = else: acquireSys(lock) -proc release*(lock: var TLock) {.tags: [FReleaseLock].} = +proc release*(lock: var TLock) {.tags: [ReleaseEffect].} = ## Releases the given lock. when nodeadlocks: var p = addr(lock) diff --git a/lib/core/macros.nim b/lib/core/macros.nim index e290cce32..32e74aebf 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -97,7 +97,7 @@ type TNimSymKinds* = set[TNimrodSymKind] type - TNimrodIdent* = object of TObject + TNimrodIdent* = object of RootObj ## represents a Nimrod identifier in the AST TNimrodSymbol {.final.} = object # hidden @@ -261,7 +261,7 @@ proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst", noSideE ## Obtains the AST nodes returned from a macro or template invocation. ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## macro FooMacro() = ## var ast = getAst(BarTemplate()) @@ -278,7 +278,7 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect. ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## macro check(ex: expr): stmt = ## # this is a simplified version of the check macro from the @@ -422,7 +422,7 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} = add(result, ")") macro dumpTree*(s: stmt): stmt {.immediate.} = echo s.treeRepr - ## Accepts a block of nimrod code and prints the parsed abstract syntax + ## Accepts a block of nim code and prints the parsed abstract syntax ## tree using the `toTree` function. Printing is done *at compile time*. ## ## You can use this as a tool to explore the Nimrod's abstract syntax @@ -430,7 +430,7 @@ macro dumpTree*(s: stmt): stmt {.immediate.} = echo s.treeRepr ## a certain expression/statement. macro dumpLisp*(s: stmt): stmt {.immediate.} = echo s.lispRepr - ## Accepts a block of nimrod code and prints the parsed abstract syntax + ## Accepts a block of nim code and prints the parsed abstract syntax ## tree using the `toLisp` function. Printing is done *at compile time*. ## ## See `dumpTree`. @@ -489,7 +489,7 @@ proc newIdentDefs*(name, kind: PNimrodNode; ## ``let`` or ``var`` blocks may have an empty ``kind`` node if the ## identifier is being assigned a value. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## var varSection = newNimNode(nnkVarSection).add( ## newIdentDefs(ident("a"), ident("string")), @@ -501,7 +501,7 @@ proc newIdentDefs*(name, kind: PNimrodNode; ## If you need to create multiple identifiers you need to use the lower level ## ``newNimNode``: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## result = newNimNode(nnkIdentDefs).add( ## ident("a"), ident("b"), ident("c"), ident("string"), @@ -549,7 +549,7 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: PNimrodNode]]): PNimrodNode {.compiletime.} = ## Constructor for ``if`` statements. ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## newIfStmt( ## (Ident, StmtList), @@ -596,7 +596,7 @@ proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}= someProc[4] = val -template badnodekind(k; f): stmt{.immediate.} = +template badNodeKind(k; f): stmt{.immediate.} = assert false, "Invalid node kind $# for macros.`$2`".format(k, f) proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} = @@ -608,7 +608,7 @@ proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} = of nnkForStmt: return someProc.last else: - badNodeKind someproc.kind, "body" + badNodeKind someProc.kind, "body" proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} = case someProc.kind @@ -643,7 +643,7 @@ template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {. immediate, dirty.} = ## Find the first child node matching condition (or nil). ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var res = findChild(n, it.kind == nnkPostfix and ## it.basename.ident == !"foo") block: @@ -738,11 +738,11 @@ proc addIdentIfAbsent*(dest: PNimrodNode, ident: string) {.compiletime.} = when not defined(booting): template emit*(e: static[string]): stmt = - ## accepts a single string argument and treats it as nimrod code + ## accepts a single string argument and treats it as nim code ## that should be inserted verbatim in the program ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## emit("echo " & '"' & "hello world".toUpper & '"') ## macro payload: stmt {.gensym.} = diff --git a/lib/core/typeinfo.nim b/lib/core/typeinfo.nim index 8df1b3dfb..842a944e1 100644 --- a/lib/core/typeinfo.nim +++ b/lib/core/typeinfo.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Dominik Picheta, Andreas Rumpf # # See the file "copying.txt", included in this @@ -50,7 +50,7 @@ type akUInt32 = 43, ## any represents an unsigned int32 akUInt64 = 44, ## any represents an unsigned int64 - TAny* = object {.pure.} ## can represent any nimrod value; NOTE: the wrapped + TAny* = object {.pure.} ## can represent any nim value; NOTE: the wrapped ## value can be modified with its wrapper! This means ## that ``TAny`` keeps a non-traced pointer to its ## wrapped value and **must not** live longer than @@ -68,20 +68,20 @@ type const GenericSeqSize = (2 * sizeof(int)) -proc genericAssign(dest, src: Pointer, mt: PNimType) {.importCompilerProc.} -proc genericShallowAssign(dest, src: Pointer, mt: PNimType) {. +proc genericAssign(dest, src: pointer, mt: PNimType) {.importCompilerProc.} +proc genericShallowAssign(dest, src: pointer, mt: PNimType) {. importCompilerProc.} proc incrSeq(seq: PGenSeq, elemSize: int): PGenSeq {.importCompilerProc.} proc newObj(typ: PNimType, size: int): pointer {.importCompilerProc.} proc newSeq(typ: PNimType, len: int): pointer {.importCompilerProc.} -proc objectInit(dest: Pointer, typ: PNimType) {.importCompilerProc.} +proc objectInit(dest: pointer, typ: PNimType) {.importCompilerProc.} -template `+!!`(a, b: expr): expr = cast[pointer](cast[TAddress](a) + b) +template `+!!`(a, b: expr): expr = cast[pointer](cast[ByteAddress](a) + b) -proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int = +proc getDiscriminant(aa: pointer, n: ptr TNimNode): int = assert(n.kind == nkCase) var d: int - var a = cast[TAddress](aa) + var a = cast[ByteAddress](aa) case n.typ.size of 1: d = ze(cast[ptr int8](a +% n.offset)[]) of 2: d = ze(cast[ptr int16](a +% n.offset)[]) @@ -89,7 +89,7 @@ proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int = else: assert(false) return d -proc selectBranch(aa: Pointer, n: ptr TNimNode): ptr TNimNode = +proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = var discr = getDiscriminant(aa, n) if discr <% n.len: result = n.sons[discr] @@ -174,14 +174,14 @@ proc `[]`*(x: TAny, i: int): TAny = of tyArray: var bs = x.rawType.base.size if i >=% x.rawType.size div bs: - raise newException(EInvalidIndex, "index out of bounds") + raise newException(IndexError, "index out of bounds") return newAny(x.value +!! i*bs, x.rawType.base) of tySequence: var s = cast[ppointer](x.value)[] - if s == nil: raise newException(EInvalidValue, "sequence is nil") + if s == nil: raise newException(ValueError, "sequence is nil") var bs = x.rawType.base.size if i >=% cast[PGenSeq](s).len: - raise newException(EInvalidIndex, "index out of bounds") + raise newException(IndexError, "index out of bounds") return newAny(s +!! (GenericSeqSize+i*bs), x.rawType.base) else: assert false @@ -191,15 +191,15 @@ proc `[]=`*(x: TAny, i: int, y: TAny) = of tyArray: var bs = x.rawType.base.size if i >=% x.rawType.size div bs: - raise newException(EInvalidIndex, "index out of bounds") + raise newException(IndexError, "index out of bounds") assert y.rawType == x.rawType.base genericAssign(x.value +!! i*bs, y.value, y.rawType) of tySequence: var s = cast[ppointer](x.value)[] - if s == nil: raise newException(EInvalidValue, "sequence is nil") + if s == nil: raise newException(ValueError, "sequence is nil") var bs = x.rawType.base.size if i >=% cast[PGenSeq](s).len: - raise newException(EInvalidIndex, "index out of bounds") + raise newException(IndexError, "index out of bounds") assert y.rawType == x.rawType.base genericAssign(s +!! (GenericSeqSize+i*bs), y.value, y.rawType) else: assert false @@ -276,7 +276,7 @@ proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} = else: result = c var i = 0 var j = 0 - while True: + while true: while a[i] == '_': inc(i) while b[j] == '_': inc(j) # BUGFIX: typo var aa = toLower(a[i]) @@ -311,12 +311,12 @@ proc `[]=`*(x: TAny, fieldName: string, value: TAny) = when false: if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[] assert x.rawType.kind in {tyTuple, tyObject} - var n = getFieldNode(x.value, t.node, fieldname) + var n = getFieldNode(x.value, t.node, fieldName) if n != nil: assert n.typ == value.rawType genericAssign(x.value +!! n.offset, value.value, value.rawType) else: - raise newException(EInvalidValue, "invalid field name: " & fieldName) + raise newException(ValueError, "invalid field name: " & fieldName) proc `[]`*(x: TAny, fieldName: string): TAny = ## gets a field of `x`; `x` represents an object or a tuple. @@ -325,80 +325,80 @@ proc `[]`*(x: TAny, fieldName: string): TAny = when false: if x.rawType.kind == tyObject: t = cast[ptr PNimType](x.value)[] assert x.rawType.kind in {tyTuple, tyObject} - var n = getFieldNode(x.value, t.node, fieldname) + var n = getFieldNode(x.value, t.node, fieldName) if n != nil: result.value = x.value +!! n.offset result.rawType = n.typ else: - raise newException(EInvalidValue, "invalid field name: " & fieldName) + raise newException(ValueError, "invalid field name: " & fieldName) proc `[]`*(x: TAny): TAny = ## dereference operation for the any `x` that represents a ptr or a ref. - assert x.rawtype.kind in {tyRef, tyPtr} + assert x.rawType.kind in {tyRef, tyPtr} result.value = cast[ppointer](x.value)[] result.rawType = x.rawType.base proc `[]=`*(x, y: TAny) = ## dereference operation for the any `x` that represents a ptr or a ref. - assert x.rawtype.kind in {tyRef, tyPtr} + assert x.rawType.kind in {tyRef, tyPtr} assert y.rawType == x.rawType.base genericAssign(cast[ppointer](x.value)[], y.value, y.rawType) proc getInt*(x: TAny): int = ## retrieve the int value out of `x`. `x` needs to represent an int. - assert skipRange(x.rawtype).kind == tyInt + assert skipRange(x.rawType).kind == tyInt result = cast[ptr int](x.value)[] proc getInt8*(x: TAny): int8 = ## retrieve the int8 value out of `x`. `x` needs to represent an int8. - assert skipRange(x.rawtype).kind == tyInt8 + assert skipRange(x.rawType).kind == tyInt8 result = cast[ptr int8](x.value)[] proc getInt16*(x: TAny): int16 = ## retrieve the int16 value out of `x`. `x` needs to represent an int16. - assert skipRange(x.rawtype).kind == tyInt16 + assert skipRange(x.rawType).kind == tyInt16 result = cast[ptr int16](x.value)[] proc getInt32*(x: TAny): int32 = ## retrieve the int32 value out of `x`. `x` needs to represent an int32. - assert skipRange(x.rawtype).kind == tyInt32 + assert skipRange(x.rawType).kind == tyInt32 result = cast[ptr int32](x.value)[] proc getInt64*(x: TAny): int64 = ## retrieve the int64 value out of `x`. `x` needs to represent an int64. - assert skipRange(x.rawtype).kind == tyInt64 + assert skipRange(x.rawType).kind == tyInt64 result = cast[ptr int64](x.value)[] -proc getBiggestInt*(x: TAny): biggestInt = +proc getBiggestInt*(x: TAny): BiggestInt = ## retrieve the integer value out of `x`. `x` needs to represent ## some integer, a bool, a char, an enum or a small enough bit set. - ## The value might be sign-extended to ``biggestInt``. - var t = skipRange(x.rawtype) + ## The value might be sign-extended to ``BiggestInt``. + var t = skipRange(x.rawType) case t.kind - of tyInt: result = biggestInt(cast[ptr int](x.value)[]) - of tyInt8: result = biggestInt(cast[ptr int8](x.value)[]) - of tyInt16: result = biggestInt(cast[ptr int16](x.value)[]) - of tyInt32: result = biggestInt(cast[ptr int32](x.value)[]) - of tyInt64, tyUInt64: result = biggestInt(cast[ptr int64](x.value)[]) - of tyBool: result = biggestInt(cast[ptr bool](x.value)[]) - of tyChar: result = biggestInt(cast[ptr char](x.value)[]) + of tyInt: result = BiggestInt(cast[ptr int](x.value)[]) + of tyInt8: result = BiggestInt(cast[ptr int8](x.value)[]) + of tyInt16: result = BiggestInt(cast[ptr int16](x.value)[]) + of tyInt32: result = BiggestInt(cast[ptr int32](x.value)[]) + of tyInt64, tyUInt64: result = BiggestInt(cast[ptr int64](x.value)[]) + of tyBool: result = BiggestInt(cast[ptr bool](x.value)[]) + of tyChar: result = BiggestInt(cast[ptr char](x.value)[]) of tyEnum, tySet: case t.size of 1: result = ze64(cast[ptr int8](x.value)[]) of 2: result = ze64(cast[ptr int16](x.value)[]) - of 4: result = biggestInt(cast[ptr int32](x.value)[]) - of 8: result = biggestInt(cast[ptr int64](x.value)[]) + of 4: result = BiggestInt(cast[ptr int32](x.value)[]) + of 8: result = BiggestInt(cast[ptr int64](x.value)[]) else: assert false - of tyUInt: result = biggestInt(cast[ptr uint](x.value)[]) - of tyUInt8: result = biggestInt(cast[ptr uint8](x.value)[]) - of tyUInt16: result = biggestInt(cast[ptr uint16](x.value)[]) - of tyUInt32: result = biggestInt(cast[ptr uint32](x.value)[]) + of tyUInt: result = BiggestInt(cast[ptr uint](x.value)[]) + of tyUInt8: result = BiggestInt(cast[ptr uint8](x.value)[]) + of tyUInt16: result = BiggestInt(cast[ptr uint16](x.value)[]) + of tyUInt32: result = BiggestInt(cast[ptr uint32](x.value)[]) else: assert false -proc setBiggestInt*(x: TAny, y: biggestInt) = +proc setBiggestInt*(x: TAny, y: BiggestInt) = ## sets the integer value of `x`. `x` needs to represent ## some integer, a bool, a char, an enum or a small enough bit set. - var t = skipRange(x.rawtype) + var t = skipRange(x.rawType) case t.kind of tyInt: cast[ptr int](x.value)[] = int(y) of tyInt8: cast[ptr int8](x.value)[] = int8(y) @@ -422,37 +422,37 @@ proc setBiggestInt*(x: TAny, y: biggestInt) = proc getUInt*(x: TAny): uint = ## retrieve the uint value out of `x`, `x` needs to represent an uint. - assert skipRange(x.rawtype).kind == tyUInt + assert skipRange(x.rawType).kind == tyUInt result = cast[ptr uint](x.value)[] proc getUInt8*(x: TAny): uint8 = ## retrieve the uint8 value out of `x`, `x` needs to represent an ## uint8. - assert skipRange(x.rawtype).kind == tyUInt8 + assert skipRange(x.rawType).kind == tyUInt8 result = cast[ptr uint8](x.value)[] proc getUInt16*(x: TAny): uint16 = ## retrieve the uint16 value out of `x`, `x` needs to represent an ## uint16. - assert skipRange(x.rawtype).kind == tyUInt16 + assert skipRange(x.rawType).kind == tyUInt16 result = cast[ptr uint16](x.value)[] proc getUInt32*(x: TAny): uint32 = ## retrieve the uint32 value out of `x`, `x` needs to represent an ## uint32. - assert skipRange(x.rawtype).kind == tyUInt32 + assert skipRange(x.rawType).kind == tyUInt32 result = cast[ptr uint32](x.value)[] proc getUInt64*(x: TAny): uint64 = ## retrieve the uint64 value out of `x`, `x` needs to represent an ## uint64. - assert skipRange(x.rawtype).kind == tyUInt64 + assert skipRange(x.rawType).kind == tyUInt64 result = cast[ptr uint64](x.value)[] proc getBiggestUint*(x: TAny): uint64 = ## retrieve the unsigned integer value out of `x`. `x` needs to ## represent an unsigned integer. - var t = skipRange(x.rawtype) + var t = skipRange(x.rawType) case t.kind of tyUInt: result = uint64(cast[ptr uint](x.value)[]) of tyUInt8: result = uint64(cast[ptr uint8](x.value)[]) @@ -464,7 +464,7 @@ proc getBiggestUint*(x: TAny): uint64 = proc setBiggestUint*(x: TAny; y: uint64) = ## sets the unsigned integer value of `c`. `c` needs to represent an ## unsigned integer. - var t = skipRange(x.rawtype) + var t = skipRange(x.rawType) case t.kind: of tyUInt: cast[ptr uint](x.value)[] = uint(y) of tyUInt8: cast[ptr uint8](x.value)[] = uint8(y) @@ -475,13 +475,13 @@ proc setBiggestUint*(x: TAny; y: uint64) = proc getChar*(x: TAny): char = ## retrieve the char value out of `x`. `x` needs to represent a char. - var t = skipRange(x.rawtype) + var t = skipRange(x.rawType) assert t.kind == tyChar result = cast[ptr char](x.value)[] proc getBool*(x: TAny): bool = ## retrieve the bool value out of `x`. `x` needs to represent a bool. - var t = skipRange(x.rawtype) + var t = skipRange(x.rawType) assert t.kind == tyBool result = cast[ptr bool](x.value)[] @@ -495,7 +495,7 @@ proc getEnumOrdinal*(x: TAny, name: string): int = ## gets the enum field ordinal from `name`. `x` needs to represent an enum ## but is only used to access the type information. In case of an error ## ``low(int)`` is returned. - var typ = skipRange(x.rawtype) + var typ = skipRange(x.rawType) assert typ.kind == tyEnum var n = typ.node var s = n.sons @@ -511,7 +511,7 @@ proc getEnumField*(x: TAny, ordinalValue: int): string = ## gets the enum field name as a string. `x` needs to represent an enum ## but is only used to access the type information. The field name of ## `ordinalValue` is returned. - var typ = skipRange(x.rawtype) + var typ = skipRange(x.rawType) assert typ.kind == tyEnum var e = ordinalValue if ntfEnumHole notin typ.flags: @@ -531,51 +531,51 @@ proc getEnumField*(x: TAny): string = proc getFloat*(x: TAny): float = ## retrieve the float value out of `x`. `x` needs to represent an float. - assert skipRange(x.rawtype).kind == tyFloat + assert skipRange(x.rawType).kind == tyFloat result = cast[ptr float](x.value)[] proc getFloat32*(x: TAny): float32 = ## retrieve the float32 value out of `x`. `x` needs to represent an float32. - assert skipRange(x.rawtype).kind == tyFloat32 + assert skipRange(x.rawType).kind == tyFloat32 result = cast[ptr float32](x.value)[] proc getFloat64*(x: TAny): float64 = ## retrieve the float64 value out of `x`. `x` needs to represent an float64. - assert skipRange(x.rawtype).kind == tyFloat64 + assert skipRange(x.rawType).kind == tyFloat64 result = cast[ptr float64](x.value)[] -proc getBiggestFloat*(x: TAny): biggestFloat = +proc getBiggestFloat*(x: TAny): BiggestFloat = ## retrieve the float value out of `x`. `x` needs to represent - ## some float. The value is extended to ``biggestFloat``. - case skipRange(x.rawtype).kind - of tyFloat: result = biggestFloat(cast[ptr Float](x.value)[]) - of tyFloat32: result = biggestFloat(cast[ptr Float32](x.value)[]) - of tyFloat64: result = biggestFloat(cast[ptr Float64](x.value)[]) + ## some float. The value is extended to ``BiggestFloat``. + case skipRange(x.rawType).kind + of tyFloat: result = BiggestFloat(cast[ptr float](x.value)[]) + of tyFloat32: result = BiggestFloat(cast[ptr float32](x.value)[]) + of tyFloat64: result = BiggestFloat(cast[ptr float64](x.value)[]) else: assert false -proc setBiggestFloat*(x: TAny, y: biggestFloat) = +proc setBiggestFloat*(x: TAny, y: BiggestFloat) = ## sets the float value of `x`. `x` needs to represent ## some float. - case skipRange(x.rawtype).kind - of tyFloat: cast[ptr Float](x.value)[] = y - of tyFloat32: cast[ptr Float32](x.value)[] = y.float32 - of tyFloat64: cast[ptr Float64](x.value)[] = y + case skipRange(x.rawType).kind + of tyFloat: cast[ptr float](x.value)[] = y + of tyFloat32: cast[ptr float32](x.value)[] = y.float32 + of tyFloat64: cast[ptr float64](x.value)[] = y else: assert false proc getString*(x: TAny): string = ## retrieve the string value out of `x`. `x` needs to represent a string. - assert x.rawtype.kind == tyString + assert x.rawType.kind == tyString if not isNil(cast[ptr pointer](x.value)[]): result = cast[ptr string](x.value)[] proc setString*(x: TAny, y: string) = ## sets the string value of `x`. `x` needs to represent a string. - assert x.rawtype.kind == tyString + assert x.rawType.kind == tyString cast[ptr string](x.value)[] = y proc getCString*(x: TAny): cstring = ## retrieve the cstring value out of `x`. `x` needs to represent a cstring. - assert x.rawtype.kind == tyCString + assert x.rawType.kind == tyCString result = cast[ptr cstring](x.value)[] proc assign*(x, y: TAny) = @@ -585,9 +585,9 @@ proc assign*(x, y: TAny) = genericAssign(x.value, y.value, y.rawType) iterator elements*(x: TAny): int = - ## iterates over every element of `x` that represents a Nimrod bitset. + ## iterates over every element of `x` that represents a Nim bitset. assert x.rawType.kind == tySet - var typ = x.rawtype + var typ = x.rawType var p = x.value # "typ.slots.len" field is for sets the "first" field var u: int64 @@ -607,9 +607,9 @@ iterator elements*(x: TAny): int = yield i+typ.node.len proc inclSetElement*(x: TAny, elem: int) = - ## includes an element `elem` in `x`. `x` needs to represent a Nimrod bitset. + ## includes an element `elem` in `x`. `x` needs to represent a Nim bitset. assert x.rawType.kind == tySet - var typ = x.rawtype + var typ = x.rawType var p = x.value # "typ.slots.len" field is for sets the "first" field var e = elem - typ.node.len diff --git a/lib/core/unsigned.nim b/lib/core/unsigned.nim index a3ddd4125..7acdf1439 100644 --- a/lib/core/unsigned.nim +++ b/lib/core/unsigned.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim index eec4daf00..d57e8d641 100644 --- a/lib/impure/db_mysql.nim +++ b/lib/impure/db_mysql.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -78,17 +78,17 @@ proc tryExec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): bool { tags: [FReadDB, FWriteDb].} = ## tries to execute the query and returns true if successful, false otherwise. var q = dbFormat(query, args) - return mysql.RealQuery(db, q, q.len) == 0'i32 + return mysql.realQuery(db, q, q.len) == 0'i32 proc rawExec(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) = var q = dbFormat(query, args) - if mysql.RealQuery(db, q, q.len) != 0'i32: dbError(db) + if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db) proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {. tags: [FReadDB, FWriteDb].} = ## executes the query and raises EDB if not successful. var q = dbFormat(query, args) - if mysql.RealQuery(db, q, q.len) != 0'i32: dbError(db) + if mysql.realQuery(db, q, q.len) != 0'i32: dbError(db) proc newRow(L: int): TRow = newSeq(result, L) @@ -96,8 +96,8 @@ proc newRow(L: int): TRow = proc properFreeResult(sqlres: mysql.PRES, row: cstringArray) = if row != nil: - while mysql.FetchRow(sqlres) != nil: discard - mysql.FreeResult(sqlres) + while mysql.fetchRow(sqlres) != nil: discard + mysql.freeResult(sqlres) iterator fastRows*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): TRow {.tags: [FReadDB].} = @@ -105,13 +105,13 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery, ## fast, but potenially dangerous: If the for-loop-body executes another ## query, the results can be undefined. For MySQL this is the case!. rawExec(db, query, args) - var sqlres = mysql.UseResult(db) + var sqlres = mysql.useResult(db) if sqlres != nil: - var L = int(mysql.NumFields(sqlres)) + var L = int(mysql.numFields(sqlres)) var result = newRow(L) var row: cstringArray while true: - row = mysql.FetchRow(sqlres) + row = mysql.fetchRow(sqlres) if row == nil: break for i in 0..L-1: setLen(result[i], 0) @@ -124,11 +124,11 @@ proc getRow*(db: TDbConn, query: TSqlQuery, ## retrieves a single row. If the query doesn't return any rows, this proc ## will return a TRow with empty strings for each column. rawExec(db, query, args) - var sqlres = mysql.UseResult(db) + var sqlres = mysql.useResult(db) if sqlres != nil: - var L = int(mysql.NumFields(sqlres)) + var L = int(mysql.numFields(sqlres)) result = newRow(L) - var row = mysql.FetchRow(sqlres) + var row = mysql.fetchRow(sqlres) if row != nil: for i in 0..L-1: setLen(result[i], 0) @@ -140,24 +140,24 @@ proc getAllRows*(db: TDbConn, query: TSqlQuery, ## executes the query and returns the whole result dataset. result = @[] rawExec(db, query, args) - var sqlres = mysql.UseResult(db) + var sqlres = mysql.useResult(db) if sqlres != nil: - var L = int(mysql.NumFields(sqlres)) + var L = int(mysql.numFields(sqlres)) var row: cstringArray var j = 0 while true: - row = mysql.FetchRow(sqlres) + row = mysql.fetchRow(sqlres) if row == nil: break setLen(result, j+1) newSeq(result[j], L) for i in 0..L-1: result[j][i] = $row[i] inc(j) - mysql.FreeResult(sqlres) + mysql.freeResult(sqlres) iterator rows*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): TRow {.tags: [FReadDB].} = - ## same as `FastRows`, but slower and safe. - for r in items(GetAllRows(db, query, args)): yield r + ## same as `fastRows`, but slower and safe. + for r in items(getAllRows(db, query, args)): yield r proc getValue*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): string {.tags: [FReadDB].} = @@ -165,7 +165,7 @@ proc getValue*(db: TDbConn, query: TSqlQuery, ## result dataset. Returns "" if the dataset contains no rows or the database ## value is NULL. result = "" - for row in FastRows(db, query, args): + for row in fastRows(db, query, args): result = row[0] break @@ -174,16 +174,16 @@ proc tryInsertId*(db: TDbConn, query: TSqlQuery, ## executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. var q = dbFormat(query, args) - if mysql.RealQuery(db, q, q.len) != 0'i32: + if mysql.realQuery(db, q, q.len) != 0'i32: result = -1'i64 else: - result = mysql.InsertId(db) + result = mysql.insertId(db) proc insertId*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} = ## executes the query (typically "INSERT") and returns the ## generated ID for the row. - result = TryInsertID(db, query, args) + result = tryInsertID(db, query, args) if result < 0: dbError(db) proc execAffectedRows*(db: TDbConn, query: TSqlQuery, @@ -192,7 +192,7 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery, ## runs the query (typically "UPDATE") and returns the ## number of affected rows rawExec(db, query, args) - result = mysql.AffectedRows(db) + result = mysql.affectedRows(db) proc close*(db: TDbConn) {.tags: [FDb].} = ## closes the database connection. @@ -202,7 +202,7 @@ proc open*(connection, user, password, database: string): TDbConn {. tags: [FDb].} = ## opens a database connection. Raises `EDb` if the connection could not ## be established. - result = mysql.Init(nil) + result = mysql.init(nil) if result == nil: dbError("could not open database connection") let colonPos = connection.find(':') @@ -210,9 +210,9 @@ proc open*(connection, user, password, database: string): TDbConn {. else: substr(connection, 0, colonPos-1) port: int32 = if colonPos < 0: 0'i32 else: substr(connection, colonPos+1).parseInt.int32 - if mysql.RealConnect(result, host, user, password, database, + if mysql.realConnect(result, host, user, password, database, port, nil, 0) == nil: var errmsg = $mysql.error(result) - db_mysql.Close(result) + db_mysql.close(result) dbError(errmsg) diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim index c375d9191..4080cd61f 100644 --- a/lib/impure/db_postgres.nim +++ b/lib/impure/db_postgres.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# Nim's Runtime Library +# (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -16,16 +16,16 @@ type TDbConn* = PPGconn ## 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 TSqlPrepared* = distinct string ## a identifier for the prepared queries - FDb* = object of FIO ## 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 + 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 -proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} = +proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} = ## constructs a TSqlQuery from the string `query`. This is supposed to be ## used as a raw-string-literal modifier: ## ``sql"update user set counter = counter + 1"`` @@ -38,7 +38,7 @@ proc dbError*(db: TDbConn) {.noreturn.} = ## raises an EDb exception. var e: ref EDb new(e) - e.msg = $PQerrorMessage(db) + e.msg = $pqErrorMessage(db) raise e proc dbError*(msg: string) {.noreturn.} = @@ -69,30 +69,30 @@ proc tryExec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} = ## tries to execute the query and returns true if successful, false otherwise. var arr = allocCStringArray(args) - var res = PQexecParams(db, query.string, int32(args.len), nil, arr, + var res = pqexecParams(db, query.string, int32(args.len), nil, arr, nil, nil, 0) deallocCStringArray(arr) - result = PQresultStatus(res) == PGRES_COMMAND_OK - PQclear(res) + result = pqresultStatus(res) == PGRES_COMMAND_OK + pqclear(res) proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {. tags: [FReadDB, FWriteDb].} = ## executes the query and raises EDB if not successful. var arr = allocCStringArray(args) - var res = PQexecParams(db, query.string, int32(args.len), nil, arr, + var res = pqexecParams(db, query.string, int32(args.len), nil, arr, nil, nil, 0) deallocCStringArray(arr) - if PQresultStatus(res) != PGRES_COMMAND_OK: dbError(db) - PQclear(res) + if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db) + pqclear(res) proc exec*(db: TDbConn, stmtName: TSqlPrepared, args: varargs[string]) {.tags: [FReadDB, FWriteDb].} = var arr = allocCStringArray(args) - var res = PQexecPrepared(db, stmtName.string, int32(args.len), arr, + var res = pqexecPrepared(db, stmtName.string, int32(args.len), arr, nil, nil, 0) deallocCStringArray(arr) - if PQResultStatus(res) != PGRES_COMMAND_OK: dbError(db) - PQclear(res) + if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db) + pqclear(res) proc newRow(L: int): TRow = newSeq(result, L) @@ -101,29 +101,29 @@ proc newRow(L: int): TRow = proc setupQuery(db: TDbConn, query: TSqlQuery, args: varargs[string]): PPGresult = var arr = allocCStringArray(args) - result = PQexecParams(db, query.string, int32(args.len), nil, arr, + result = pqexecParams(db, query.string, int32(args.len), nil, arr, nil, nil, 0) deallocCStringArray(arr) - if PQResultStatus(result) != PGRES_TUPLES_OK: dbError(db) + if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db) proc setupQuery(db: TDbConn, stmtName: TSqlPrepared, args: varargs[string]): PPGresult = var arr = allocCStringArray(args) - result = PQexecPrepared(db, stmtName.string, int32(args.len), arr, + result = pqexecPrepared(db, stmtName.string, int32(args.len), arr, nil, nil, 0) deallocCStringArray(arr) - if PQResultStatus(result) != PGRES_TUPLES_OK: dbError(db) + if pqResultStatus(result) != PGRES_TUPLES_OK: dbError(db) proc prepare*(db: TDbConn; stmtName: string, query: TSqlQuery; nParams: int): TSqlPrepared = - var res = PQprepare(db, stmtName, query.string, int32(nParams), nil) - if PQResultStatus(res) != PGRES_COMMAND_OK: dbError(db) + var res = pqprepare(db, stmtName, query.string, int32(nParams), nil) + if pqResultStatus(res) != PGRES_COMMAND_OK: dbError(db) return TSqlPrepared(stmtName) proc setRow(res: PPGresult, r: var TRow, line, cols: int32) = for col in 0..cols-1: setLen(r[col], 0) - var x = PQgetvalue(res, line, col) + var x = pqgetvalue(res, line, col) add(r[col], x) iterator fastRows*(db: TDbConn, query: TSqlQuery, @@ -132,12 +132,12 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery, ## fast, but potenially dangerous: If the for-loop-body executes another ## query, the results can be undefined. For Postgres it is safe though. var res = setupQuery(db, query, args) - var L = PQnfields(res) + var L = pqnfields(res) var result = newRow(L) - for i in 0..PQntuples(res)-1: + for i in 0..pqntuples(res)-1: setRow(res, result, i, L) yield result - PQclear(res) + pqclear(res) iterator fastRows*(db: TDbConn, stmtName: TSqlPrepared, args: varargs[string, `$`]): TRow {.tags: [FReadDB].} = @@ -155,24 +155,24 @@ proc getRow*(db: TDbConn, query: TSqlQuery, ## retrieves a single row. If the query doesn't return any rows, this proc ## will return a TRow with empty strings for each column. var res = setupQuery(db, query, args) - var L = PQnfields(res) + var L = pqnfields(res) result = newRow(L) setRow(res, result, 0, L) - PQclear(res) + pqclear(res) proc getRow*(db: TDbConn, stmtName: TSqlPrepared, - args: varargs[string, `$`]): TRow {.tags: [FReadDB].} = - var res = setupQuery(db, stmtName, args) - var L = PQnfields(res) - result = newRow(L) - setRow(res, result, 0, L) - PQclear(res) + args: varargs[string, `$`]): TRow {.tags: [FReadDB].} = + var res = setupQuery(db, stmtName, args) + var L = PQnfields(res) + result = newRow(L) + setRow(res, result, 0, L) + PQclear(res) proc getAllRows*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} = ## executes the query and returns the whole result dataset. result = @[] - for r in FastRows(db, query, args): + for r in fastRows(db, query, args): result.add(r) proc getAllRows*(db: TDbConn, stmtName: TSqlPrepared, @@ -184,15 +184,15 @@ proc getAllRows*(db: TDbConn, stmtName: TSqlPrepared, iterator rows*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): TRow {.tags: [FReadDB].} = - ## same as `FastRows`, but slower and safe. - for r in items(GetAllRows(db, query, args)): yield r + ## same as `fastRows`, but slower and safe. + for r in items(getAllRows(db, query, args)): yield r proc getValue*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): string {.tags: [FReadDB].} = ## executes the query and returns the first column of the first row of the ## result dataset. Returns "" if the dataset contains no rows or the database ## value is NULL. - var x = PQgetvalue(setupQuery(db, query, args), 0, 0) + var x = pqgetvalue(setupQuery(db, query, args), 0, 0) result = if isNil(x): "" else: $x proc tryInsertID*(db: TDbConn, query: TSqlQuery, @@ -201,10 +201,10 @@ proc tryInsertID*(db: TDbConn, query: TSqlQuery, ## generated ID for the row or -1 in case of an error. For Postgre this adds ## ``RETURNING id`` to the query, so it only works if your primary key is ## named ``id``. - var x = PQgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"), + var x = pqgetvalue(setupQuery(db, TSqlQuery(string(query) & " RETURNING id"), args), 0, 0) if not isNil(x): - result = ParseBiggestInt($x) + result = parseBiggestInt($x) else: result = -1 @@ -214,7 +214,7 @@ proc insertID*(db: TDbConn, query: TSqlQuery, ## generated ID for the row. For Postgre this adds ## ``RETURNING id`` to the query, so it only works if your primary key is ## named ``id``. - result = TryInsertID(db, query, args) + result = tryInsertID(db, query, args) if result < 0: dbError(db) proc execAffectedRows*(db: TDbConn, query: TSqlQuery, @@ -223,14 +223,14 @@ proc execAffectedRows*(db: TDbConn, query: TSqlQuery, ## executes the query (typically "UPDATE") and returns the ## number of affected rows. var q = dbFormat(query, args) - var res = PQExec(db, q) - if PQresultStatus(res) != PGRES_COMMAND_OK: dbError(db) - result = parseBiggestInt($PQcmdTuples(res)) - PQclear(res) + var res = pqExec(db, q) + if pqresultStatus(res) != PGRES_COMMAND_OK: dbError(db) + result = parseBiggestInt($pqcmdTuples(res)) + pqclear(res) proc close*(db: TDbConn) {.tags: [FDb].} = ## closes the database connection. - if db != nil: PQfinish(db) + if db != nil: pqfinish(db) proc open*(connection, user, password, database: string): TDbConn {. tags: [FDb].} = @@ -242,16 +242,14 @@ proc open*(connection, user, password, database: string): TDbConn {. ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## - ## con = Open("", "", "", "host=localhost port=5432 dbname=mydb") + ## con = open("", "", "", "host=localhost port=5432 dbname=mydb") ## ## See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING ## for more information. ## ## Note that the connection parameter is not used but exists to maintain - ## the nimrod db api. - result = PQsetdbLogin(nil, nil, nil, nil, database, user, password) - if PQStatus(result) != CONNECTION_OK: dbError(result) # result = nil - - + ## the nim db api. + result = pqsetdbLogin(nil, nil, nil, nil, database, user, password) + if pqStatus(result) != CONNECTION_OK: dbError(result) # result = nil diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim index 809ee7039..bc9e0b591 100644 --- a/lib/impure/db_sqlite.nim +++ b/lib/impure/db_sqlite.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -16,13 +16,13 @@ type TDbConn* = PSqlite3 ## 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 - FReadDb* = object of FDB ## effect that denotes a read operation - FWriteDb* = object of FDB ## effect that denotes a write 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 proc sql*(query: string): TSqlQuery {.noSideEffect, inline.} = ## constructs a TSqlQuery from the string `query`. This is supposed to be @@ -65,16 +65,16 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string = add(result, c) proc tryExec*(db: TDbConn, query: TSqlQuery, - args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} = + args: varargs[string, `$`]): bool {.tags: [FReadDb, FWriteDb].} = ## tries to execute the query and returns true if successful, false otherwise. var q = dbFormat(query, args) - var stmt: sqlite3.PStmt + var stmt: sqlite3.Pstmt if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK: if step(stmt) == SQLITE_DONE: result = finalize(stmt) == SQLITE_OK proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {. - tags: [FReadDB, FWriteDb].} = + tags: [FReadDb, FWriteDb].} = ## executes the query and raises EDB if not successful. if not tryExec(db, query, args): dbError(db) @@ -83,11 +83,11 @@ proc newRow(L: int): TRow = for i in 0..L-1: result[i] = "" proc setupQuery(db: TDbConn, query: TSqlQuery, - args: varargs[string]): PStmt = + args: varargs[string]): Pstmt = var q = dbFormat(query, args) if prepare_v2(db, q, q.len.cint, result, nil) != SQLITE_OK: dbError(db) -proc setRow(stmt: PStmt, r: var TRow, cols: cint) = +proc setRow(stmt: Pstmt, r: var TRow, cols: cint) = for col in 0..cols-1: setLen(r[col], column_bytes(stmt, col)) # set capacity setLen(r[col], 0) @@ -95,12 +95,12 @@ proc setRow(stmt: PStmt, r: var TRow, cols: cint) = if not isNil(x): add(r[col], x) iterator fastRows*(db: TDbConn, query: TSqlQuery, - args: varargs[string, `$`]): TRow {.tags: [FReadDB].} = + args: varargs[string, `$`]): TRow {.tags: [FReadDb].} = ## executes the query and iterates over the result dataset. This is very ## fast, but potenially dangerous: If the for-loop-body executes another ## query, the results can be undefined. For Sqlite it is safe though. var stmt = setupQuery(db, query, args) - var L = (columnCount(stmt)) + var L = (column_count(stmt)) var result = newRow(L) while step(stmt) == SQLITE_ROW: setRow(stmt, result, L) @@ -108,30 +108,30 @@ iterator fastRows*(db: TDbConn, query: TSqlQuery, if finalize(stmt) != SQLITE_OK: dbError(db) proc getRow*(db: TDbConn, query: TSqlQuery, - args: varargs[string, `$`]): TRow {.tags: [FReadDB].} = + args: varargs[string, `$`]): TRow {.tags: [FReadDb].} = ## retrieves a single row. If the query doesn't return any rows, this proc ## will return a TRow with empty strings for each column. var stmt = setupQuery(db, query, args) - var L = (columnCount(stmt)) + var L = (column_count(stmt)) result = newRow(L) if step(stmt) == SQLITE_ROW: setRow(stmt, result, L) if finalize(stmt) != SQLITE_OK: dbError(db) proc getAllRows*(db: TDbConn, query: TSqlQuery, - args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} = + args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDb].} = ## executes the query and returns the whole result dataset. result = @[] for r in fastRows(db, query, args): result.add(r) iterator rows*(db: TDbConn, query: TSqlQuery, - args: varargs[string, `$`]): TRow {.tags: [FReadDB].} = + args: varargs[string, `$`]): TRow {.tags: [FReadDb].} = ## same as `FastRows`, but slower and safe. for r in fastRows(db, query, args): yield r proc getValue*(db: TDbConn, query: TSqlQuery, - args: varargs[string, `$`]): string {.tags: [FReadDB].} = + args: varargs[string, `$`]): string {.tags: [FReadDb].} = ## executes the query and returns the first column of the first row of the ## result dataset. Returns "" if the dataset contains no rows or the database ## value is NULL. @@ -153,7 +153,7 @@ proc tryInsertID*(db: TDbConn, query: TSqlQuery, ## executes the query (typically "INSERT") and returns the ## generated ID for the row or -1 in case of an error. var q = dbFormat(query, args) - var stmt: sqlite3.PStmt + var stmt: sqlite3.Pstmt result = -1 if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK: if step(stmt) == SQLITE_DONE: @@ -172,18 +172,18 @@ proc insertID*(db: TDbConn, query: TSqlQuery, proc execAffectedRows*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): int64 {. - tags: [FReadDB, FWriteDb].} = + tags: [FReadDb, FWriteDb].} = ## executes the query (typically "UPDATE") and returns the ## number of affected rows. exec(db, query, args) result = changes(db) -proc close*(db: TDbConn) {.tags: [FDB].} = +proc close*(db: TDbConn) {.tags: [FDb].} = ## closes the database connection. if sqlite3.close(db) != SQLITE_OK: dbError(db) proc open*(connection, user, password, database: string): TDbConn {. - tags: [FDB].} = + tags: [FDb].} = ## opens a database connection. Raises `EDb` if the connection could not ## be established. Only the ``connection`` parameter is used for ``sqlite``. var db: TDbConn diff --git a/lib/impure/dialogs.nim b/lib/impure/dialogs.nim index 00ba2663e..bbed99239 100644 --- a/lib/impure/dialogs.nim +++ b/lib/impure/dialogs.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -8,7 +8,7 @@ # -## This module implements portable dialogs for Nimrod; the implementation +## This module implements portable dialogs for Nim; the implementation ## builds on the GTK interface. On Windows, native dialogs are shown instead. import diff --git a/lib/impure/graphics.nim b/lib/impure/graphics.nim index 2c8e96460..dfadb46ee 100644 --- a/lib/impure/graphics.nim +++ b/lib/impure/graphics.nim @@ -1,20 +1,20 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf, Dominik Picheta # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This module implements graphical output for Nimrod; the current +## This module implements graphical output for Nim; the current ## implementation uses SDL but the interface is meant to support multiple ## backends some day. There is no need to init SDL as this module does that ## implicitly. import colors, math from sdl import PSurface # Bug -from sdl_ttf import OpenFont, closeFont +from sdl_ttf import openFont, closeFont type TRect* = tuple[x, y, width, height: int] @@ -25,24 +25,24 @@ type w*, h*: Natural s*: sdl.PSurface - EGraphics* = object of EIO + EGraphics* = object of IOError TFont {.pure, final.} = object f: sdl_ttf.PFont - color: SDL.TColor + color: sdl.TColor PFont* = ref TFont ## represents a font -proc toSdlColor*(c: TColor): Sdl.TColor = - ## Convert colors.TColor to SDL.TColor +proc toSdlColor*(c: Color): sdl.TColor = + ## Convert colors.TColor to sdl.TColor var x = c.extractRGB result.r = x.r and 0xff result.g = x.g and 0xff result.b = x.b and 0xff -proc createSdlColor*(sur: PSurface, c: TColor, alpha: int = 0): int32 = +proc createSdlColor*(sur: PSurface, c: Color, alpha: int = 0): int32 = ## Creates a color using ``sdl.MapRGBA``. var x = c.extractRGB - return sdl.MapRGBA(sur.s.format, x.r and 0xff, x.g and 0xff, + return sdl.mapRGBA(sur.s.format, x.r and 0xff, x.g and 0xff, x.b and 0xff, alpha and 0xff) proc toSdlRect*(r: TRect): sdl.TRect = @@ -53,7 +53,7 @@ proc toSdlRect*(r: TRect): sdl.TRect = result.h = uint16(r.height) proc raiseEGraphics = - raise newException(EGraphics, $SDL.GetError()) + raise newException(EGraphics, $sdl.getError()) proc surfaceFinalizer(s: PSurface) = sdl.freeSurface(s.s) @@ -62,21 +62,21 @@ proc newSurface*(width, height: int): PSurface = new(result, surfaceFinalizer) result.w = width result.h = height - result.s = SDL.CreateRGBSurface(SDL.SWSURFACE, width, height, + result.s = sdl.createRGBSurface(sdl.SWSURFACE, width, height, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0) if result.s == nil: raiseEGraphics() - assert(not sdl.MustLock(result.s)) + assert(not sdl.mustLock(result.s)) proc fontFinalizer(f: PFont) = closeFont(f.f) proc newFont*(name = "VeraMono.ttf", size = 9, color = colBlack): PFont = ## Creates a new font object. Raises ``EIO`` if the font cannot be loaded. new(result, fontFinalizer) - result.f = OpenFont(name, size.cint) + result.f = openFont(name, size.cint) if result.f == nil: - raise newException(EIO, "Could not open font file: " & name) + raise newException(IOError, "Could not open font file: " & name) result.color = toSdlColor(color) var @@ -92,7 +92,7 @@ proc newScreenSurface*(width, height: int): PSurface = new(result, surfaceFinalizer) result.w = width result.h = height - result.s = SDL.SetVideoMode(width, height, 0, 0) + result.s = sdl.setVideoMode(width, height, 0, 0) if result.s == nil: raiseEGraphics() @@ -100,7 +100,7 @@ proc writeToBMP*(sur: PSurface, filename: string) = ## Saves the contents of the surface `sur` to the file `filename` as a ## BMP file. if sdl.saveBMP(sur.s, filename) != 0: - raise newException(EIO, "cannot write: " & filename) + raise newException(IOError, "cannot write: " & filename) type TPixels = array[0..1000_000-1, int32] @@ -110,44 +110,44 @@ template setPix(video, pitch, x, y, col: expr): stmt = video[y * pitch + x] = int32(col) template getPix(video, pitch, x, y: expr): expr = - colors.TColor(video[y * pitch + x]) + colors.Color(video[y * pitch + x]) const ColSize = 4 -proc getPixel(sur: PSurface, x, y: Natural): colors.TColor {.inline.} = +proc getPixel(sur: PSurface, x, y: Natural): colors.Color {.inline.} = assert x <% sur.w assert y <% sur.h result = getPix(cast[PPixels](sur.s.pixels), sur.s.pitch.int div ColSize, x, y) -proc setPixel(sur: PSurface, x, y: Natural, col: colors.TColor) {.inline.} = +proc setPixel(sur: PSurface, x, y: Natural, col: colors.Color) {.inline.} = assert x <% sur.w assert y <% sur.h var pixs = cast[PPixels](sur.s.pixels) #pixs[y * (sur.s.pitch div colSize) + x] = int(col) setPix(pixs, sur.s.pitch.int div ColSize, x, y, col) -proc `[]`*(sur: PSurface, p: TPoint): TColor = +proc `[]`*(sur: PSurface, p: TPoint): Color = ## get pixel at position `p`. No range checking is done! result = getPixel(sur, p.x, p.y) -proc `[]`*(sur: PSurface, x, y: int): TColor = +proc `[]`*(sur: PSurface, x, y: int): Color = ## get pixel at position ``(x, y)``. No range checking is done! result = getPixel(sur, x, y) -proc `[]=`*(sur: PSurface, p: TPoint, col: TColor) = +proc `[]=`*(sur: PSurface, p: TPoint, col: Color) = ## set the pixel at position `p`. No range checking is done! setPixel(sur, p.x, p.y, col) -proc `[]=`*(sur: PSurface, x, y: int, col: TColor) = +proc `[]=`*(sur: PSurface, x, y: int, col: Color) = ## set the pixel at position ``(x, y)``. No range checking is done! setPixel(sur, x, y, col) proc blit*(destSurf: PSurface, destRect: TRect, srcSurf: PSurface, srcRect: TRect) = ## Copies ``srcSurf`` into ``destSurf`` - var destTRect, srcTRect: SDL.TRect + var destTRect, srcTRect: sdl.TRect destTRect.x = int16(destRect.x) destTRect.y = int16(destRect.y) @@ -159,12 +159,12 @@ proc blit*(destSurf: PSurface, destRect: TRect, srcSurf: PSurface, srcTRect.w = uint16(srcRect.width) srcTRect.h = uint16(srcRect.height) - if SDL.blitSurface(srcSurf.s, addr(srcTRect), destSurf.s, addr(destTRect)) != 0: + if sdl.blitSurface(srcSurf.s, addr(srcTRect), destSurf.s, addr(destTRect)) != 0: raiseEGraphics() proc textBounds*(text: string, font = defaultFont): tuple[width, height: int] = var w, h: cint - if sdl_ttf.SizeUTF8(font.f, text, w, h) < 0: raiseEGraphics() + if sdl_ttf.sizeUTF8(font.f, text, w, h) < 0: raiseEGraphics() result.width = int(w) result.height = int(h) @@ -175,21 +175,21 @@ proc drawText*(sur: PSurface, p: TPoint, text: string, font = defaultFont) = new(textSur, surfaceFinalizer) # Render the text - textSur.s = sdl_ttf.RenderTextBlended(font.f, text, font.color) + textSur.s = sdl_ttf.renderTextBlended(font.f, text, font.color) # Merge the text surface with sur sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h)) proc drawText*(sur: PSurface, p: TPoint, text: string, - bg: TColor, font = defaultFont) = + bg: Color, font = defaultFont) = ## Draws text, at location ``p`` with font ``font``. ``bg`` ## is the background color. var textSur: PSurface # This surface will have the text drawn on it new(textSur, surfaceFinalizer) - textSur.s = sdl_ttf.RenderTextShaded(font.f, text, font.color, toSdlColor(bg)) + textSur.s = sdl_ttf.renderTextShaded(font.f, text, font.color, toSdlColor(bg)) # Merge the text surface with sur sur.blit((p.x, p.y, sur.w, sur.h), textSur, (0, 0, sur.w, sur.h)) -proc drawCircle*(sur: PSurface, p: TPoint, r: Natural, color: TColor) = +proc drawCircle*(sur: PSurface, p: TPoint, r: Natural, color: Color) = ## draws a circle with center `p` and radius `r` with the given color ## onto the surface `sur`. var video = cast[PPixels](sur.s.pixels) @@ -229,7 +229,7 @@ proc `>-<`(val: int, s: PSurface): int {.inline.} = proc `>|<`(val: int, s: PSurface): int {.inline.} = return if val < 0: 0 elif val >= s.h: s.h-1 else: val -proc drawLine*(sur: PSurface, p1, p2: TPoint, color: TColor) = +proc drawLine*(sur: PSurface, p1, p2: TPoint, color: Color) = ## draws a line between the two points `p1` and `p2` with the given color ## onto the surface `sur`. var stepx, stepy: int = 0 @@ -273,7 +273,7 @@ proc drawLine*(sur: PSurface, p1, p2: TPoint, color: TColor) = fraction = fraction + dx setPix(video, pitch, x0, y0, color) -proc drawHorLine*(sur: PSurface, x, y, w: Natural, Color: TColor) = +proc drawHorLine*(sur: PSurface, x, y, w: Natural, color: Color) = ## draws a horizontal line from (x,y) to (x+w-1, y). var video = cast[PPixels](sur.s.pixels) var pitch = sur.s.pitch.int div ColSize @@ -282,7 +282,7 @@ proc drawHorLine*(sur: PSurface, x, y, w: Natural, Color: TColor) = for i in 0 .. min(sur.s.w-x, w)-1: setPix(video, pitch, x + i, y, color) -proc drawVerLine*(sur: PSurface, x, y, h: Natural, Color: TColor) = +proc drawVerLine*(sur: PSurface, x, y, h: Natural, color: Color) = ## draws a vertical line from (x,y) to (x, y+h-1). var video = cast[PPixels](sur.s.pixels) var pitch = sur.s.pitch.int div ColSize @@ -291,7 +291,7 @@ proc drawVerLine*(sur: PSurface, x, y, h: Natural, Color: TColor) = for i in 0 .. min(sur.s.h-y, h)-1: setPix(video, pitch, x, y + i, color) -proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: TColor) = +proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: Color) = ## draws a circle with center `p` and radius `r` with the given color ## onto the surface `sur` and fills it. var a = 1 - r @@ -301,11 +301,11 @@ proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: TColor) = var y = p.y while px <= py: # Fill up the middle half of the circle - DrawVerLine(s, x + px, y, py + 1, color) - DrawVerLine(s, x + px, y - py, py, color) + drawVerLine(s, x + px, y, py + 1, color) + drawVerLine(s, x + px, y - py, py, color) if px != 0: - DrawVerLine(s, x - px, y, py + 1, color) - DrawVerLine(s, x - px, y - py, py, color) + drawVerLine(s, x - px, y, py + 1, color) + drawVerLine(s, x - px, y - py, py, color) if a < 0: a = a + (2 * px + 3) else: @@ -313,13 +313,13 @@ proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: TColor) = py = py - 1 # Fill up the left/right half of the circle if py >= px: - DrawVerLine(s, x + py + 1, y, px + 1, color) - DrawVerLine(s, x + py + 1, y - px, px, color) - DrawVerLine(s, x - py - 1, y, px + 1, color) - DrawVerLine(s, x - py - 1, y - px, px, color) + drawVerLine(s, x + py + 1, y, px + 1, color) + drawVerLine(s, x + py + 1, y - px, px, color) + drawVerLine(s, x - py - 1, y, px + 1, color) + drawVerLine(s, x - py - 1, y - px, px, color) px = px + 1 -proc drawRect*(sur: PSurface, r: TRect, color: TColor) = +proc drawRect*(sur: PSurface, r: TRect, color: Color) = ## draws a rectangle. var video = cast[PPixels](sur.s.pixels) var pitch = sur.s.pitch.int div ColSize @@ -337,78 +337,78 @@ proc drawRect*(sur: PSurface, r: TRect, color: TColor) = setPix(video, pitch, r.x, r.y + i, color) setPix(video, pitch, r.x + minW - 1, r.y + i, color) # Draw right side -proc fillRect*(sur: PSurface, r: TRect, col: TColor) = +proc fillRect*(sur: PSurface, r: TRect, col: Color) = ## Fills a rectangle using sdl's ``FillRect`` function. var rect = toSdlRect(r) - if sdl.FillRect(sur.s, addr(rect), sur.createSdlColor(col)) == -1: + if sdl.fillRect(sur.s, addr(rect), sur.createSdlColor(col)) == -1: raiseEGraphics() -proc plot4EllipsePoints(sur: PSurface, CX, CY, X, Y: Natural, col: TColor) = +proc plot4EllipsePoints(sur: PSurface, cx, cy, x, y: Natural, col: Color) = var video = cast[PPixels](sur.s.pixels) var pitch = sur.s.pitch.int div ColSize - if CX+X <= sur.s.w-1: - if CY+Y <= sur.s.h-1: setPix(video, pitch, CX+X, CY+Y, col) - if CY-Y <= sur.s.h-1: setPix(video, pitch, CX+X, CY-Y, col) - if CX-X <= sur.s.w-1: - if CY+Y <= sur.s.h-1: setPix(video, pitch, CX-X, CY+Y, col) - if CY-Y <= sur.s.h-1: setPix(video, pitch, CX-X, CY-Y, col) - -proc drawEllipse*(sur: PSurface, CX, CY, XRadius, YRadius: Natural, - col: TColor) = + if cx+x <= sur.s.w-1: + if cy+y <= sur.s.h-1: setPix(video, pitch, cx+x, cy+y, col) + if cy-y <= sur.s.h-1: setPix(video, pitch, cx+x, cy-y, col) + if cx-x <= sur.s.w-1: + if cy+y <= sur.s.h-1: setPix(video, pitch, cx-x, cy+y, col) + if cy-y <= sur.s.h-1: setPix(video, pitch, cx-x, cy-y, col) + +proc drawEllipse*(sur: PSurface, cx, cy, xRadius, yRadius: Natural, + col: Color) = ## Draws an ellipse, ``CX`` and ``CY`` specify the center X and Y of the ## ellipse, ``XRadius`` and ``YRadius`` specify half the width and height ## of the ellipse. var - X, Y: Natural - XChange, YChange: Int - EllipseError: Natural - TwoASquare, TwoBSquare: Natural - StoppingX, StoppingY: Natural + x, y: Natural + xChange, yChange: int + ellipseError: Natural + twoASquare, twoBSquare: Natural + stoppingX, stoppingY: Natural - TwoASquare = 2 * XRadius * XRadius - TwoBSquare = 2 * YRadius * YRadius - X = XRadius - Y = 0 - XChange = YRadius * YRadius * (1 - 2 * XRadius) - YChange = XRadius * XRadius - EllipseError = 0 - StoppingX = TwoBSquare * XRadius - StoppingY = 0 + twoASquare = 2 * xRadius * xRadius + twoBSquare = 2 * yRadius * yRadius + x = xRadius + y = 0 + xChange = yRadius * yRadius * (1 - 2 * xRadius) + yChange = xRadius * xRadius + ellipseError = 0 + stoppingX = twoBSquare * xRadius + stoppingY = 0 - while StoppingX >= StoppingY: # 1st set of points, y` > - 1 - sur.Plot4EllipsePoints(CX, CY, X, Y, col) - inc(Y) - inc(StoppingY, TwoASquare) - inc(EllipseError, YChange) - inc(YChange, TwoASquare) - if (2 * EllipseError + XChange) > 0 : + while stoppingX >= stoppingY: # 1st set of points, y` > - 1 + sur.plot4EllipsePoints(cx, cy, x, y, col) + inc(y) + inc(stoppingY, twoASquare) + inc(ellipseError, yChange) + inc(yChange, twoASquare) + if (2 * ellipseError + xChange) > 0 : dec(x) - dec(StoppingX, TwoBSquare) - inc(EllipseError, XChange) - inc(XChange, TwoBSquare) + dec(stoppingX, twoBSquare) + inc(ellipseError, xChange) + inc(xChange, twoBSquare) # 1st point set is done; start the 2nd set of points - X = 0 - Y = YRadius - XChange = YRadius * YRadius - YChange = XRadius * XRadius * (1 - 2 * YRadius) - EllipseError = 0 - StoppingX = 0 - StoppingY = TwoASquare * YRadius - while StoppingX <= StoppingY: - sur.Plot4EllipsePoints(CX, CY, X, Y, col) - inc(X) - inc(StoppingX, TwoBSquare) - inc(EllipseError, XChange) - inc(XChange,TwoBSquare) - if (2 * EllipseError + YChange) > 0: - dec(Y) - dec(StoppingY, TwoASquare) - inc(EllipseError, YChange) - inc(YChange,TwoASquare) + x = 0 + y = yRadius + xChange = yRadius * yRadius + yChange = xRadius * xRadius * (1 - 2 * yRadius) + ellipseError = 0 + stoppingX = 0 + stoppingY = twoASquare * yRadius + while stoppingX <= stoppingY: + sur.plot4EllipsePoints(cx, cy, x, y, col) + inc(x) + inc(stoppingX, twoBSquare) + inc(ellipseError, xChange) + inc(xChange,twoBSquare) + if (2 * ellipseError + yChange) > 0: + dec(y) + dec(stoppingY, twoASquare) + inc(ellipseError, yChange) + inc(yChange,twoASquare) -proc plotAA(sur: PSurface, x, y: int, c: float, color: TColor) = +proc plotAA(sur: PSurface, x, y: int, c: float, color: Color) = if (x > 0 and x < sur.s.w) and (y > 0 and y < sur.s.h): var video = cast[PPixels](sur.s.pixels) var pitch = sur.s.pitch.int div ColSize @@ -424,7 +424,7 @@ template cround(x: expr): expr = ipart(x + 0.5) template fpart(x: expr): expr = x - ipart(x) template rfpart(x: expr): expr = 1.0 - fpart(x) -proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: TColor) = +proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: Color) = ## Draws a anti-aliased line from ``p1`` to ``p2``, using Xiaolin Wu's ## line algorithm var (x1, x2, y1, y2) = (p1.x.toFloat(), p2.x.toFloat(), @@ -444,11 +444,11 @@ proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: TColor) = swap(x2, y2) swap(dx, dy) - template doPlot(x, y: int, c: float, color: TColor): stmt = + template doPlot(x, y: int, c: float, color: Color): stmt = if ax < ay: - sur.PlotAA(y, x, c, color) + sur.plotAA(y, x, c, color) else: - sur.PlotAA(x, y, c, color) + sur.plotAA(x, y, c, color) if x2 < x1: swap(x1, x2) @@ -482,22 +482,22 @@ proc drawLineAA*(sur: PSurface, p1, p2: TPoint, color: TColor) = intery = intery + gradient inc(x) -proc fillSurface*(sur: PSurface, color: TColor) = +proc fillSurface*(sur: PSurface, color: Color) = ## Fills the entire surface with ``color``. - if sdl.FillRect(sur.s, nil, sur.createSdlColor(color)) == -1: + if sdl.fillRect(sur.s, nil, sur.createSdlColor(color)) == -1: raiseEGraphics() template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {. immediate.} = ## Simple template which creates an event loop. ``Event`` is the name of the ## variable containing the TEvent object. - while True: - var event: SDL.TEvent - if SDL.WaitEvent(addr(event)) == 1: + while true: + var event: sdl.TEvent + if sdl.waitEvent(addr(event)) == 1: actions -if sdl.Init(sdl.INIT_VIDEO) < 0: raiseEGraphics() -if sdl_ttf.Init() < 0: raiseEGraphics() +if sdl.init(sdl.INIT_VIDEO) < 0: raiseEGraphics() +if sdl_ttf.init() < 0: raiseEGraphics() when isMainModule: var surf = newScreenSurface(800, 600) @@ -539,19 +539,19 @@ when isMainModule: withEvents(surf, event): var eventp = addr(event) case event.kind: - of SDL.QUITEV: + of sdl.QUITEV: break - of SDL.KEYDOWN: - var evk = sdl.EvKeyboard(eventp) - if evk.keysym.sym == SDL.K_LEFT: + of sdl.KEYDOWN: + var evk = sdl.evKeyboard(eventp) + if evk.keysym.sym == sdl.K_LEFT: surf.drawHorLine(395, 300, 50, colBlack) echo("Drawing") - elif evk.keysym.sym == SDL.K_ESCAPE: + elif evk.keysym.sym == sdl.K_ESCAPE: break else: echo(evk.keysym.sym) - of SDL.MOUSEBUTTONDOWN: - var mbd = sdl.EvMouseButton(eventp) + of sdl.MOUSEBUTTONDOWN: + var mbd = sdl.evMouseButton(eventp) if mouseStartX == -1 or mouseStartY == -1: mouseStartX = int(mbd.x) mouseStartY = int(mbd.y) @@ -560,16 +560,16 @@ when isMainModule: mouseStartX = -1 mouseStartY = -1 - of SDL.MouseMotion: - var mm = sdl.EvMouseMotion(eventp) + of sdl.MOUSEMOTION: + var mm = sdl.evMouseMotion(eventp) if mouseStartX != -1 and mouseStartY != -1: surf.drawLineAA((mouseStartX, mouseStartY), (int(mm.x), int(mm.y)), colPurple) #echo(mm.x, " ", mm.y, " ", mm.yrel) else: - #echo(event.kind) + discard "echo(event.kind)" - SDL.UpdateRect(surf.s, 0, 0, 800, 600) + sdl.updateRect(surf.s, 0, 0, 800, 600) surf.writeToBMP("test.bmp") - SDL.Quit() + sdl.quit() diff --git a/lib/impure/osinfo_posix.nim b/lib/impure/osinfo_posix.nim index 4fde82012..1baff8c55 100644 --- a/lib/impure/osinfo_posix.nim +++ b/lib/impure/osinfo_posix.nim @@ -1,20 +1,21 @@ import posix, strutils, os -type - Tstatfs {.importc: "struct statfs64", - header: "<sys/statfs.h>", final, pure.} = object - f_type: int - f_bsize: int - f_blocks: int - f_bfree: int - f_bavail: int - f_files: int - f_ffree: int - f_fsid: int - f_namelen: int +when false: + type + Tstatfs {.importc: "struct statfs64", + header: "<sys/statfs.h>", final, pure.} = object + f_type: int + f_bsize: int + f_blocks: int + f_bfree: int + f_bavail: int + f_files: int + f_ffree: int + f_fsid: int + f_namelen: int -proc statfs(path: string, buf: var Tstatfs): int {. - importc, header: "<sys/vfs.h>".} + proc statfs(path: string, buf: var Tstatfs): int {. + importc, header: "<sys/vfs.h>".} proc getSystemVersion*(): string = @@ -23,7 +24,7 @@ proc getSystemVersion*(): string = var unix_info: TUtsname if uname(unix_info) != 0: - os.OSError() + os.raiseOSError(osLastError()) if $unix_info.sysname == "Linux": # Linux diff --git a/lib/impure/osinfo_win.nim b/lib/impure/osinfo_win.nim index 572e50273..f423a34a3 100644 --- a/lib/impure/osinfo_win.nim +++ b/lib/impure/osinfo_win.nim @@ -375,7 +375,7 @@ proc getFileSize*(file: string): BiggestInt = var hFile = findFirstFileA(file, fileData) if hFile == INVALID_HANDLE_VALUE: - raise newException(EIO, $getLastError()) + raise newException(IOError, $getLastError()) return fileData.nFileSizeLow @@ -386,10 +386,10 @@ proc getDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller, proc getPartitionInfo*(partition: string): TPartitionInfo = ## Retrieves partition info, for example ``partition`` may be ``"C:\"`` - var FreeBytes, TotalBytes, TotalFreeBytes: TFiletime - var res = getDiskFreeSpaceEx(r"C:\", FreeBytes, TotalBytes, - TotalFreeBytes) - return (FreeBytes, TotalBytes) + var freeBytes, totalBytes, totalFreeBytes: TFiletime + discard getDiskFreeSpaceEx(r"C:\", freeBytes, totalBytes, + totalFreeBytes) + return (freeBytes, totalBytes) when isMainModule: var r = getMemoryInfo() diff --git a/lib/impure/rdstdin.nim b/lib/impure/rdstdin.nim index 1037d3bda..07ef13fd9 100644 --- a/lib/impure/rdstdin.nim +++ b/lib/impure/rdstdin.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -15,13 +15,13 @@ when defined(Windows): proc readLineFromStdin*(prompt: string): TaintedString {. - tags: [FReadIO, FWriteIO].} = + tags: [ReadIOEffect, WriteIOEffect].} = ## Reads a line from stdin. stdout.write(prompt) result = readLine(stdin) proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {. - tags: [FReadIO, FWriteIO].} = + tags: [ReadIOEffect, WriteIOEffect].} = ## Reads a `line` from stdin. `line` must not be ## ``nil``! May throw an IO exception. ## A line of text may be delimited by ``CR``, ``LF`` or @@ -35,7 +35,7 @@ else: import readline, history proc readLineFromStdin*(prompt: string): TaintedString {. - tags: [FReadIO, FWriteIO].} = + tags: [ReadIOEffect, WriteIOEffect].} = var buffer = readline.readLine(prompt) if isNil(buffer): quit(0) result = TaintedString($buffer) @@ -44,7 +44,7 @@ else: readline.free(buffer) proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {. - tags: [FReadIO, FWriteIO].} = + tags: [ReadIOEffect, WriteIOEffect].} = var buffer = readline.readLine(prompt) if isNil(buffer): quit(0) line = TaintedString($buffer) diff --git a/lib/impure/re.nim b/lib/impure/re.nim index ac07b2d6b..fc9ed3ce0 100644 --- a/lib/impure/re.nim +++ b/lib/impure/re.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Regular expression support for Nimrod. Consider using the pegs module +## Regular expression support for Nim. Consider using the pegs module ## instead. ## This module is implemented by providing a wrapper around the ## `PRCE (Perl-Compatible Regular Expressions) <http://www.pcre.org>`_ @@ -28,7 +28,7 @@ const ## More subpatterns cannot be captured! type - TRegexFlag* = enum ## options for regular expressions + RegexFlag* = enum ## options for regular expressions reIgnoreCase = 0, ## do caseless matching reMultiLine = 1, ## ``^`` and ``$`` match newlines within data reDotAll = 2, ## ``.`` matches anything including NL @@ -36,17 +36,20 @@ type reStudy = 4 ## study the expression (may be omitted if the ## expression will be used only once) - TRegexDesc {.pure, final.} = object + RegexDesc = object h: PPcre e: ptr TExtra - TRegex* = ref TRegexDesc ## a compiled regular expression + Regex* = ref RegexDesc ## a compiled regular expression - EInvalidRegEx* = object of EInvalidValue + RegexError* = object of ValueError ## is raised if the pattern is no valid regular expression. +{.deprecated: [TRegexFlag: RegexFlag, TRegexDesc: RegexDesc, TRegex: Regex, + EInvalidRegEx: RegexError].} + proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} = - var e: ref EInvalidRegEx + var e: ref RegexError new(e) e.msg = msg raise e @@ -55,11 +58,11 @@ proc rawCompile(pattern: string, flags: cint): PPcre = var msg: cstring offset: cint - result = pcre.Compile(pattern, flags, addr(msg), addr(offset), nil) + result = pcre.compile(pattern, flags, addr(msg), addr(offset), nil) if result == nil: raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n") -proc finalizeRegEx(x: TRegex) = +proc finalizeRegEx(x: Regex) = # XXX This is a hack, but PCRE does not export its "free" function properly. # Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``). # Fortunately the implementation is unlikely to change. @@ -67,8 +70,8 @@ proc finalizeRegEx(x: TRegex) = if not isNil(x.e): pcre.free_substring(cast[cstring](x.e)) -proc re*(s: string, flags = {reExtended, reStudy}): TRegex = - ## Constructor of regular expressions. Note that Nimrod's +proc re*(s: string, flags = {reExtended, reStudy}): Regex = + ## Constructor of regular expressions. Note that Nim's ## extended raw string literals support this syntax ``re"[abc]"`` as ## a short form for ``re(r"[abc]")``. new(result, finalizeRegEx) @@ -78,12 +81,12 @@ proc re*(s: string, flags = {reExtended, reStudy}): TRegex = result.e = pcre.study(result.h, 0, msg) if not isNil(msg): raiseInvalidRegex($msg) -proc matchOrFind(s: string, pattern: TRegex, matches: var openArray[string], +proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string], start, flags: cint): cint = var - rawMatches: array[0..maxSubpatterns * 3 - 1, cint] - res = pcre.Exec(pattern.h, pattern.e, s, len(s).cint, start, flags, - cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3) + rawMatches: array[0..MaxSubpatterns * 3 - 1, cint] + res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start, flags, + cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3) if res < 0'i32: return res for i in 1..int(res)-1: var a = rawMatches[i * 2] @@ -92,16 +95,16 @@ proc matchOrFind(s: string, pattern: TRegex, matches: var openArray[string], else: matches[i-1] = "" return rawMatches[1] - rawMatches[0] -proc findBounds*(s: string, pattern: TRegex, matches: var openArray[string], +proc findBounds*(s: string, pattern: Regex, matches: var openArray[string], start = 0): tuple[first, last: int] = ## returns the starting position and end position of `pattern` in `s` ## and the captured ## substrings in the array `matches`. If it does not match, nothing ## is written into `matches` and ``(-1,0)`` is returned. var - rawMatches: array[0..maxSubpatterns * 3 - 1, cint] - res = pcre.Exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32, - cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3) + rawMatches: array[0..MaxSubpatterns * 3 - 1, cint] + res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32, + cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3) if res < 0'i32: return (-1, 0) for i in 1..int(res)-1: var a = rawMatches[i * 2] @@ -110,7 +113,7 @@ proc findBounds*(s: string, pattern: TRegex, matches: var openArray[string], else: matches[i-1] = "" return (rawMatches[0].int, rawMatches[1].int - 1) -proc findBounds*(s: string, pattern: TRegex, +proc findBounds*(s: string, pattern: Regex, matches: var openArray[tuple[first, last: int]], start = 0): tuple[first, last: int] = ## returns the starting position and end position of ``pattern`` in ``s`` @@ -118,9 +121,9 @@ proc findBounds*(s: string, pattern: TRegex, ## If it does not match, nothing is written into `matches` and ## ``(-1,0)`` is returned. var - rawMatches: array[0..maxSubpatterns * 3 - 1, cint] - res = pcre.Exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32, - cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3) + rawMatches: array[0..MaxSubpatterns * 3 - 1, cint] + res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32, + cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3) if res < 0'i32: return (-1, 0) for i in 1..int(res)-1: var a = rawMatches[i * 2] @@ -129,25 +132,25 @@ proc findBounds*(s: string, pattern: TRegex, else: matches[i-1] = (-1,0) return (rawMatches[0].int, rawMatches[1].int - 1) -proc findBounds*(s: string, pattern: TRegex, +proc findBounds*(s: string, pattern: Regex, start = 0): tuple[first, last: int] = ## returns the starting position of `pattern` in `s`. If it does not ## match, ``(-1,0)`` is returned. var rawMatches: array[0..3 - 1, cint] - res = pcre.Exec(pattern.h, nil, s, len(s).cint, start.cint, 0'i32, + res = pcre.exec(pattern.h, nil, s, len(s).cint, start.cint, 0'i32, cast[ptr cint](addr(rawMatches)), 3) if res < 0'i32: return (int(res), 0) return (int(rawMatches[0]), int(rawMatches[1]-1)) -proc matchOrFind(s: string, pattern: TRegex, start, flags: cint): cint = - var rawMatches: array [0..maxSubpatterns * 3 - 1, cint] - result = pcre.Exec(pattern.h, pattern.e, s, len(s).cint, start, flags, - cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3) +proc matchOrFind(s: string, pattern: Regex, start, flags: cint): cint = + var rawMatches: array [0..MaxSubpatterns * 3 - 1, cint] + result = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start, flags, + cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3) if result >= 0'i32: result = rawMatches[1] - rawMatches[0] -proc match*(s: string, pattern: TRegex, matches: var openArray[string], +proc match*(s: string, pattern: Regex, matches: var openArray[string], start = 0): bool = ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and ## the captured substrings in the array ``matches``. If it does not @@ -156,32 +159,32 @@ proc match*(s: string, pattern: TRegex, matches: var openArray[string], return matchOrFind(s, pattern, matches, start.cint, pcre.ANCHORED) == cint(s.len - start) -proc match*(s: string, pattern: TRegex, start = 0): bool = +proc match*(s: string, pattern: Regex, start = 0): bool = ## returns ``true`` if ``s[start..]`` matches the ``pattern``. return matchOrFind(s, pattern, start.cint, pcre.ANCHORED) == cint(s.len-start) -proc matchLen*(s: string, pattern: TRegex, matches: var openArray[string], +proc matchLen*(s: string, pattern: Regex, matches: var openArray[string], start = 0): int = ## the same as ``match``, but it returns the length of the match, ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. return matchOrFind(s, pattern, matches, start.cint, pcre.ANCHORED) -proc matchLen*(s: string, pattern: TRegex, start = 0): int = +proc matchLen*(s: string, pattern: Regex, start = 0): int = ## the same as ``match``, but it returns the length of the match, ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. return matchOrFind(s, pattern, start.cint, pcre.ANCHORED) -proc find*(s: string, pattern: TRegex, matches: var openArray[string], +proc find*(s: string, pattern: Regex, matches: var openArray[string], start = 0): int = ## returns the starting position of ``pattern`` in ``s`` and the captured ## substrings in the array ``matches``. If it does not match, nothing ## is written into ``matches`` and -1 is returned. var - rawMatches: array[0..maxSubpatterns * 3 - 1, cint] - res = pcre.Exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32, - cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3) + rawMatches: array[0..MaxSubpatterns * 3 - 1, cint] + res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, start.cint, 0'i32, + cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3) if res < 0'i32: return res for i in 1..int(res)-1: var a = rawMatches[i * 2] @@ -190,33 +193,33 @@ proc find*(s: string, pattern: TRegex, matches: var openArray[string], else: matches[i-1] = "" return rawMatches[0] -proc find*(s: string, pattern: TRegex, start = 0): int = +proc find*(s: string, pattern: Regex, start = 0): int = ## returns the starting position of ``pattern`` in ``s``. If it does not ## match, -1 is returned. var rawMatches: array[0..3 - 1, cint] - res = pcre.Exec(pattern.h, nil, s, len(s).cint, start.cint, 0'i32, + res = pcre.exec(pattern.h, nil, s, len(s).cint, start.cint, 0'i32, cast[ptr cint](addr(rawMatches)), 3) if res < 0'i32: return res return rawMatches[0] -iterator findAll*(s: string, pattern: TRegex, start = 0): string = +iterator findAll*(s: string, pattern: Regex, start = 0): string = ## Yields all matching *substrings* of `s` that match `pattern`. ## ## Note that since this is an iterator you should not modify the string you ## are iterating over: bad things could happen. var i = int32(start) - var rawMatches: array[0..maxSubpatterns * 3 - 1, cint] + var rawMatches: array[0..MaxSubpatterns * 3 - 1, cint] while true: - let res = pcre.Exec(pattern.h, pattern.e, s, len(s).cint, i, 0'i32, - cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3) + let res = pcre.exec(pattern.h, pattern.e, s, len(s).cint, i, 0'i32, + cast[ptr cint](addr(rawMatches)), MaxSubpatterns * 3) if res < 0'i32: break let a = rawMatches[0] let b = rawMatches[1] yield substr(s, int(a), int(b)-1) i = b -proc findAll*(s: string, pattern: TRegex, start = 0): seq[string] = +proc findAll*(s: string, pattern: Regex, start = 0): seq[string] = ## returns all matching *substrings* of `s` that match `pattern`. ## If it does not match, @[] is returned. accumulateResult(findAll(s, pattern, start)) @@ -224,11 +227,11 @@ proc findAll*(s: string, pattern: TRegex, start = 0): seq[string] = when not defined(nimhygiene): {.pragma: inject.} -template `=~` *(s: string, pattern: TRegex): expr = +template `=~` *(s: string, pattern: Regex): expr = ## This calls ``match`` with an implicit declared ``matches`` array that ## can be used in the scope of the ``=~`` call: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## if line =~ re"\s*(\w+)\s*\=\s*(\w+)": ## # matches a key=value pair: @@ -242,41 +245,41 @@ template `=~` *(s: string, pattern: TRegex): expr = ## else: ## echo("syntax error") ## - bind maxSubPatterns + bind MaxSubPatterns when not declaredInScope(matches): var matches {.inject.}: array[0..MaxSubpatterns-1, string] match(s, pattern, matches) # ------------------------- more string handling ------------------------------ -proc contains*(s: string, pattern: TRegex, start = 0): bool = +proc contains*(s: string, pattern: Regex, start = 0): bool = ## same as ``find(s, pattern, start) >= 0`` return find(s, pattern, start) >= 0 -proc contains*(s: string, pattern: TRegex, matches: var openArray[string], +proc contains*(s: string, pattern: Regex, matches: var openArray[string], start = 0): bool = ## same as ``find(s, pattern, matches, start) >= 0`` return find(s, pattern, matches, start) >= 0 -proc startsWith*(s: string, prefix: TRegex): bool = +proc startsWith*(s: string, prefix: Regex): bool = ## returns true if `s` starts with the pattern `prefix` result = matchLen(s, prefix) >= 0 -proc endsWith*(s: string, suffix: TRegex): bool = +proc endsWith*(s: string, suffix: Regex): bool = ## returns true if `s` ends with the pattern `prefix` for i in 0 .. s.len-1: if matchLen(s, suffix, i) == s.len - i: return true -proc replace*(s: string, sub: TRegex, by = ""): string = +proc replace*(s: string, sub: Regex, by = ""): string = ## Replaces `sub` in `s` by the string `by`. Captures cannot be ## accessed in `by`. Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "var1=key; var2=key2".replace(re"(\w+)'='(\w+)") ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## "; " result = "" @@ -289,20 +292,20 @@ proc replace*(s: string, sub: TRegex, by = ""): string = prev = match.last + 1 add(result, substr(s, prev)) -proc replacef*(s: string, sub: TRegex, by: string): string = +proc replacef*(s: string, sub: Regex, by: string): string = ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "var1=key; var2=key2".replacef(re"(\w+)'='(\w+)", "$1<-$2$2") ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## "var1<-keykey; val2<-key2key2" result = "" - var caps: array[0..maxSubpatterns-1, string] + var caps: array[0..MaxSubpatterns-1, string] var prev = 0 while true: var match = findBounds(s, sub, caps, prev) @@ -314,7 +317,7 @@ proc replacef*(s: string, sub: TRegex, by: string): string = when false: result = "" var i = 0 - var caps: array[0..maxSubpatterns-1, string] + var caps: array[0..MaxSubpatterns-1, string] while i < s.len: var x = matchLen(s, sub, caps, i) if x <= 0: @@ -327,12 +330,12 @@ proc replacef*(s: string, sub: TRegex, by: string): string = add(result, substr(s, i)) proc parallelReplace*(s: string, subs: openArray[ - tuple[pattern: TRegex, repl: string]]): string = + tuple[pattern: Regex, repl: string]]): string = ## Returns a modified copy of `s` with the substitutions in `subs` ## applied in parallel. result = "" var i = 0 - var caps: array[0..maxSubpatterns-1, string] + var caps: array[0..MaxSubpatterns-1, string] while i < s.len: block searchSubs: for j in 0..high(subs): @@ -347,26 +350,26 @@ proc parallelReplace*(s: string, subs: openArray[ add(result, substr(s, i)) proc transformFile*(infile, outfile: string, - subs: openArray[tuple[pattern: TRegex, repl: string]]) = + subs: openArray[tuple[pattern: Regex, repl: string]]) = ## reads in the file `infile`, performs a parallel replacement (calls ## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an ## error occurs. This is supposed to be used for quick scripting. var x = readFile(infile).string writeFile(outfile, x.parallelReplace(subs)) -iterator split*(s: string, sep: TRegex): string = +iterator split*(s: string, sep: Regex): string = ## Splits the string `s` into substrings. ## ## Substrings are separated by the regular expression `sep`. ## Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for word in split("00232this02939is39an22example111", re"\d+"): ## writeln(stdout, word) ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "this" ## "is" ## "an" @@ -386,7 +389,7 @@ iterator split*(s: string, sep: TRegex): string = if first < last: yield substr(s, first, last-1) -proc split*(s: string, sep: TRegex): seq[string] = +proc split*(s: string, sep: Regex): seq[string] = ## Splits the string `s` into substrings. accumulateResult(split(s, sep)) diff --git a/lib/impure/ssl.nim b/lib/impure/ssl.nim index 54d524c7b..bb7cfc0d3 100644 --- a/lib/impure/ssl.nim +++ b/lib/impure/ssl.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Dominik Picheta # # See the file "copying.txt", included in this @@ -8,31 +8,31 @@ # ## This module provides an easy to use sockets-style -## nimrod interface to the OpenSSL library. +## nim interface to the OpenSSL library. {.deprecated.} import openssl, strutils, os type - TSecureSocket* {.final.} = object - ssl: PSSL - bio: PBIO + TSecureSocket* = object + ssl: SslPtr + bio: BIO proc connect*(sock: var TSecureSocket, address: string, - port: int): Int = + port: int): int = ## Connects to the specified `address` on the specified `port`. ## Returns the result of the certificate validation. SslLoadErrorStrings() ERR_load_BIO_strings() if SSL_library_init() != 1: - OSError() + raiseOSError(osLastError()) var ctx = SSL_CTX_new(SSLv23_client_method()) if ctx == nil: ERR_print_errors_fp(stderr) - OSError() + raiseOSError(osLastError()) #if SSL_CTX_load_verify_locations(ctx, # "/tmp/openssl-0.9.8e/certs/vsign1.pem", NIL) == 0: @@ -41,14 +41,14 @@ proc connect*(sock: var TSecureSocket, address: string, sock.bio = BIO_new_ssl_connect(ctx) if BIO_get_ssl(sock.bio, addr(sock.ssl)) == 0: - OSError() + raiseOSError(osLastError()) if BIO_set_conn_hostname(sock.bio, address & ":" & $port) != 1: - OSError() + raiseOSError(osLastError()) if BIO_do_connect(sock.bio) <= 0: ERR_print_errors_fp(stderr) - OSError() + raiseOSError(osLastError()) result = SSL_get_verify_result(sock.ssl) @@ -57,30 +57,30 @@ proc recvLine*(sock: TSecureSocket, line: var TaintedString): bool = ## Returns false when no data is available to be read. ## `Line` must be initialized and not nil! setLen(line.string, 0) - while True: + while true: var c: array[0..0, char] var n = BIO_read(sock.bio, c, c.len.cint) - if n <= 0: return False + if n <= 0: return false if c[0] == '\r': n = BIO_read(sock.bio, c, c.len.cint) if n > 0 and c[0] == '\L': - return True + return true elif n <= 0: - return False - elif c[0] == '\L': return True + return false + elif c[0] == '\L': return true add(line.string, c) proc send*(sock: TSecureSocket, data: string) = ## Writes `data` to the socket. if BIO_write(sock.bio, data, data.len.cint) <= 0: - OSError() + raiseOSError(osLastError()) proc close*(sock: TSecureSocket) = ## Closes the socket if BIO_free(sock.bio) <= 0: ERR_print_errors_fp(stderr) - OSError() + raiseOSError(osLastError()) when isMainModule: var s: TSecureSocket diff --git a/lib/impure/web.nim b/lib/impure/web.nim deleted file mode 100644 index 5f04422d1..000000000 --- a/lib/impure/web.nim +++ /dev/null @@ -1,63 +0,0 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module contains simple high-level procedures for dealing with the -## web. Use cases: -## -## * requesting URLs -## * sending and retrieving emails -## * sending and retrieving files from an FTP server -## -## Currently only requesting URLs is implemented. The implementation depends -## on the libcurl library! -## -## **Deprecated since version 0.8.8:** Use the -## `httpclient <httpclient.html>`_ module instead. -## - -{.deprecated.} - -import libcurl, streams - -proc curlwrapperWrite(p: pointer, size, nmemb: int, - data: pointer): int {.cdecl.} = - var stream = cast[PStream](data) - stream.writeData(p, size*nmemb) - return size*nmemb - -proc URLretrieveStream*(url: string): PStream = - ## retrieves the given `url` and returns a stream which one can read from to - ## obtain the contents. Returns nil if an error occurs. - result = newStringStream() - var hCurl = easy_init() - if hCurl == nil: return nil - if easy_setopt(hCurl, OPT_URL, url) != E_OK: return nil - if easy_setopt(hCurl, OPT_WRITEFUNCTION, - curlwrapperWrite) != E_OK: return nil - if easy_setopt(hCurl, OPT_WRITEDATA, result) != E_OK: return nil - if easy_perform(hCurl) != E_OK: return nil - easy_cleanup(hCurl) - -proc URLretrieveString*(url: string): TaintedString = - ## retrieves the given `url` and returns the contents. Returns nil if an - ## error occurs. - var stream = newStringStream() - var hCurl = easy_init() - if hCurl == nil: return - if easy_setopt(hCurl, OPT_URL, url) != E_OK: return - if easy_setopt(hCurl, OPT_WRITEFUNCTION, - curlwrapperWrite) != E_OK: return - if easy_setopt(hCurl, OPT_WRITEDATA, stream) != E_OK: return - if easy_perform(hCurl) != E_OK: return - easy_cleanup(hCurl) - result = stream.data.TaintedString - -when isMainModule: - echo URLretrieveString("http://nimrod-code.org/") - diff --git a/lib/impure/zipfiles.nim b/lib/impure/zipfiles.nim index 1726449d8..fb687e6f1 100644 --- a/lib/impure/zipfiles.nim +++ b/lib/impure/zipfiles.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,18 +13,18 @@ import streams, libzip, times, os type - TZipArchive* = object of TObject ## represents a zip archive - mode: TFileMode + TZipArchive* = object of RootObj ## represents a zip archive + mode: FileMode w: PZip proc zipError(z: var TZipArchive) = - var e: ref EIO + var e: ref IOError new(e) e.msg = $zip_strerror(z.w) raise e -proc open*(z: var TZipArchive, filename: string, mode: TFileMode = fmRead): bool = +proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool = ## Opens a zip file for reading, writing or appending. All file modes are ## supported. Returns true iff successful, false otherwise. var err, flags: int32 @@ -72,7 +72,7 @@ proc addFile*(z: var TZipArchive, file: string) = proc mySourceCallback(state, data: pointer, len: int, cmd: TZipSourceCmd): int {.cdecl.} = - var src = cast[PStream](state) + var src = cast[Stream](state) case cmd of ZIP_SOURCE_OPEN: if src.setPositionImpl != nil: setPosition(src, 0) # reset @@ -93,7 +93,7 @@ proc mySourceCallback(state, data: pointer, len: int, of constZIP_SOURCE_FREE: GC_unref(src) else: assert(false) -proc addFile*(z: var TZipArchive, dest: string, src: PStream) = +proc addFile*(z: var TZipArchive, dest: string, src: Stream) = ## Adds a file named with `dest` to the archive `z`. `dest` ## may contain a path. The file's content is read from the `src` stream. assert(z.mode != fmRead) @@ -107,14 +107,14 @@ proc addFile*(z: var TZipArchive, dest: string, src: PStream) = # -------------- zip file stream --------------------------------------------- type - TZipFileStream = object of TStream + TZipFileStream = object of StreamObj f: PZipFile PZipFileStream* = ref TZipFileStream ## a reader stream of a file within a zip archive -proc fsClose(s: PStream) = zip_fclose(PZipFileStream(s).f) -proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int = +proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f) +proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = result = zip_fread(PZipFileStream(s).f, buffer, bufLen) proc newZipFileStream(f: PZipFile): PZipFileStream = @@ -144,7 +144,7 @@ iterator walkFiles*(z: var TZipArchive): string = inc(i) -proc extractFile*(z: var TZipArchive, srcFile: string, dest: PStream) = +proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) = ## extracts a file from the zip archive `z` to the destination stream. var strm = getStream(z, srcFile) while true: diff --git a/lib/js/dom.nim b/lib/js/dom.nim index 951d8e835..b07666dd1 100644 --- a/lib/js/dom.nim +++ b/lib/js/dom.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -446,7 +446,7 @@ proc unescape*(uri: cstring): cstring {.importc, nodecl.} proc decodeURIComponent*(uri: cstring): cstring {.importc, nodecl.} proc encodeURIComponent*(uri: cstring): cstring {.importc, nodecl.} -proc isFinite*(x: biggestFloat): bool {.importc, nodecl.} -proc isNaN*(x: biggestFloat): bool {.importc, nodecl.} -proc parseFloat*(s: cstring): biggestFloat {.importc, nodecl.} +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.} diff --git a/lib/nimbase.h b/lib/nimbase.h index b43094227..ac90081d8 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -1,7 +1,7 @@ /* - Nimrod's Runtime Library - (c) Copyright 2013 Andreas Rumpf + Nim's Runtime Library + (c) Copyright 2014 Andreas Rumpf See the file "copying.txt", included in this distribution, for details about the copyright. @@ -141,9 +141,11 @@ __clang__ /* these compilers have a fastcall so use it: */ # define N_NIMCALL(rettype, name) rettype __fastcall name # define N_NIMCALL_PTR(rettype, name) rettype (__fastcall *name) +# define N_RAW_NIMCALL __fastcall #else # define N_NIMCALL(rettype, name) rettype name /* no modifier */ # define N_NIMCALL_PTR(rettype, name) rettype (*name) +# define N_RAW_NIMCALL #endif #define N_CLOSURE(rettype, name) N_NIMCALL(rettype, name) @@ -175,9 +177,9 @@ __clang__ # define NIM_NIL 0 struct NimException { - NimException(struct E_Base* exp, const char* msg): exp(exp), msg(msg) {} + NimException(struct Exception* exp, const char* msg): exp(exp), msg(msg) {} - struct E_Base* exp; + struct Exception* exp; const char* msg; }; #else @@ -382,3 +384,9 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); } "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]; #endif + +#ifdef __cplusplus +# define NIM_EXTERNC extern "C" +#else +# define NIM_EXTERNC +#endif diff --git a/lib/nimrtl.nim b/lib/nimrtl.nim index 68b7d7bd9..96dab1284 100644 --- a/lib/nimrtl.nim +++ b/lib/nimrtl.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/packages/docutils/highlite.nim b/lib/packages/docutils/highlite.nim index ff371f4e1..d4bd94e5e 100644 --- a/lib/packages/docutils/highlite.nim +++ b/lib/packages/docutils/highlite.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -23,7 +23,7 @@ type gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler, gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel, gtReference, gtOther - TGeneralTokenizer* = object of TObject + TGeneralTokenizer* = object of RootObj kind*: TTokenClass start*, length*: int buf: cstring @@ -31,11 +31,11 @@ type state: TTokenClass TSourceLanguage* = enum - langNone, langNimrod, langCpp, langCsharp, langC, langJava + langNone, langNim, langNimrod, langCpp, langCsharp, langC, langJava const - sourceLanguageToStr*: array[TSourceLanguage, string] = ["none", "Nimrod", - "C++", "C#", "C", "Java"] + sourceLanguageToStr*: array[TSourceLanguage, string] = ["none", + "Nim", "Nimrod", "C++", "C#", "C", "Java"] tokenClassToStr*: array[TTokenClass, string] = ["Eof", "None", "Whitespace", "DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber", "Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit", @@ -46,7 +46,7 @@ const # The following list comes from doc/keywords.txt, make sure it is # synchronized with this array by running the module itself as a test case. - nimrodKeywords = ["addr", "and", "as", "asm", "atomic", "bind", "block", + nimKeywords = ["addr", "and", "as", "asm", "atomic", "bind", "block", "break", "case", "cast", "const", "continue", "converter", "discard", "distinct", "div", "do", "elif", "else", "end", "enum", "except", "export", "finally", "for", "from", "generic", "if", "import", "in", "include", @@ -79,7 +79,7 @@ proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) = discard proc nimGetKeyword(id: string): TTokenClass = - for k in nimrodKeywords: + for k in nimKeywords: if cmpIgnoreStyle(id, k) == 0: return gtKeyword result = gtIdentifier when false: @@ -542,7 +542,7 @@ proc javaNextToken(g: var TGeneralTokenizer) = proc getNextToken*(g: var TGeneralTokenizer, lang: TSourceLanguage) = case lang of langNone: assert false - of langNimrod: nimNextToken(g) + of langNim, langNimrod: nimNextToken(g) of langCpp: cppNextToken(g) of langCsharp: csharpNextToken(g) of langC: cNextToken(g) @@ -557,7 +557,7 @@ when isMainModule: keywords = input.split() break doAssert(not keywords.isNil, "Couldn't read any keywords.txt file!") - doAssert keywords.len == nimrodKeywords.len, "No matching lengths" + doAssert keywords.len == nimKeywords.len, "No matching lengths" for i in 0..keywords.len-1: - #echo keywords[i], " == ", nimrodKeywords[i] - doAssert keywords[i] == nimrodKeywords[i], "Unexpected keyword" + #echo keywords[i], " == ", nimKeywords[i] + doAssert keywords[i] == nimKeywords[i], "Unexpected keyword" diff --git a/lib/packages/docutils/rst.nim b/lib/packages/docutils/rst.nim index 23459ade6..b21d51c93 100644 --- a/lib/packages/docutils/rst.nim +++ b/lib/packages/docutils/rst.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -17,7 +17,7 @@ import type TRstParseOption* = enum ## options for the RST parser roSkipPounds, ## skip ``#`` at line beginning (documentation - ## embedded in Nimrod comments) + ## embedded in Nim comments) roSupportSmilies, ## make the RST parser support smilies like ``:)`` roSupportRawDirective, ## support the ``raw`` directive (don't support ## it for sandboxing) @@ -66,8 +66,8 @@ proc getArgument*(n: PRstNode): string # ----------------------------- scanner part -------------------------------- const - SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'} - SmileyStartChars: TCharSet = {':', ';', '8'} + SymChars: set[char] = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'} + SmileyStartChars: set[char] = {':', ';', '8'} Smilies = { ":D": "icon_e_biggrin", ":-D": "icon_e_biggrin", @@ -111,21 +111,21 @@ const type TTokType = enum tkEof, tkIndent, tkWhite, tkWord, tkAdornment, tkPunct, tkOther - TToken{.final.} = object # a RST token + TToken = object # a RST token kind*: TTokType # the type of the token ival*: int # the indentation or parsed integer value symbol*: string # the parsed symbol as string line*, col*: int # line and column of the token TTokenSeq = seq[TToken] - TLexer = object of TObject + TLexer = object of RootObj buf*: cstring bufpos*: int line*, col*, baseIndent*: int skipPounds*: bool -proc getThing(L: var TLexer, tok: var TToken, s: TCharSet) = +proc getThing(L: var TLexer, tok: var TToken, s: set[char]) = tok.kind = tkWord tok.line = L.line tok.col = L.col @@ -273,7 +273,7 @@ type findFile: TFindFileHandler # How to find files. PSharedState = ref TSharedState - TRstParser = object of TObject + TRstParser = object of RootObj idx*: int tok*: TTokenSeq s*: PSharedState @@ -282,7 +282,7 @@ type line*, col*: int hasToc*: bool - EParseError* = object of EInvalidValue + EParseError* = object of ValueError proc whichMsgClass*(k: TMsgKind): TMsgClass = ## returns which message class `k` belongs to. diff --git a/lib/packages/docutils/rstast.nim b/lib/packages/docutils/rstast.nim index 8f946d973..52af672df 100644 --- a/lib/packages/docutils/rstast.nim +++ b/lib/packages/docutils/rstast.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -286,7 +286,7 @@ proc renderRstToRst*(n: PRstNode, result: var string) = var d: TRenderContext renderRstToRst(d, n, result) -proc renderRstToJsonNode(node: PRstNode): PJsonNode = +proc renderRstToJsonNode(node: PRstNode): JsonNode = result = %[ (key: "kind", val: %($node.kind)), @@ -295,7 +295,7 @@ proc renderRstToJsonNode(node: PRstNode): PJsonNode = if node.text != nil: result.add("text", %node.text) if node.sons != nil and len(node.sons) > 0: - var accm = newSeq[PJsonNode](len(node.sons)) + var accm = newSeq[JsonNode](len(node.sons)) for i, son in node.sons: accm[i] = renderRstToJsonNode(son) result.add("sons", %accm) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index e9bae69b5..02b0afd2f 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -35,16 +35,16 @@ type outHtml, # output is HTML outLatex # output is Latex - TTocEntry{.final.} = object + TTocEntry = object n*: PRstNode refname*, header*: string TMetaEnum* = enum metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion - TRstGenerator* = object of TObject + TRstGenerator* = object of RootObj target*: TOutputTarget - config*: PStringTable + config*: StringTableRef splitAfter*: int # split too long entries in the TOC tocPart*: seq[TTocEntry] hasToc*: bool @@ -57,21 +57,21 @@ type currentSection: string ## \ ## Stores the empty string or the last headline/overline found in the rst ## document, so it can be used as a prettier name for term index generation. - seenIndexTerms: TTable[string, int] ## \ + seenIndexTerms: Table[string, int] ## \ ## Keeps count of same text index terms to generate different identifiers ## for hyperlinks. See renderIndexTerm proc for details. PDoc = var TRstGenerator ## Alias to type less. proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget, - config: PStringTable, filename: string, + config: StringTableRef, filename: string, options: TRstParseOptions, findFile: TFindFileHandler, msgHandler: TMsgHandler) = ## Initializes a ``TRstGenerator``. ## ## You need to call this before using a ``TRstGenerator`` with any other - ## procs in this module. Pass a non ``nil`` ``PStringTable`` value as + ## procs in this module. Pass a non ``nil`` ``StringTableRef`` value as ## `config` with parameters used by the HTML output generator. If you don't ## know what to use, pass the results of the `defaultConfig() ## <#defaultConfig>_` proc. @@ -103,7 +103,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget, ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## import packages/docutils/rstgen ## @@ -231,7 +231,7 @@ proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string) ## ``initRstGenerator`` and parse a rst file with ``rstParse`` from the ## `packages/docutils/rst module <rst.html>`_. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## # ...configure gen and rst vars... ## var generatedHTML = "" @@ -341,13 +341,13 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) = [id, term]) type - TIndexEntry {.pure, final.} = object + TIndexEntry = object keyword: string link: string linkTitle: string ## If not nil, contains a prettier text for the href linkDesc: string ## If not nil, the title attribute of the final href - TIndexedDocs {.pure, final.} = TTable[TIndexEntry, seq[TIndexEntry]] ## \ + TIndexedDocs = Table[TIndexEntry, seq[TIndexEntry]] ## \ ## Contains the index sequences for doc types. ## ## The key is a *fake* TIndexEntry which will contain the title of the @@ -597,7 +597,7 @@ proc mergeIndexes*(dir: string): string = ## Merges all index files in `dir` and returns the generated index as HTML. ## ## This proc will first scan `dir` for index files with the ``.idx`` - ## extension previously created by commands like ``nimrod doc|rst2html`` + ## extension previously created by commands like ``nim doc|rst2html`` ## which use the ``--index:on`` switch. These index files are the result of ## calls to `setIndexTerm() <#setIndexTerm>`_ and `writeIndexFile() ## <#writeIndexFile>`_, so they are simple tab separated files. @@ -768,7 +768,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = var langstr = strip(getArgument(n)) var lang: TSourceLanguage if langstr == "": - lang = langNimrod # default language + lang = langNim # default language else: lang = getSourceLanguage(langstr) @@ -1011,7 +1011,7 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string], inc(i) if i > L-1 or frmt[i] notin {'0'..'9'}: break if j > high(varvalues) + 1: - raise newException(EInvalidValue, "invalid index: " & $j) + raise newException(ValueError, "invalid index: " & $j) num = j add(result, varvalues[j - 1]) of 'A'..'Z', 'a'..'z', '\x80'..'\xFF': @@ -1024,13 +1024,13 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string], if idx >= 0: add(result, varvalues[idx]) else: - raise newException(EInvalidValue, "unknown substitution var: " & id) + raise newException(ValueError, "unknown substitution var: " & id) of '{': var id = "" inc(i) while frmt[i] != '}': if frmt[i] == '\0': - raise newException(EInvalidValue, "'}' expected") + raise newException(ValueError, "'}' expected") add(id, frmt[i]) inc(i) inc(i) # skip } @@ -1038,9 +1038,9 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string], var idx = getVarIdx(varnames, id) if idx >= 0: add(result, varvalues[idx]) else: - raise newException(EInvalidValue, "unknown substitution var: " & id) + raise newException(ValueError, "unknown substitution var: " & id) else: - raise newException(EInvalidValue, "unknown substitution: $" & $frmt[i]) + raise newException(ValueError, "unknown substitution: $" & $frmt[i]) var start = i while i < L: if frmt[i] != '$': inc(i) @@ -1048,10 +1048,10 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string], if i-1 >= start: add(result, substr(frmt, start, i - 1)) -proc defaultConfig*(): PStringTable = +proc defaultConfig*(): StringTableRef = ## Returns a default configuration for embedded HTML generation. ## - ## The returned ``PStringTable`` contains the paramters used by the HTML + ## The returned ``StringTableRef`` contains the paramters 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. @@ -1113,7 +1113,7 @@ $content # ---------- forum --------------------------------------------------------- proc rstToHtml*(s: string, options: TRstParseOptions, - config: PStringTable): string = + config: StringTableRef): string = ## Converts an input rst string into embeddable HTML. ## ## This convenience proc parses any input string using rst markup (it doesn't @@ -1123,7 +1123,7 @@ proc rstToHtml*(s: string, options: TRstParseOptions, ## work. For an explanation of the ``config`` parameter see the ## ``initRstGenerator`` proc. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## import packages/docutils/rstgen, strtabs ## ## echo rstToHtml("*Hello* **world**!", {}, diff --git a/lib/posix/epoll.nim b/lib/posix/epoll.nim index ee04348e8..5565a5ae8 100644 --- a/lib/posix/epoll.nim +++ b/lib/posix/epoll.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Dominik Picheta # # See the file "copying.txt", included in this diff --git a/lib/posix/inotify.nim b/lib/posix/inotify.nim index 852eb12fa..c6f0633ff 100644 --- a/lib/posix/inotify.nim +++ b/lib/posix/inotify.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Dominik Picheta # # See the file "copying.txt", included in this diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim index e1bcd9dfc..c3085f0fb 100644 --- a/lib/posix/posix.nim +++ b/lib/posix/posix.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,14 +13,14 @@ # net/if, sys/socket, sys/uio, netinet/in, netinet/tcp, netdb ## This is a raw POSIX interface module. It does not not provide any -## convenience: cstrings are used instead of proper Nimrod strings and +## convenience: cstrings are used instead of proper Nim strings and ## return codes indicate errors. If you want exceptions -## and a proper Nimrod-like interface, use the OS module or write a wrapper. +## and a proper Nim-like interface, use the OS module or write a wrapper. ## Coding conventions: ## ALL types are named the same as in the POSIX standard except that they start ## with 'T' or 'P' (if they are pointers) and without the '_t' suffix to be -## consistent with Nimrod conventions. If an identifier is a Nimrod keyword +## consistent with Nim conventions. If an identifier is a Nim keyword ## the \`identifier\` notation is used. ## ## This library relies on the header files of your C compiler. The @@ -29,7 +29,7 @@ {.deadCodeElim:on.} -from times import TTime +from times import Time const hasSpawnH = not defined(haiku) # should exist for every Posix system nowadays @@ -83,8 +83,11 @@ else: ## A type representing a directory stream. type - TSocketHandle* = distinct cint # The type used to represent socket descriptors + SocketHandle* = distinct cint # The type used to represent socket descriptors +{.deprecated: [TSocketHandle: SocketHandle].} + +type Tdirent* {.importc: "struct dirent", header: "<dirent.h>", final, pure.} = object ## dirent_t struct d_ino*: Tino ## File serial number. @@ -264,9 +267,9 @@ type ## For a typed memory object, the length in bytes. ## For other file types, the use of this field is ## unspecified. - st_atime*: TTime ## Time of last access. - st_mtime*: TTime ## Time of last data modification. - st_ctime*: TTime ## Time of last status change. + st_atime*: Time ## Time of last access. + st_mtime*: Time ## Time of last data modification. + st_ctime*: Time ## Time of last status change. st_blksize*: Tblksize ## A file system-specific preferred I/O block size ## for this object. In some file system types, this ## may vary from file to file. @@ -307,7 +310,7 @@ type tm_isdst*: cint ## Daylight Savings flag. Ttimespec* {.importc: "struct timespec", header: "<time.h>", final, pure.} = object ## struct timespec - tv_sec*: TTime ## Seconds. + tv_sec*: Time ## Seconds. tv_nsec*: int ## Nanoseconds. titimerspec* {.importc: "struct itimerspec", header: "<time.h>", final, pure.} = object ## struct itimerspec @@ -381,12 +384,12 @@ type sched_ss_max_repl*: cint ## Maximum pending replenishments for ## sporadic server. - Ttimeval* {.importc: "struct timeval", header: "<sys/select.h>", - final, pure.} = object ## struct timeval + Timeval* {.importc: "struct timeval", header: "<sys/select.h>", + final, pure.} = object ## struct timeval tv_sec*: int ## Seconds. tv_usec*: int ## Microseconds. TFdSet* {.importc: "fd_set", header: "<sys/select.h>", - final, pure.} = object + final, pure.} = object Tmcontext* {.importc: "mcontext_t", header: "<ucontext.h>", final, pure.} = object Tucontext* {.importc: "ucontext_t", header: "<ucontext.h>", @@ -419,11 +422,11 @@ when hasSpawnH: header: "<spawn.h>", final, pure.} = object type - TSocklen* {.importc: "socklen_t", header: "<sys/socket.h>".} = cuint + Socklen* {.importc: "socklen_t", header: "<sys/socket.h>".} = cuint TSa_Family* {.importc: "sa_family_t", header: "<sys/socket.h>".} = cint - TSockAddr* {.importc: "struct sockaddr", header: "<sys/socket.h>", - pure, final.} = object ## struct sockaddr + SockAddr* {.importc: "struct sockaddr", header: "<sys/socket.h>", + pure, final.} = object ## struct sockaddr sa_family*: TSa_Family ## Address family. sa_data*: array [0..255, char] ## Socket address (variable-length data). @@ -446,17 +449,17 @@ type Tmsghdr* {.importc: "struct msghdr", pure, final, header: "<sys/socket.h>".} = object ## struct msghdr msg_name*: pointer ## Optional address. - msg_namelen*: TSocklen ## Size of address. + msg_namelen*: Socklen ## Size of address. msg_iov*: ptr TIOVec ## Scatter/gather array. msg_iovlen*: cint ## Members in msg_iov. msg_control*: pointer ## Ancillary data; see below. - msg_controllen*: TSocklen ## Ancillary data buffer len. + msg_controllen*: Socklen ## Ancillary data buffer len. msg_flags*: cint ## Flags on received message. Tcmsghdr* {.importc: "struct cmsghdr", pure, final, header: "<sys/socket.h>".} = object ## struct cmsghdr - cmsg_len*: TSocklen ## Data byte count, including the cmsghdr. + cmsg_len*: Socklen ## Data byte count, including the cmsghdr. cmsg_level*: cint ## Originating protocol. cmsg_type*: cint ## Protocol-specific type. @@ -471,15 +474,15 @@ type TInAddrT* {.importc: "in_addr_t", pure, final, header: "<netinet/in.h>".} = int32 ## unsigned! - TInAddr* {.importc: "struct in_addr", pure, final, + InAddr* {.importc: "struct in_addr", pure, final, header: "<netinet/in.h>".} = object ## struct in_addr s_addr*: TInAddrScalar - Tsockaddr_in* {.importc: "struct sockaddr_in", pure, final, + Sockaddr_in* {.importc: "struct sockaddr_in", pure, final, header: "<netinet/in.h>".} = object ## struct sockaddr_in sin_family*: TSa_Family ## AF_INET. sin_port*: TInPort ## Port number. - sin_addr*: TInAddr ## IP address. + sin_addr*: InAddr ## IP address. TIn6Addr* {.importc: "struct in6_addr", pure, final, header: "<netinet/in.h>".} = object ## struct in6_addr @@ -498,7 +501,7 @@ type ipv6mr_multiaddr*: TIn6Addr ## IPv6 multicast address. ipv6mr_interface*: cint ## Interface index. - Thostent* {.importc: "struct hostent", pure, final, + Hostent* {.importc: "struct hostent", pure, final, header: "<netdb.h>".} = object ## struct hostent h_name*: cstring ## Official name of the host. h_aliases*: cstringArray ## A pointer to an array of pointers to @@ -528,8 +531,8 @@ type ## a null pointer. p_proto*: cint ## The protocol number. - TServent* {.importc: "struct servent", pure, final, - header: "<netdb.h>".} = object ## struct servent + Servent* {.importc: "struct servent", pure, final, + header: "<netdb.h>".} = object ## struct servent s_name*: cstring ## Official name of the service. s_aliases*: cstringArray ## A pointer to an array of pointers to ## alternative service names, terminated by @@ -539,16 +542,16 @@ type s_proto*: cstring ## The name of the protocol to use when ## contacting the service. - Taddrinfo* {.importc: "struct addrinfo", pure, final, + AddrInfo* {.importc: "struct addrinfo", pure, final, header: "<netdb.h>".} = object ## struct addrinfo ai_flags*: cint ## Input flags. ai_family*: cint ## Address family of socket. ai_socktype*: cint ## Socket type. ai_protocol*: cint ## Protocol of socket. - ai_addrlen*: TSocklen ## Length of socket address. - ai_addr*: ptr TSockAddr ## Socket address of socket. + ai_addrlen*: Socklen ## Length of socket address. + ai_addr*: ptr SockAddr ## Socket address of socket. ai_canonname*: cstring ## Canonical name of service location. - ai_next*: ptr Taddrinfo ## Pointer to next in list. + ai_next*: ptr AddrInfo ## Pointer to next in list. TPollfd* {.importc: "struct pollfd", pure, final, header: "<poll.h>".} = object ## struct pollfd @@ -558,6 +561,11 @@ type Tnfds* {.importc: "nfds_t", header: "<poll.h>".} = cint +{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo, + TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval, + Thostent: Hostent, TServent: Servent, + TInAddr: InAddr].} + var errno* {.importc, header: "<errno.h>".}: cint ## error variable h_errno* {.importc, header: "<netdb.h>".}: cint @@ -1784,7 +1792,7 @@ proc ntohl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".} proc ntohs*(a1: int16): int16 {.importc, header: "<arpa/inet.h>".} proc inet_addr*(a1: cstring): TInAddrT {.importc, header: "<arpa/inet.h>".} -proc inet_ntoa*(a1: TInAddr): cstring {.importc, header: "<arpa/inet.h>".} +proc inet_ntoa*(a1: InAddr): cstring {.importc, header: "<arpa/inet.h>".} proc inet_ntop*(a1: cint, a2: pointer, a3: cstring, a4: int32): cstring {. importc, header: "<arpa/inet.h>".} proc inet_pton*(a1: cint, a2: cstring, a3: pointer): cint {. @@ -1814,7 +1822,7 @@ proc dlopen*(a1: cstring, a2: cint): pointer {.importc, header: "<dlfcn.h>".} proc dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "<dlfcn.h>".} proc creat*(a1: cstring, a2: TMode): cint {.importc, header: "<fcntl.h>".} -proc fcntl*(a1: cint | TSocketHandle, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".} +proc fcntl*(a1: cint | SocketHandle, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".} proc open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".} proc posix_fadvise*(a1: cint, a2, a3: TOff, a4: cint): cint {. importc, header: "<fcntl.h>".} @@ -2092,7 +2100,7 @@ proc access*(a1: cstring, a2: cint): cint {.importc, header: "<unistd.h>".} proc alarm*(a1: cint): cint {.importc, header: "<unistd.h>".} proc chdir*(a1: cstring): cint {.importc, header: "<unistd.h>".} proc chown*(a1: cstring, a2: Tuid, a3: TGid): cint {.importc, header: "<unistd.h>".} -proc close*(a1: cint | TSocketHandle): cint {.importc, header: "<unistd.h>".} +proc close*(a1: cint | SocketHandle): cint {.importc, header: "<unistd.h>".} proc confstr*(a1: cint, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".} proc crypt*(a1, a2: cstring): cstring {.importc, header: "<unistd.h>".} proc ctermid*(a1: cstring): cstring {.importc, header: "<unistd.h>".} @@ -2277,22 +2285,22 @@ proc clock_nanosleep*(a1: TClockId, a2: cint, a3: var Ttimespec, proc clock_settime*(a1: TClockId, a2: var Ttimespec): cint {. importc, header: "<time.h>".} -proc ctime*(a1: var TTime): cstring {.importc, header: "<time.h>".} -proc ctime_r*(a1: var TTime, a2: cstring): cstring {.importc, header: "<time.h>".} -proc difftime*(a1, a2: TTime): cdouble {.importc, header: "<time.h>".} +proc ctime*(a1: var Time): cstring {.importc, header: "<time.h>".} +proc ctime_r*(a1: var Time, a2: cstring): cstring {.importc, header: "<time.h>".} +proc difftime*(a1, a2: Time): cdouble {.importc, header: "<time.h>".} proc getdate*(a1: cstring): ptr Ttm {.importc, header: "<time.h>".} -proc gmtime*(a1: var TTime): ptr Ttm {.importc, header: "<time.h>".} -proc gmtime_r*(a1: var TTime, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>".} -proc localtime*(a1: var TTime): ptr Ttm {.importc, header: "<time.h>".} -proc localtime_r*(a1: var TTime, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>".} -proc mktime*(a1: var Ttm): TTime {.importc, header: "<time.h>".} -proc timegm*(a1: var Ttm): TTime {.importc, header: "<time.h>".} +proc gmtime*(a1: var Time): ptr Ttm {.importc, header: "<time.h>".} +proc gmtime_r*(a1: var Time, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>".} +proc localtime*(a1: var Time): ptr Ttm {.importc, header: "<time.h>".} +proc localtime_r*(a1: var Time, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>".} +proc mktime*(a1: var Ttm): Time {.importc, header: "<time.h>".} +proc timegm*(a1: var Ttm): Time {.importc, header: "<time.h>".} proc nanosleep*(a1, a2: var Ttimespec): cint {.importc, header: "<time.h>".} proc strftime*(a1: cstring, a2: int, a3: cstring, a4: var Ttm): int {.importc, header: "<time.h>".} proc strptime*(a1, a2: cstring, a3: var Ttm): cstring {.importc, header: "<time.h>".} -proc time*(a1: var TTime): TTime {.importc, header: "<time.h>".} +proc time*(a1: var Time): Time {.importc, header: "<time.h>".} proc timer_create*(a1: var TClockId, a2: var TsigEvent, a3: var Ttimer): cint {.importc, header: "<time.h>".} proc timer_delete*(a1: var Ttimer): cint {.importc, header: "<time.h>".} @@ -2372,14 +2380,15 @@ proc strerror*(errnum: cint): cstring {.importc, header: "<string.h>".} proc hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".} proc FD_CLR*(a1: cint, a2: var TFdSet) {.importc, header: "<sys/select.h>".} -proc FD_ISSET*(a1: cint | TSocketHandle, a2: var TFdSet): cint {. +proc FD_ISSET*(a1: cint | SocketHandle, a2: var TFdSet): cint {. importc, header: "<sys/select.h>".} -proc FD_SET*(a1: cint | TSocketHandle, a2: var TFdSet) {.importc, header: "<sys/select.h>".} +proc fdSet*(a1: cint | SocketHandle, a2: var TFdSet) {. + importc: "FD_SET", header: "<sys/select.h>".} proc FD_ZERO*(a1: var TFdSet) {.importc, header: "<sys/select.h>".} proc pselect*(a1: cint, a2, a3, a4: ptr TFdSet, a5: ptr Ttimespec, a6: var Tsigset): cint {.importc, header: "<sys/select.h>".} -proc select*(a1: cint | TSocketHandle, a2, a3, a4: ptr TFdSet, a5: ptr Ttimeval): cint {. +proc select*(a1: cint | SocketHandle, a2, a3, a4: ptr TFdSet, a5: ptr Timeval): cint {. importc, header: "<sys/select.h>".} when hasSpawnH: @@ -2455,48 +2464,48 @@ proc CMSG_FIRSTHDR*(mhdr: ptr Tmsghdr): ptr Tcmsghdr {. importc, header: "<sys/socket.h>".} const - INVALID_SOCKET* = TSocketHandle(-1) + INVALID_SOCKET* = SocketHandle(-1) -proc `==`*(x, y: TSocketHandle): bool {.borrow.} +proc `==`*(x, y: SocketHandle): bool {.borrow.} -proc accept*(a1: TSocketHandle, a2: ptr TSockAddr, a3: ptr TSocklen): TSocketHandle {. +proc accept*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr Socklen): SocketHandle {. importc, header: "<sys/socket.h>".} -proc bindSocket*(a1: TSocketHandle, a2: ptr TSockAddr, a3: TSocklen): cint {. +proc bindSocket*(a1: SocketHandle, a2: ptr SockAddr, a3: Socklen): cint {. importc: "bind", header: "<sys/socket.h>".} ## is Posix's ``bind``, because ``bind`` is a reserved word -proc connect*(a1: TSocketHandle, a2: ptr TSockAddr, a3: TSocklen): cint {. +proc connect*(a1: SocketHandle, a2: ptr SockAddr, a3: Socklen): cint {. importc, header: "<sys/socket.h>".} -proc getpeername*(a1: TSocketHandle, a2: ptr TSockAddr, a3: ptr TSocklen): cint {. +proc getpeername*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr Socklen): cint {. importc, header: "<sys/socket.h>".} -proc getsockname*(a1: TSocketHandle, a2: ptr TSockAddr, a3: ptr TSocklen): cint {. +proc getsockname*(a1: SocketHandle, a2: ptr SockAddr, a3: ptr Socklen): cint {. importc, header: "<sys/socket.h>".} -proc getsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: ptr TSocklen): cint {. +proc getsockopt*(a1: SocketHandle, a2, a3: cint, a4: pointer, a5: ptr Socklen): cint {. importc, header: "<sys/socket.h>".} -proc listen*(a1: TSocketHandle, a2: cint): cint {. +proc listen*(a1: SocketHandle, a2: cint): cint {. importc, header: "<sys/socket.h>".} -proc recv*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {. +proc recv*(a1: SocketHandle, a2: pointer, a3: int, a4: cint): int {. importc, header: "<sys/socket.h>".} -proc recvfrom*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint, - a5: ptr TSockAddr, a6: ptr TSocklen): int {. +proc recvfrom*(a1: SocketHandle, a2: pointer, a3: int, a4: cint, + a5: ptr SockAddr, a6: ptr Socklen): int {. importc, header: "<sys/socket.h>".} -proc recvmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {. +proc recvmsg*(a1: SocketHandle, a2: ptr Tmsghdr, a3: cint): int {. importc, header: "<sys/socket.h>".} -proc send*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {. +proc send*(a1: SocketHandle, a2: pointer, a3: int, a4: cint): int {. importc, header: "<sys/socket.h>".} -proc sendmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {. +proc sendmsg*(a1: SocketHandle, a2: ptr Tmsghdr, a3: cint): int {. importc, header: "<sys/socket.h>".} -proc sendto*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint, a5: ptr TSockAddr, - a6: TSocklen): int {. +proc sendto*(a1: SocketHandle, a2: pointer, a3: int, a4: cint, a5: ptr SockAddr, + a6: Socklen): int {. importc, header: "<sys/socket.h>".} -proc setsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: TSocklen): cint {. +proc setsockopt*(a1: SocketHandle, a2, a3: cint, a4: pointer, a5: Socklen): cint {. importc, header: "<sys/socket.h>".} -proc shutdown*(a1: TSocketHandle, a2: cint): cint {. +proc shutdown*(a1: SocketHandle, a2: cint): cint {. importc, header: "<sys/socket.h>".} -proc socket*(a1, a2, a3: cint): TSocketHandle {. +proc socket*(a1, a2, a3: cint): SocketHandle {. importc, header: "<sys/socket.h>".} proc sockatmark*(a1: cint): cint {. importc, header: "<sys/socket.h>".} @@ -2550,21 +2559,21 @@ proc endhostent*() {.importc, header: "<netdb.h>".} proc endnetent*() {.importc, header: "<netdb.h>".} proc endprotoent*() {.importc, header: "<netdb.h>".} proc endservent*() {.importc, header: "<netdb.h>".} -proc freeaddrinfo*(a1: ptr Taddrinfo) {.importc, header: "<netdb.h>".} +proc freeaddrinfo*(a1: ptr AddrInfo) {.importc, header: "<netdb.h>".} proc gai_strerror*(a1: cint): cstring {.importc, header: "<netdb.h>".} -proc getaddrinfo*(a1, a2: cstring, a3: ptr Taddrinfo, - a4: var ptr Taddrinfo): cint {.importc, header: "<netdb.h>".} +proc getaddrinfo*(a1, a2: cstring, a3: ptr AddrInfo, + a4: var ptr AddrInfo): cint {.importc, header: "<netdb.h>".} -proc gethostbyaddr*(a1: pointer, a2: TSocklen, a3: cint): ptr Thostent {. +proc gethostbyaddr*(a1: pointer, a2: Socklen, a3: cint): ptr Hostent {. importc, header: "<netdb.h>".} -proc gethostbyname*(a1: cstring): ptr Thostent {.importc, header: "<netdb.h>".} -proc gethostent*(): ptr Thostent {.importc, header: "<netdb.h>".} +proc gethostbyname*(a1: cstring): ptr Hostent {.importc, header: "<netdb.h>".} +proc gethostent*(): ptr Hostent {.importc, header: "<netdb.h>".} -proc getnameinfo*(a1: ptr TSockAddr, a2: TSocklen, - a3: cstring, a4: TSocklen, a5: cstring, - a6: TSocklen, a7: cint): cint {.importc, header: "<netdb.h>".} +proc getnameinfo*(a1: ptr SockAddr, a2: Socklen, + a3: cstring, a4: Socklen, a5: cstring, + a6: Socklen, a7: cint): cint {.importc, header: "<netdb.h>".} proc getnetbyaddr*(a1: int32, a2: cint): ptr Tnetent {.importc, header: "<netdb.h>".} proc getnetbyname*(a1: cstring): ptr Tnetent {.importc, header: "<netdb.h>".} @@ -2574,10 +2583,10 @@ proc getprotobyname*(a1: cstring): ptr TProtoent {.importc, header: "<netdb.h>". proc getprotobynumber*(a1: cint): ptr TProtoent {.importc, header: "<netdb.h>".} proc getprotoent*(): ptr TProtoent {.importc, header: "<netdb.h>".} -proc getservbyname*(a1, a2: cstring): ptr TServent {.importc, header: "<netdb.h>".} -proc getservbyport*(a1: cint, a2: cstring): ptr TServent {. +proc getservbyname*(a1, a2: cstring): ptr Servent {.importc, header: "<netdb.h>".} +proc getservbyport*(a1: cint, a2: cstring): ptr Servent {. importc, header: "<netdb.h>".} -proc getservent*(): ptr TServent {.importc, header: "<netdb.h>".} +proc getservent*(): ptr Servent {.importc, header: "<netdb.h>".} proc sethostent*(a1: cint) {.importc, header: "<netdb.h>".} proc setnetent*(a1: cint) {.importc, header: "<netdb.h>".} @@ -2590,7 +2599,7 @@ proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: int): cint {. proc realpath*(name, resolved: cstring): cstring {. importc: "realpath", header: "<stdlib.h>".} -proc utimes*(path: cstring, times: ptr array [2, Ttimeval]): int {. +proc utimes*(path: cstring, times: ptr array [2, Timeval]): int {. importc: "utimes", header: "<sys/time.h>".} ## Sets file access and modification times. ## diff --git a/lib/prelude.nim b/lib/prelude.nim index 50b4d4092..940864207 100644 --- a/lib/prelude.nim +++ b/lib/prelude.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -10,12 +10,12 @@ ## This is an include file that simply imports common modules for your ## convenience: ## -## .. code-block:: nimrod +## .. code-block:: nim ## include prelude ## ## Same as: ## -## .. code-block:: nimrod +## .. code-block:: nim ## import os, strutils, times, parseutils, parseopt, hashes, tables, sets import os, strutils, times, parseutils, parseopt, hashes, tables, sets diff --git a/lib/pure/actors.nim b/lib/pure/actors.nim index 2d902debe..f2c50ce4c 100644 --- a/lib/pure/actors.nim +++ b/lib/pure/actors.nim @@ -1,19 +1,19 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## `Actor`:idx: support for Nimrod. An actor is implemented as a thread with +## `Actor`:idx: support for Nim. An actor is implemented as a thread with ## a channel as its inbox. This module requires the ``--threads:on`` ## command line switch. ## ## Example: ## -## .. code-block:: nimrod +## .. code-block:: nim ## ## var ## a: TActorPool[int, void] @@ -21,6 +21,11 @@ ## for i in 0 .. < 300: ## a.spawn(i, proc (x: int) {.thread.} = echo x) ## a.join() +## +## **Note**: This whole module is deprecated. Use `threadpool` and ``spawn`` +## instead. + +{.deprecated.} from os import sleep diff --git a/lib/pure/actors.nimrod.cfg b/lib/pure/actors.nim.cfg index c6bb9c545..c6bb9c545 100644 --- a/lib/pure/actors.nimrod.cfg +++ b/lib/pure/actors.nim.cfg diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 89c83a8a4..0358a9a81 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -10,10 +10,13 @@ ## This module implements some common generic algorithms. type - TSortOrder* = enum ## sort order + SortOrder* = enum ## sort order Descending, Ascending -proc `*`*(x: int, order: TSortOrder): int {.inline.} = +{.deprecated: [TSortOrder: SortOrder].} + + +proc `*`*(x: int, order: SortOrder): int {.inline.} = ## flips `x` if ``order == Descending``; ## if ``order == Ascending`` then `x` is returned. ## `x` is supposed to be the result of a comparator, ie ``< 0`` for @@ -69,7 +72,7 @@ proc smartBinarySearch*[T](a: openArray[T], key: T): int = const onlySafeCode = true -proc lowerBound*[T](a: openarray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int = +proc lowerBound*[T](a: openArray[T], key: T, cmp: proc(x,y: T): int {.closure.}): int = ## same as binarySearch except that if key is not in `a` then this ## returns the location where `key` would be if it were. In other ## words if you have a sorted sequence and you call insert(thing, elm, lowerBound(thing, elm)) @@ -98,9 +101,9 @@ proc lowerBound*[T](a: openarray[T], key: T, cmp: proc(x,y: T): int {.closure.}) else: count = step -proc lowerBound*[T](a: openarray[T], key: T): int = lowerBound(a, key, cmp[T]) +proc lowerBound*[T](a: openArray[T], key: T): int = lowerBound(a, key, cmp[T]) proc merge[T](a, b: var openArray[T], lo, m, hi: int, - cmp: proc (x, y: T): int {.closure.}, order: TSortOrder) = + cmp: proc (x, y: T): int {.closure.}, order: SortOrder) = template `<-` (a, b: expr) = when false: a = b @@ -147,16 +150,16 @@ proc merge[T](a, b: var openArray[T], lo, m, hi: int, proc sort*[T](a: var openArray[T], cmp: proc (x, y: T): int {.closure.}, - order = TSortOrder.Ascending) = - ## Default Nimrod sort. The sorting is guaranteed to be stable and + order = SortOrder.Ascending) = + ## Default Nim sort. The sorting is guaranteed to be stable and ## the worst case is guaranteed to be O(n log n). ## The current implementation uses an iterative ## mergesort to achieve this. It uses a temporary sequence of - ## length ``a.len div 2``. Currently Nimrod does not support a + ## length ``a.len div 2``. Currently Nim does not support a ## sensible default argument for ``cmp``, so you have to provide one ## of your own. However, the ``system.cmp`` procs can be used: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## sort(myIntArray, system.cmp[int]) ## @@ -167,7 +170,7 @@ proc sort*[T](a: var openArray[T], ## You can inline adhoc comparison procs with the `do notation ## <manual.html#do-notation>`_. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## people.sort do (x, y: Person) -> int: ## result = cmp(x.surname, y.surname) @@ -184,7 +187,7 @@ proc sort*[T](a: var openArray[T], dec(m, s*2) s = s*2 -proc product*[T](x: openarray[seq[T]]): seq[seq[T]] = +proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = ## produces the Cartesian product of the array. Warning: complexity ## may explode. result = @[] diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 0ea8ef43b..073cd3576 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # # See the file "copying.txt", included in this @@ -13,45 +13,143 @@ import os, oids, tables, strutils, macros, times import rawsockets, net -export TPort, TSocketFlags +export Port, SocketFlag #{.injectStmt: newGcInvariant().} ## AsyncDispatch -## ------------- +## ************* ## -## This module implements a brand new dispatcher based on Futures. -## On Windows IOCP is used and on other operating systems the ``selectors`` -## module is used instead. +## This module implements asynchronous IO. This includes a dispatcher, +## a ``Future`` type implementation, and an ``async`` macro which allows +## asynchronous code to be written in a synchronous style with the ``await`` +## keyword. ## -## **Note:** This module is still largely experimental. +## The dispatcher acts as a kind of event loop. You must call ``poll`` on it +## (or a function which does so for you such as ``waitFor`` or ``runForever``) +## in order to poll for any outstanding events. The underlying implementation +## is based on epoll on Linux, IO Completion Ports on Windows and select on +## other operating systems. +## +## The ``poll`` function will not, on its own, return any events. Instead +## an appropriate ``Future`` object will be completed. A ``Future`` is a +## type which holds a value which is not yet available, but which *may* be +## available in the future. You can check whether a future is finished +## by using the ``finished`` function. When a future is finished it means that +## either the value that it holds is now available or it holds an error instead. +## The latter situation occurs when the operation to complete a future fails +## with an exception. You can distinguish between the two situations with the +## ``failed`` function. +## +## Future objects can also store a callback procedure which will be called +## automatically once the future completes. +## +## Futures therefore can be thought of as an implementation of the proactor +## pattern. In this +## pattern you make a request for an action, and once that action is fulfilled +## a future is completed with the result of that action. Requests can be +## made by calling the appropriate functions. For example: calling the ``recv`` +## function will create a request for some data to be read from a socket. The +## future which the ``recv`` function returns will then complete once the +## requested amount of data is read **or** an exception occurs. +## +## Code to read some data from a socket may look something like this: +## +## .. code-block::nim +## var future = socket.recv(100) +## future.callback = +## proc () = +## echo(future.read) +## +## All asynchronous functions returning a ``Future`` will not block. They +## will not however return immediately. An asynchronous function will have +## code which will be executed before an asynchronous request is made, in most +## cases this code sets up the request. +## +## In the above example, the ``recv`` function will return a brand new +## ``Future`` instance once the request for data to be read from the socket +## is made. This ``Future`` instance will complete once the requested amount +## of data is read, in this case it is 100 bytes. The second line sets a +## callback on this future which will be called once the future completes. +## All the callback does is write the data stored in the future to ``stdout``. +## The ``read`` function is used for this and it checks whether the future +## completes with an error for you (if it did it will simply raise the +## error), if there is no error however it returns the value of the future. +## +## Asynchronous procedures +## ----------------------- +## +## Asynchronous procedures remove the pain of working with callbacks. They do +## this by allowing you to write asynchronous code the same way as you would +## write synchronous code. +## +## An asynchronous procedure is marked using the ``{.async.}`` pragma. +## When marking a procedure with the ``{.async.}`` pragma it must have a +## ``Future[T]`` return type or no return type at all. If you do not specify +## a return type then ``Future[void]`` is assumed. +## +## Inside asynchronous procedures ``await`` can be used to call any +## procedures which return a +## ``Future``; this includes asynchronous procedures. When a procedure is +## "awaited", the asynchronous procedure it is awaited in will +## suspend its execution +## until the awaited procedure's Future completes. At which point the +## asynchronous procedure will resume its execution. During the period +## when an asynchronous procedure is suspended other asynchronous procedures +## will be run by the dispatcher. +## +## The ``await`` call may be used in many contexts. It can be used on the right +## hand side of a variable declaration: ``var data = await socket.recv(100)``, +## in which case the variable will be set to the value of the future +## automatically. It can be used to await a ``Future`` object, and it can +## be used to await a procedure returning a ``Future[void]``: +## ``await socket.send("foobar")``. +## +## Discarding futures +## ------------------ +## +## Futures should **never** be discarded. This is because they may contain +## errors. If you do not care for the result of a Future then you should +## use the ``asyncCheck`` procedure instead of the ``discard`` keyword. +## +## Examples +## -------- +## +## For examples take a look at the documentation for the modules implementing +## asynchronous IO. A good place to start is the +## `asyncnet module <asyncnet.html>`_. +## +## Limitations/Bugs +## ---------------- +## +## * ``except`` statement (without `try`) does not work inside async procedures. +## * The effect system (``raises: []``) does not work with async procedures. +## * Can't await in a ``except`` body -# TODO: ``except`` statement (without `try`) does not work. -# TODO: Multiple exception names in a ``except`` don't work. -# TODO: The effect system (raises: []) has trouble with my try transformation. -# TODO: Can't await in a 'except' body -# TODO: getCurrentException(Msg) don't work # TODO: Check if yielded future is nil and throw a more meaningful exception # -- Futures type - PFutureBase* = ref object of PObject + FutureBase* = ref object of RootObj ## Untyped future. cb: proc () {.closure,gcsafe.} finished: bool - error*: ref EBase + error*: ref Exception ## Stored exception errorStackTrace*: string when not defined(release): stackTrace: string ## For debugging purposes only. id: int fromProc: string - PFuture*[T] = ref object of PFutureBase - value: T + Future*[T] = ref object of FutureBase ## Typed future. + value: T ## Stored value + +{.deprecated: [PFutureBase: FutureBase, PFuture: Future].} -var currentID* = 0 -proc newFuture*[T](fromProc: string = "unspecified"): PFuture[T] = + +var currentID = 0 +proc newFuture*[T](fromProc: string = "unspecified"): Future[T] = ## Creates a new future. ## ## Specifying ``fromProc``, which is a string specifying the name of the proc @@ -64,7 +162,7 @@ proc newFuture*[T](fromProc: string = "unspecified"): PFuture[T] = result.fromProc = fromProc currentID.inc() -proc checkFinished[T](future: PFuture[T]) = +proc checkFinished[T](future: Future[T]) = when not defined(release): if future.finished: echo("<-----> ", future.id, " ", future.fromProc) @@ -77,7 +175,7 @@ proc checkFinished[T](future: PFuture[T]) = echo getStackTrace() assert false -proc complete*[T](future: PFuture[T], val: T) = +proc complete*[T](future: Future[T], val: T) = ## Completes ``future`` with value ``val``. #assert(not future.finished, "Future already finished, cannot finish twice.") checkFinished(future) @@ -87,7 +185,7 @@ proc complete*[T](future: PFuture[T], val: T) = if future.cb != nil: future.cb() -proc complete*(future: PFuture[void]) = +proc complete*(future: Future[void]) = ## Completes a void ``future``. #assert(not future.finished, "Future already finished, cannot finish twice.") checkFinished(future) @@ -96,7 +194,7 @@ proc complete*(future: PFuture[void]) = if future.cb != nil: future.cb() -proc fail*[T](future: PFuture[T], error: ref EBase) = +proc fail*[T](future: Future[T], error: ref Exception) = ## Completes ``future`` with ``error``. #assert(not future.finished, "Future already finished, cannot finish twice.") checkFinished(future) @@ -112,8 +210,9 @@ proc fail*[T](future: PFuture[T], error: ref EBase) = # TODO: This may turn out to be a bad idea. # Turns out this is a bad idea. #raise error + discard -proc `callback=`*(future: PFutureBase, cb: proc () {.closure,gcsafe.}) = +proc `callback=`*(future: FutureBase, cb: proc () {.closure,gcsafe.}) = ## Sets the callback proc to be called when the future completes. ## ## If future has already completed then ``cb`` will be called immediately. @@ -124,23 +223,24 @@ proc `callback=`*(future: PFutureBase, cb: proc () {.closure,gcsafe.}) = if future.finished: future.cb() -proc `callback=`*[T](future: PFuture[T], - cb: proc (future: PFuture[T]) {.closure,gcsafe.}) = +proc `callback=`*[T](future: Future[T], + cb: proc (future: Future[T]) {.closure,gcsafe.}) = ## Sets the callback proc to be called when the future completes. ## ## If future has already completed then ``cb`` will be called immediately. future.callback = proc () = cb(future) -proc echoOriginalStackTrace[T](future: PFuture[T]) = +proc echoOriginalStackTrace[T](future: Future[T]) = # TODO: Come up with something better. when not defined(release): echo("Original stack trace in ", future.fromProc, ":") - if not future.errorStackTrace.isNil() and future.errorStackTrace != "": + if not future.errorStackTrace.isNil and future.errorStackTrace != "": echo(future.errorStackTrace) else: echo("Empty or nil stack trace.") + echo("Continuing...") -proc read*[T](future: PFuture[T]): T = +proc read*[T](future: Future[T]): T = ## Retrieves the value of ``future``. Future must be finished otherwise ## this function will fail with a ``EInvalidValue`` exception. ## @@ -153,24 +253,28 @@ proc read*[T](future: PFuture[T]): T = return future.value else: # TODO: Make a custom exception type for this? - raise newException(EInvalidValue, "Future still in progress.") + raise newException(ValueError, "Future still in progress.") -proc readError*[T](future: PFuture[T]): ref EBase = +proc readError*[T](future: Future[T]): ref Exception = + ## Retrieves the exception stored in ``future``. + ## + ## An ``ValueError`` exception will be thrown if no exception exists + ## in the specified Future. if future.error != nil: return future.error else: - raise newException(EInvalidValue, "No error in future.") + raise newException(ValueError, "No error in future.") -proc finished*[T](future: PFuture[T]): bool = +proc finished*[T](future: Future[T]): bool = ## Determines whether ``future`` has completed. ## ## ``True`` may indicate an error or a value. Use ``failed`` to distinguish. future.finished -proc failed*(future: PFutureBase): bool = +proc failed*(future: FutureBase): bool = ## Determines whether ``future`` completed with an error. - future.error != nil + return future.error != nil -proc asyncCheck*[T](future: PFuture[T]) = +proc asyncCheck*[T](future: Future[T]) = ## Sets a callback on ``future`` which raises an exception if the future ## finished with an error. ## @@ -181,7 +285,7 @@ proc asyncCheck*[T](future: PFuture[T]) = echoOriginalStackTrace(future) raise future.error -proc `and`*[T, Y](fut1: PFuture[T], fut2: PFuture[Y]): PFuture[void] = +proc `and`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = ## Returns a future which will complete once both ``fut1`` and ``fut2`` ## complete. var retFuture = newFuture[void]("asyncdispatch.`and`") @@ -193,7 +297,7 @@ proc `and`*[T, Y](fut1: PFuture[T], fut2: PFuture[Y]): PFuture[void] = if fut1.finished: retFuture.complete() return retFuture -proc `or`*[T, Y](fut1: PFuture[T], fut2: PFuture[Y]): PFuture[void] = +proc `or`*[T, Y](fut1: Future[T], fut2: Future[Y]): Future[void] = ## Returns a future which will complete once either ``fut1`` or ``fut2`` ## complete. var retFuture = newFuture[void]("asyncdispatch.`or`") @@ -204,8 +308,8 @@ proc `or`*[T, Y](fut1: PFuture[T], fut2: PFuture[Y]): PFuture[void] = return retFuture type - PDispatcherBase = ref object of PObject - timers: seq[tuple[finishAt: float, fut: PFuture[void]]] + PDispatcherBase = ref object of RootRef + timers: seq[tuple[finishAt: float, fut: Future[void]]] proc processTimers(p: PDispatcherBase) = var oldTimers = p.timers @@ -219,21 +323,21 @@ proc processTimers(p: PDispatcherBase) = when defined(windows) or defined(nimdoc): import winlean, sets, hashes type - TCompletionKey = dword + TCompletionKey = Dword TCompletionData* = object - sock: TAsyncFD - cb: proc (sock: TAsyncFD, bytesTransferred: DWORD, - errcode: TOSErrorCode) {.closure,gcsafe.} + fd*: TAsyncFD # TODO: Rename this. + cb*: proc (fd: TAsyncFD, bytesTransferred: Dword, + errcode: OSErrorCode) {.closure,gcsafe.} PDispatcher* = ref object of PDispatcherBase ioPort: THandle - handles: TSet[TAsyncFD] + handles: HashSet[TAsyncFD] TCustomOverlapped = object of TOVERLAPPED data*: TCompletionData - PCustomOverlapped = ref TCustomOverlapped + PCustomOverlapped* = ref TCustomOverlapped TAsyncFD* = distinct int @@ -243,7 +347,7 @@ when defined(windows) or defined(nimdoc): proc newDispatcher*(): PDispatcher = ## Creates a new Dispatcher instance. new result - result.ioPort = CreateIOCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1) + result.ioPort = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1) result.handles = initSet[TAsyncFD]() result.timers = @[] @@ -253,19 +357,19 @@ when defined(windows) or defined(nimdoc): if gDisp.isNil: gDisp = newDispatcher() result = gDisp - proc register*(sock: TAsyncFD) = - ## Registers ``sock`` with the dispatcher. + proc register*(fd: TAsyncFD) = + ## Registers ``fd`` with the dispatcher. let p = getGlobalDispatcher() - if CreateIOCompletionPort(sock.THandle, p.ioPort, - cast[TCompletionKey](sock), 1) == 0: - osError(osLastError()) - p.handles.incl(sock) + if createIoCompletionPort(fd.THandle, p.ioPort, + cast[TCompletionKey](fd), 1) == 0: + raiseOSError(osLastError()) + p.handles.incl(fd) - proc verifyPresence(sock: TAsyncFD) = - ## Ensures that socket has been registered with the dispatcher. + proc verifyPresence(fd: TAsyncFD) = + ## Ensures that file descriptor has been registered with the dispatcher. let p = getGlobalDispatcher() - if sock notin p.handles: - raise newException(EInvalidValue, + if fd notin p.handles: + raise newException(ValueError, "Operation performed on a socket which has not been registered with" & " the dispatcher yet.") @@ -273,40 +377,40 @@ when defined(windows) or defined(nimdoc): ## Waits for completion events and processes them. let p = getGlobalDispatcher() if p.handles.len == 0 and p.timers.len == 0: - raise newException(EInvalidValue, + raise newException(ValueError, "No handles or timers registered in dispatcher.") let llTimeout = if timeout == -1: winlean.INFINITE else: timeout.int32 - var lpNumberOfBytesTransferred: DWORD + var lpNumberOfBytesTransferred: Dword var lpCompletionKey: ULONG var customOverlapped: PCustomOverlapped - let res = GetQueuedCompletionStatus(p.ioPort, + let res = getQueuedCompletionStatus(p.ioPort, addr lpNumberOfBytesTransferred, addr lpCompletionKey, - cast[ptr POverlapped](addr customOverlapped), llTimeout).bool + cast[ptr POVERLAPPED](addr customOverlapped), llTimeout).bool # http://stackoverflow.com/a/12277264/492186 # TODO: http://www.serverframework.com/handling-multiple-pending-socket-read-and-write-operations.html if res: # This is useful for ensuring the reliability of the overlapped struct. - assert customOverlapped.data.sock == lpCompletionKey.TAsyncFD + assert customOverlapped.data.fd == lpCompletionKey.TAsyncFD - customOverlapped.data.cb(customOverlapped.data.sock, - lpNumberOfBytesTransferred, TOSErrorCode(-1)) + customOverlapped.data.cb(customOverlapped.data.fd, + lpNumberOfBytesTransferred, OSErrorCode(-1)) GC_unref(customOverlapped) else: let errCode = osLastError() if customOverlapped != nil: - assert customOverlapped.data.sock == lpCompletionKey.TAsyncFD - customOverlapped.data.cb(customOverlapped.data.sock, + assert customOverlapped.data.fd == lpCompletionKey.TAsyncFD + customOverlapped.data.cb(customOverlapped.data.fd, lpNumberOfBytesTransferred, errCode) GC_unref(customOverlapped) else: if errCode.int32 == WAIT_TIMEOUT: # Timed out discard - else: osError(errCode) + else: raiseOSError(errCode) # Timer processing. processTimers(p) @@ -315,72 +419,72 @@ when defined(windows) or defined(nimdoc): var acceptExPtr: pointer = nil var getAcceptExSockAddrsPtr: pointer = nil - proc initPointer(s: TSocketHandle, func: var pointer, guid: var TGUID): bool = + proc initPointer(s: SocketHandle, func: var pointer, guid: var TGUID): bool = # Ref: https://github.com/powdahound/twisted/blob/master/twisted/internet/iocpreactor/iocpsupport/winsock_pointers.c - var bytesRet: DWord + var bytesRet: Dword func = nil result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, addr guid, - sizeof(TGUID).dword, addr func, sizeof(pointer).DWORD, + sizeof(TGUID).Dword, addr func, sizeof(pointer).Dword, addr bytesRet, nil, nil) == 0 proc initAll() = let dummySock = newRawSocket() if not initPointer(dummySock, connectExPtr, WSAID_CONNECTEX): - osError(osLastError()) + raiseOSError(osLastError()) if not initPointer(dummySock, acceptExPtr, WSAID_ACCEPTEX): - osError(osLastError()) + raiseOSError(osLastError()) if not initPointer(dummySock, getAcceptExSockAddrsPtr, WSAID_GETACCEPTEXSOCKADDRS): - osError(osLastError()) + raiseOSError(osLastError()) - proc connectEx(s: TSocketHandle, name: ptr TSockAddr, namelen: cint, - lpSendBuffer: pointer, dwSendDataLength: dword, - lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool = - if connectExPtr.isNil: raise newException(EInvalidValue, "Need to initialise ConnectEx().") + proc connectEx(s: SocketHandle, name: ptr TSockAddr, namelen: cint, + lpSendBuffer: pointer, dwSendDataLength: Dword, + lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool = + if connectExPtr.isNil: raise newException(ValueError, "Need to initialise ConnectEx().") let func = - cast[proc (s: TSocketHandle, name: ptr TSockAddr, namelen: cint, - lpSendBuffer: pointer, dwSendDataLength: dword, - lpdwBytesSent: PDWORD, lpOverlapped: POverlapped): bool {.stdcall,gcsafe.}](connectExPtr) + cast[proc (s: SocketHandle, name: ptr TSockAddr, namelen: cint, + lpSendBuffer: pointer, dwSendDataLength: Dword, + lpdwBytesSent: PDword, lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](connectExPtr) result = func(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent, lpOverlapped) - proc acceptEx(listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer, + proc acceptEx(listenSock, acceptSock: SocketHandle, lpOutputBuffer: pointer, dwReceiveDataLength, dwLocalAddressLength, - dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD, - lpOverlapped: POverlapped): bool = - if acceptExPtr.isNil: raise newException(EInvalidValue, "Need to initialise AcceptEx().") + dwRemoteAddressLength: Dword, lpdwBytesReceived: PDword, + lpOverlapped: POVERLAPPED): bool = + if acceptExPtr.isNil: raise newException(ValueError, "Need to initialise AcceptEx().") let func = - cast[proc (listenSock, acceptSock: TSocketHandle, lpOutputBuffer: pointer, + cast[proc (listenSock, acceptSock: SocketHandle, lpOutputBuffer: pointer, dwReceiveDataLength, dwLocalAddressLength, - dwRemoteAddressLength: DWORD, lpdwBytesReceived: PDWORD, - lpOverlapped: POverlapped): bool {.stdcall,gcsafe.}](acceptExPtr) + dwRemoteAddressLength: Dword, lpdwBytesReceived: PDword, + lpOverlapped: POVERLAPPED): bool {.stdcall,gcsafe.}](acceptExPtr) result = func(listenSock, acceptSock, lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, lpdwBytesReceived, lpOverlapped) proc getAcceptExSockaddrs(lpOutputBuffer: pointer, - dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD, - LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: lpint, - RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: lpint) = + dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: Dword, + LocalSockaddr: ptr ptr TSockAddr, LocalSockaddrLength: LPInt, + RemoteSockaddr: ptr ptr TSockAddr, RemoteSockaddrLength: LPInt) = if getAcceptExSockAddrsPtr.isNil: - raise newException(EInvalidValue, "Need to initialise getAcceptExSockAddrs().") + raise newException(ValueError, "Need to initialise getAcceptExSockAddrs().") let func = cast[proc (lpOutputBuffer: pointer, dwReceiveDataLength, dwLocalAddressLength, - dwRemoteAddressLength: DWORD, LocalSockaddr: ptr ptr TSockAddr, - LocalSockaddrLength: lpint, RemoteSockaddr: ptr ptr TSockAddr, - RemoteSockaddrLength: lpint) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr) + dwRemoteAddressLength: Dword, LocalSockaddr: ptr ptr TSockAddr, + LocalSockaddrLength: LPInt, RemoteSockaddr: ptr ptr TSockAddr, + RemoteSockaddrLength: LPInt) {.stdcall,gcsafe.}](getAcceptExSockAddrsPtr) func(lpOutputBuffer, dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, LocalSockaddr, LocalSockaddrLength, RemoteSockaddr, RemoteSockaddrLength) - proc connect*(socket: TAsyncFD, address: string, port: TPort, - af = AF_INET): PFuture[void] = + proc connect*(socket: TAsyncFD, address: string, port: Port, + af = AF_INET): Future[void] = ## Connects ``socket`` to server at ``address:port``. ## - ## Returns a ``PFuture`` which will complete when the connection succeeds + ## Returns a ``Future`` which will complete when the connection succeeds ## or an error occurs. verifyPresence(socket) var retFuture = newFuture[void]("connect") @@ -389,31 +493,31 @@ when defined(windows) or defined(nimdoc): saddr.sin_family = int16(toInt(af)) saddr.sin_port = 0 saddr.sin_addr.s_addr = INADDR_ANY - if bindAddr(socket.TSocketHandle, cast[ptr TSockAddr](addr(saddr)), + if bindAddr(socket.SocketHandle, cast[ptr TSockAddr](addr(saddr)), sizeof(saddr).TSockLen) < 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) var aiList = getAddrInfo(address, port, af) var success = false - var lastError: TOSErrorCode + var lastError: OSErrorCode var it = aiList while it != nil: # "the OVERLAPPED structure must remain valid until the I/O completes" # http://blogs.msdn.com/b/oldnewthing/archive/2011/02/02/10123392.aspx var ol = PCustomOverlapped() GC_ref(ol) - ol.data = TCompletionData(sock: socket, cb: - proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) = + ol.data = TCompletionData(fd: socket, cb: + proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) = if not retFuture.finished: - if errcode == TOSErrorCode(-1): + if errcode == OSErrorCode(-1): retFuture.complete() else: - retFuture.fail(newException(EOS, osErrorMsg(errcode))) + retFuture.fail(newException(OSError, osErrorMsg(errcode))) ) - var ret = connectEx(socket.TSocketHandle, it.ai_addr, - sizeof(TSockAddrIn).cint, nil, 0, nil, - cast[POverlapped](ol)) + var ret = connectEx(socket.SocketHandle, it.ai_addr, + sizeof(Tsockaddr_in).cint, nil, 0, nil, + cast[POVERLAPPED](ol)) if ret: # Request to connect completed immediately. success = true @@ -435,15 +539,17 @@ when defined(windows) or defined(nimdoc): dealloc(aiList) if not success: - retFuture.fail(newException(EOS, osErrorMsg(lastError))) + retFuture.fail(newException(OSError, osErrorMsg(lastError))) return retFuture proc recv*(socket: TAsyncFD, size: int, - flags = {TSocketFlags.SafeDisconn}): PFuture[string] = + flags = {SocketFlag.SafeDisconn}): Future[string] = ## Reads **up to** ``size`` bytes from ``socket``. Returned future will ## complete once all the data requested is read, a part of the data has been ## read, or the socket has disconnected in which case the future will ## complete with a value of ``""``. + ## + ## **Warning**: The ``Peek`` socket flag is not supported on Windows. # Things to note: @@ -453,19 +559,21 @@ when defined(windows) or defined(nimdoc): # '\0' in the message currently signifies a socket disconnect. Who # knows what will happen when someone sends that to our socket. verifyPresence(socket) + assert SocketFlag.Peek notin flags, "Peek not supported on Windows." + var retFuture = newFuture[string]("recv") var dataBuf: TWSABuf dataBuf.buf = cast[cstring](alloc0(size)) dataBuf.len = size - var bytesReceived: DWord - var flagsio = flags.toOSFlags().DWord + var bytesReceived: Dword + var flagsio = flags.toOSFlags().Dword var ol = PCustomOverlapped() GC_ref(ol) - ol.data = TCompletionData(sock: socket, cb: - proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) = + ol.data = TCompletionData(fd: socket, cb: + proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) = if not retFuture.finished: - if errcode == TOSErrorCode(-1): + if errcode == OSErrorCode(-1): if bytesCount == 0 and dataBuf.buf[0] == '\0': retFuture.complete("") else: @@ -477,14 +585,14 @@ when defined(windows) or defined(nimdoc): if flags.isDisconnectionError(errcode): retFuture.complete("") else: - retFuture.fail(newException(EOS, osErrorMsg(errcode))) + retFuture.fail(newException(OSError, osErrorMsg(errcode))) if dataBuf.buf != nil: dealloc dataBuf.buf dataBuf.buf = nil ) - let ret = WSARecv(socket.TSocketHandle, addr dataBuf, 1, addr bytesReceived, - addr flagsio, cast[POverlapped](ol), nil) + let ret = WSARecv(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived, + addr flagsio, cast[POVERLAPPED](ol), nil) if ret == -1: let err = osLastError() if err.int32 != ERROR_IO_PENDING: @@ -495,7 +603,7 @@ when defined(windows) or defined(nimdoc): if flags.isDisconnectionError(err): retFuture.complete("") else: - retFuture.fail(newException(EOS, osErrorMsg(err))) + 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 @@ -527,7 +635,7 @@ when defined(windows) or defined(nimdoc): return retFuture proc send*(socket: TAsyncFD, data: string, - flags = {TSocketFlags.SafeDisconn}): PFuture[void] = + flags = {SocketFlag.SafeDisconn}): Future[void] = ## Sends ``data`` to ``socket``. The returned future will complete once all ## data has been sent. verifyPresence(socket) @@ -537,23 +645,23 @@ when defined(windows) or defined(nimdoc): dataBuf.buf = data # since this is not used in a callback, this is fine dataBuf.len = data.len - var bytesReceived, lowFlags: DWord + var bytesReceived, lowFlags: Dword var ol = PCustomOverlapped() GC_ref(ol) - ol.data = TCompletionData(sock: socket, cb: - proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) = + ol.data = TCompletionData(fd: socket, cb: + proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) = if not retFuture.finished: - if errcode == TOSErrorCode(-1): + if errcode == OSErrorCode(-1): retFuture.complete() else: if flags.isDisconnectionError(errcode): retFuture.complete() else: - retFuture.fail(newException(EOS, osErrorMsg(errcode))) + retFuture.fail(newException(OSError, osErrorMsg(errcode))) ) - let ret = WSASend(socket.TSocketHandle, addr dataBuf, 1, addr bytesReceived, - lowFlags, cast[POverlapped](ol), nil) + let ret = WSASend(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived, + lowFlags, cast[POVERLAPPED](ol), nil) if ret == -1: let err = osLastError() if err.int32 != ERROR_IO_PENDING: @@ -561,7 +669,7 @@ when defined(windows) or defined(nimdoc): if flags.isDisconnectionError(err): retFuture.complete() else: - retFuture.fail(newException(EOS, osErrorMsg(err))) + retFuture.fail(newException(OSError, osErrorMsg(err))) else: retFuture.complete() # We don't deallocate ``ol`` here because even though this completed @@ -569,8 +677,8 @@ when defined(windows) or defined(nimdoc): # free ``ol``. return retFuture - proc acceptAddr*(socket: TAsyncFD, flags = {TSocketFlags.SafeDisconn}): - PFuture[tuple[address: string, client: TAsyncFD]] = + proc acceptAddr*(socket: TAsyncFD, flags = {SocketFlag.SafeDisconn}): + Future[tuple[address: string, client: TAsyncFD]] = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection and the remote address of the client. ## The future will complete when the connection is successfully accepted. @@ -586,28 +694,28 @@ when defined(windows) or defined(nimdoc): var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]("acceptAddr") var clientSock = newRawSocket() - if clientSock == osInvalidSocket: osError(osLastError()) + if clientSock == osInvalidSocket: raiseOSError(osLastError()) const lpOutputLen = 1024 var lpOutputBuf = newString(lpOutputLen) - var dwBytesReceived: DWORD - let dwReceiveDataLength = 0.DWORD # We don't want any data to be read. - let dwLocalAddressLength = DWORD(sizeof (TSockaddr_in) + 16) - let dwRemoteAddressLength = DWORD(sizeof(TSockaddr_in) + 16) + var dwBytesReceived: Dword + let dwReceiveDataLength = 0.Dword # We don't want any data to be read. + let dwLocalAddressLength = Dword(sizeof (Tsockaddr_in) + 16) + let dwRemoteAddressLength = Dword(sizeof(Tsockaddr_in) + 16) template completeAccept(): stmt {.immediate, dirty.} = var listenSock = socket let setoptRet = setsockopt(clientSock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, addr listenSock, sizeof(listenSock).TSockLen) - if setoptRet != 0: osError(osLastError()) + if setoptRet != 0: raiseOSError(osLastError()) - var LocalSockaddr, RemoteSockaddr: ptr TSockAddr + var localSockaddr, remoteSockaddr: ptr TSockAddr var localLen, remoteLen: int32 getAcceptExSockaddrs(addr lpOutputBuf[0], dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, - addr LocalSockaddr, addr localLen, - addr RemoteSockaddr, addr remoteLen) + addr localSockaddr, addr localLen, + addr remoteSockaddr, addr remoteLen) register(clientSock.TAsyncFD) # TODO: IPv6. Check ``sa_family``. http://stackoverflow.com/a/9212542/492186 retFuture.complete( @@ -625,25 +733,25 @@ when defined(windows) or defined(nimdoc): else: retFuture.complete(newAcceptFut.read) else: - retFuture.fail(newException(EOS, osErrorMsg(errcode))) + retFuture.fail(newException(OSError, osErrorMsg(errcode))) var ol = PCustomOverlapped() GC_ref(ol) - ol.data = TCompletionData(sock: socket, cb: - proc (sock: TAsyncFD, bytesCount: DWord, errcode: TOSErrorCode) = + ol.data = TCompletionData(fd: socket, cb: + proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) = if not retFuture.finished: - if errcode == TOSErrorCode(-1): + if errcode == OSErrorCode(-1): completeAccept() else: failAccept(errcode) ) # http://msdn.microsoft.com/en-us/library/windows/desktop/ms737524%28v=vs.85%29.aspx - let ret = acceptEx(socket.TSocketHandle, clientSock, addr lpOutputBuf[0], + let ret = acceptEx(socket.SocketHandle, clientSock, addr lpOutputBuf[0], dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength, - addr dwBytesReceived, cast[POverlapped](ol)) + addr dwBytesReceived, cast[POVERLAPPED](ol)) if not ret: let err = osLastError() @@ -658,17 +766,23 @@ when defined(windows) or defined(nimdoc): return retFuture - proc newAsyncRawSocket*(domain: TDomain = AF_INET, - typ: TType = SOCK_STREAM, - protocol: TProtocol = IPPROTO_TCP): TAsyncFD = + proc newAsyncRawSocket*(domain, typ, protocol: cint): TAsyncFD = + ## Creates a new socket and registers it with the dispatcher implicitly. + result = newRawSocket(domain, typ, protocol).TAsyncFD + result.SocketHandle.setBlocking(false) + register(result) + + proc newAsyncRawSocket*(domain: Domain = AF_INET, + typ: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): TAsyncFD = ## Creates a new socket and registers it with the dispatcher implicitly. result = newRawSocket(domain, typ, protocol).TAsyncFD - result.TSocketHandle.setBlocking(false) + result.SocketHandle.setBlocking(false) register(result) proc closeSocket*(socket: TAsyncFD) = ## Closes a socket and ensures that it is unregistered. - socket.TSocketHandle.close() + socket.SocketHandle.close() getGlobalDispatcher().handles.excl(socket) proc unregister*(fd: TAsyncFD) = @@ -692,10 +806,10 @@ else: type TAsyncFD* = distinct cint - TCallback = proc (sock: TAsyncFD): bool {.closure,gcsafe.} + TCallback = proc (fd: TAsyncFD): bool {.closure,gcsafe.} PData* = ref object of PObject - sock: TAsyncFD + fd: TAsyncFD readCBs: seq[TCallback] writeCBs: seq[TCallback] @@ -714,51 +828,56 @@ else: if gDisp.isNil: gDisp = newDispatcher() result = gDisp - proc update(sock: TAsyncFD, events: set[TEvent]) = + proc update(fd: TAsyncFD, events: set[TEvent]) = let p = getGlobalDispatcher() - assert sock.TSocketHandle in p.selector - discard p.selector.update(sock.TSocketHandle, events) + assert fd.SocketHandle in p.selector + discard p.selector.update(fd.SocketHandle, events) - proc register(sock: TAsyncFD) = + proc register*(fd: TAsyncFD) = let p = getGlobalDispatcher() - var data = PData(sock: sock, readCBs: @[], writeCBs: @[]) - p.selector.register(sock.TSocketHandle, {}, data.PObject) + var data = PData(fd: fd, readCBs: @[], writeCBs: @[]) + p.selector.register(fd.SocketHandle, {}, data.PObject) + + proc newAsyncRawSocket*(domain: cint, typ: cint, protocol: cint): TAsyncFD = + result = newRawSocket(domain, typ, protocol).TAsyncFD + result.SocketHandle.setBlocking(false) + register(result) proc newAsyncRawSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, protocol: TProtocol = IPPROTO_TCP): TAsyncFD = result = newRawSocket(domain, typ, protocol).TAsyncFD - result.TSocketHandle.setBlocking(false) + result.SocketHandle.setBlocking(false) register(result) proc closeSocket*(sock: TAsyncFD) = let disp = getGlobalDispatcher() - sock.TSocketHandle.close() - disp.selector.unregister(sock.TSocketHandle) + sock.SocketHandle.close() + disp.selector.unregister(sock.SocketHandle) proc unregister*(fd: TAsyncFD) = - getGlobalDispatcher().selector.unregister(fd.TSocketHandle) + getGlobalDispatcher().selector.unregister(fd.SocketHandle) - proc addRead(sock: TAsyncFD, cb: TCallback) = + proc addRead*(fd: TAsyncFD, cb: TCallback) = let p = getGlobalDispatcher() - if sock.TSocketHandle notin p.selector: + if fd.SocketHandle notin p.selector: raise newException(EInvalidValue, "File descriptor not registered.") - p.selector[sock.TSocketHandle].data.PData.readCBs.add(cb) - update(sock, p.selector[sock.TSocketHandle].events + {EvRead}) + p.selector[fd.SocketHandle].data.PData.readCBs.add(cb) + update(fd, p.selector[fd.SocketHandle].events + {EvRead}) - proc addWrite(sock: TAsyncFD, cb: TCallback) = + proc addWrite*(fd: TAsyncFD, cb: TCallback) = let p = getGlobalDispatcher() - if sock.TSocketHandle notin p.selector: + if fd.SocketHandle notin p.selector: raise newException(EInvalidValue, "File descriptor not registered.") - p.selector[sock.TSocketHandle].data.PData.writeCBs.add(cb) - update(sock, p.selector[sock.TSocketHandle].events + {EvWrite}) + p.selector[fd.SocketHandle].data.PData.writeCBs.add(cb) + update(fd, p.selector[fd.SocketHandle].events + {EvWrite}) proc poll*(timeout = 500) = let p = getGlobalDispatcher() for info in p.selector.select(timeout): let data = PData(info.key.data) - assert data.sock == info.key.fd.TAsyncFD - #echo("In poll ", data.sock.cint) + assert data.fd == info.key.fd.TAsyncFD + #echo("In poll ", data.fd.cint) if EvRead in info.events: # Callback may add items to ``data.readCBs`` which causes issues if # we are iterating over ``data.readCBs`` at the same time. We therefore @@ -766,7 +885,7 @@ else: let currentCBs = data.readCBs data.readCBs = @[] for cb in currentCBs: - if not cb(data.sock): + if not cb(data.fd): # Callback wants to be called again. data.readCBs.add(cb) @@ -774,7 +893,7 @@ else: let currentCBs = data.writeCBs data.writeCBs = @[] for cb in currentCBs: - if not cb(data.sock): + if not cb(data.fd): # Callback wants to be called again. data.writeCBs.add(cb) @@ -783,18 +902,19 @@ else: if data.readCBs.len != 0: newEvents = {EvRead} if data.writeCBs.len != 0: newEvents = newEvents + {EvWrite} if newEvents != info.key.events: - update(data.sock, newEvents) + update(data.fd, newEvents) else: # FD no longer a part of the selector. Likely been closed # (e.g. socket disconnected). + discard processTimers(p) proc connect*(socket: TAsyncFD, address: string, port: TPort, - af = AF_INET): PFuture[void] = + af = AF_INET): Future[void] = var retFuture = newFuture[void]("connect") - proc cb(sock: TAsyncFD): bool = + proc cb(fd: TAsyncFD): bool = # We have connected. retFuture.complete() return true @@ -804,7 +924,7 @@ else: var lastError: TOSErrorCode var it = aiList while it != nil: - var ret = connect(socket.TSocketHandle, it.ai_addr, it.ai_addrlen.TSocklen) + var ret = connect(socket.SocketHandle, it.ai_addr, it.ai_addrlen.Socklen) if ret == 0: # Request to connect completed immediately. success = true @@ -826,14 +946,14 @@ else: return retFuture proc recv*(socket: TAsyncFD, size: int, - flags = {TSocketFlags.SafeDisconn}): PFuture[string] = + flags = {TSocketFlags.SafeDisconn}): Future[string] = var retFuture = newFuture[string]("recv") var readBuffer = newString(size) proc cb(sock: TAsyncFD): bool = result = true - let res = recv(sock.TSocketHandle, addr readBuffer[0], size.cint, + let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint, flags.toOSFlags()) #echo("recv cb res: ", res) if res < 0: @@ -857,7 +977,7 @@ else: return retFuture proc send*(socket: TAsyncFD, data: string, - flags = {TSocketFlags.SafeDisconn}): PFuture[void] = + flags = {TSocketFlags.SafeDisconn}): Future[void] = var retFuture = newFuture[void]("send") var written = 0 @@ -866,7 +986,7 @@ else: result = true let netSize = data.len-written var d = data.cstring - let res = send(sock.TSocketHandle, addr d[written], netSize.cint, + let res = send(sock.SocketHandle, addr d[written], netSize.cint, MSG_NOSIGNAL) if res < 0: let lastError = osLastError() @@ -889,15 +1009,15 @@ else: return retFuture proc acceptAddr*(socket: TAsyncFD, flags = {TSocketFlags.SafeDisconn}): - PFuture[tuple[address: string, client: TAsyncFD]] = + Future[tuple[address: string, client: TAsyncFD]] = var retFuture = newFuture[tuple[address: string, client: TAsyncFD]]("acceptAddr") proc cb(sock: TAsyncFD): bool = result = true - var sockAddress: Tsockaddr_in - var addrLen = sizeof(sockAddress).TSocklen - var client = accept(sock.TSocketHandle, - cast[ptr TSockAddr](addr(sockAddress)), addr(addrLen)) + var sockAddress: SockAddr_in + var addrLen = sizeof(sockAddress).Socklen + var client = accept(sock.SocketHandle, + cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) if client == osInvalidSocket: let lastError = osLastError() assert lastError.int32 notin {EWOULDBLOCK, EAGAIN} @@ -914,7 +1034,7 @@ else: addRead(socket, cb) return retFuture -proc sleepAsync*(ms: int): PFuture[void] = +proc sleepAsync*(ms: int): Future[void] = ## Suspends the execution of the current async procedure for the next ## ``ms`` miliseconds. var retFuture = newFuture[void]("sleepAsync") @@ -923,14 +1043,14 @@ proc sleepAsync*(ms: int): PFuture[void] = return retFuture proc accept*(socket: TAsyncFD, - flags = {TSocketFlags.SafeDisconn}): PFuture[TAsyncFD] = + flags = {SocketFlag.SafeDisconn}): Future[TAsyncFD] = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection. ## The future will complete when the connection is successfully accepted. var retFut = newFuture[TAsyncFD]("accept") var fut = acceptAddr(socket, flags) fut.callback = - proc (future: PFuture[tuple[address: string, client: TAsyncFD]]) = + proc (future: Future[tuple[address: string, client: TAsyncFD]]) = assert future.finished if future.failed: retFut.fail(future.error) @@ -940,7 +1060,7 @@ proc accept*(socket: TAsyncFD, # -- Await Macro -template createCb*(retFutureSym, iteratorNameSym, +template createCb(retFutureSym, iteratorNameSym, name: expr): stmt {.immediate.} = var nameIterVar = iteratorNameSym #{.push stackTrace: off.} @@ -963,29 +1083,50 @@ template createCb*(retFutureSym, iteratorNameSym, cb() #{.pop.} proc generateExceptionCheck(futSym, - exceptBranch, rootReceiver, fromNode: PNimrodNode): PNimrodNode {.compileTime.} = - if exceptBranch == nil: + tryStmt, rootReceiver, fromNode: PNimrodNode): PNimrodNode {.compileTime.} = + if tryStmt.kind == nnkNilLit: result = rootReceiver else: - if exceptBranch[0].kind == nnkStmtList: - result = newIfStmt( - (newDotExpr(futSym, newIdentNode("failed")), - exceptBranch[0] - ) - ) - else: - expectKind(exceptBranch[1], nnkStmtList) - result = newIfStmt( - (newDotExpr(futSym, newIdentNode("failed")), - newIfStmt( - (infix(newDotExpr(futSym, newIdentNode("error")), "of", exceptBranch[0]), - exceptBranch[1]) - ) - ) - ) + var exceptionChecks: seq[tuple[cond, body: PNimrodNode]] = @[] + let errorNode = newDotExpr(futSym, newIdentNode("error")) + for i in 1 .. <tryStmt.len: + let exceptBranch = tryStmt[i] + if exceptBranch[0].kind == nnkStmtList: + exceptionChecks.add((newIdentNode("true"), exceptBranch[0])) + else: + var exceptIdentCount = 0 + var ifCond: PNimrodNode + for i in 0 .. <exceptBranch.len: + let child = exceptBranch[i] + if child.kind == nnkIdent: + let cond = infix(errorNode, "of", child) + if exceptIdentCount == 0: + ifCond = cond + else: + ifCond = infix(ifCond, "or", cond) + else: + break + exceptIdentCount.inc + + expectKind(exceptBranch[exceptIdentCount], nnkStmtList) + exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount])) + # -> -> else: raise futSym.error + exceptionChecks.add((newIdentNode("true"), + newNimNode(nnkRaiseStmt).add(errorNode))) + # Read the future if there is no error. + # -> else: futSym.read let elseNode = newNimNode(nnkElse, fromNode) elseNode.add newNimNode(nnkStmtList, fromNode) elseNode[0].add rootReceiver + + let ifBody = newStmtList() + ifBody.add newCall(newIdentNode("setCurrentException"), errorNode) + ifBody.add newIfStmt(exceptionChecks) + ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit()) + + result = newIfStmt( + (newDotExpr(futSym, newIdentNode("failed")), ifBody) + ) result.add elseNode template createVar(result: var PNimrodNode, futSymName: string, @@ -997,25 +1138,25 @@ template createVar(result: var PNimrodNode, futSymName: string, result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y result.add newNimNode(nnkYieldStmt, fromNode).add(futSym) # -> yield future<x> valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read - result.add generateExceptionCheck(futSym, exceptBranch, rootReceiver, fromNode) + result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode) proc processBody(node, retFutureSym: PNimrodNode, subTypeIsVoid: bool, - exceptBranch: PNimrodNode): PNimrodNode {.compileTime.} = + tryStmt: PNimrodNode): PNimrodNode {.compileTime.} = #echo(node.treeRepr) result = node case node.kind of nnkReturnStmt: result = newNimNode(nnkStmtList, node) if node[0].kind == nnkEmpty: - if not subtypeIsVoid: + if not subTypeIsVoid: result.add newCall(newIdentNode("complete"), retFutureSym, newIdentNode("result")) else: result.add newCall(newIdentNode("complete"), retFutureSym) else: result.add newCall(newIdentNode("complete"), retFutureSym, - node[0].processBody(retFutureSym, subtypeIsVoid, exceptBranch)) + node[0].processBody(retFutureSym, subTypeIsVoid, tryStmt)) result.add newNimNode(nnkReturnStmt, node).add(newNilLit()) return # Don't process the children of this return stmt @@ -1070,7 +1211,7 @@ proc processBody(node, retFutureSym: PNimrodNode, res: PNimrodNode): bool {.compileTime.} = result = false while i < n[0].len: - var processed = processBody(n[0][i], retFutureSym, subtypeIsVoid, n[1]) + var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n) if processed.kind != n[0][i].kind or processed.len != n[0][i].len: expectKind(processed, nnkStmtList) expectKind(processed[2][1], nnkElse) @@ -1090,7 +1231,7 @@ proc processBody(node, retFutureSym: PNimrodNode, else: discard for i in 0 .. <result.len: - result[i] = processBody(result[i], retFutureSym, subtypeIsVoid, exceptBranch) + result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, tryStmt) proc getName(node: PNimrodNode): string {.compileTime.} = case node.kind @@ -1113,12 +1254,12 @@ macro async*(prc: stmt): stmt {.immediate.} = hint("Processing " & prc[0].getName & " as an async proc.") let returnType = prc[3][0] - # Verify that the return type is a PFuture[T] + # Verify that the return type is a Future[T] if returnType.kind == nnkIdent: - error("Expected return type of 'PFuture' got '" & $returnType & "'") + error("Expected return type of 'Future' got '" & $returnType & "'") elif returnType.kind == nnkBracketExpr: - if $returnType[0] != "PFuture": - error("Expected return type of 'PFuture' got '" & $returnType[0] & "'") + if $returnType[0] != "Future": + error("Expected return type of 'Future' got '" & $returnType[0] & "'") let subtypeIsVoid = returnType.kind == nnkEmpty or (returnType.kind == nnkBracketExpr and @@ -1139,7 +1280,7 @@ macro async*(prc: stmt): stmt {.immediate.} = subRetType), newLit(prc[0].getName)))) # Get type from return type of this proc - # -> iterator nameIter(): PFutureBase {.closure.} = + # -> iterator nameIter(): FutureBase {.closure.} = # -> var result: T # -> <proc_body> # -> complete(retFuture, result) @@ -1155,14 +1296,14 @@ macro async*(prc: stmt): stmt {.immediate.} = # -> complete(retFuture) procBody.add(newCall(newIdentNode("complete"), retFutureSym)) - var closureIterator = newProc(iteratorNameSym, [newIdentNode("PFutureBase")], + var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")], procBody, nnkIteratorDef) closureIterator[4] = newNimNode(nnkPragma, prc[6]).add(newIdentNode("closure")) outerProcBody.add(closureIterator) # -> createCb(retFuture) var cbName = newIdentNode("cb") - var procCb = newCall("createCb", retFutureSym, iteratorNameSym, + var procCb = newCall(bindSym"createCb", retFutureSym, iteratorNameSym, newStrLitNode(prc[0].getName)) outerProcBody.add procCb @@ -1178,16 +1319,16 @@ macro async*(prc: stmt): stmt {.immediate.} = if subtypeIsVoid: # Add discardable pragma. if returnType.kind == nnkEmpty: - # Add PFuture[void] - result[3][0] = parseExpr("PFuture[void]") + # Add Future[void] + result[3][0] = parseExpr("Future[void]") result[6] = outerProcBody #echo(treeRepr(result)) - #if prc[0].getName == "getFile": + #if prc[0].getName == "catch": # echo(toStrLit(result)) -proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} = +proc recvLine*(socket: TAsyncFD): Future[string] {.async.} = ## Reads a line of data from ``socket``. Returned future will complete once ## a full line is read or an error occurs. ## @@ -1200,6 +1341,11 @@ proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} = ## If the socket is disconnected in the middle of a line (before ``\r\L`` ## is read) then line will be set to ``""``. ## The partial line **will be lost**. + ## + ## **Warning**: This assumes that lines are delimited by ``\r\L``. + ## + ## **Note**: This procedure is mostly used for testing. You likely want to + ## use ``asyncnet.recvLine`` instead. template addNLIfEmpty(): stmt = if result.len == 0: @@ -1212,9 +1358,8 @@ proc recvLine*(socket: TAsyncFD): PFuture[string] {.async.} = if c.len == 0: return "" if c == "\r": - c = await recv(socket, 1, {TSocketFlags.SafeDisconn, TSocketFlags.Peek}) - if c.len > 0 and c == "\L": - discard await recv(socket, 1) + c = await recv(socket, 1) + assert c == "\l" addNLIfEmpty() return elif c == "\L": @@ -1227,10 +1372,9 @@ proc runForever*() = while true: poll() -proc waitFor*[T](fut: PFuture[T]) = +proc waitFor*[T](fut: PFuture[T]): T = ## **Blocks** the current thread until the specified future completes. while not fut.finished: poll() - if fut.failed: - raise fut.error + fut.read diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim new file mode 100644 index 000000000..c09cb5a35 --- /dev/null +++ b/lib/pure/asyncfile.nim @@ -0,0 +1,325 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2014 Dominik Picheta +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements asynchronous file handling. +## +## .. code-block:: Nim +## import asyncfile, asyncdispatch, os +## +## proc main() {.async.} = +## var file = openAsync(getTempDir() / "foobar.txt", fmReadWrite) +## await file.write("test") +## file.setFilePos(0) +## let data = await file.readAll() +## doAssert data == "test" +## file.close() +## +## waitFor main() + +import asyncdispatch, os + +when defined(windows): + import winlean +else: + import posix + +type + AsyncFile = ref object + fd: TAsyncFd + offset: int64 + +when defined(windows): + proc getDesiredAccess(mode: TFileMode): int32 = + case mode + of fmRead: + result = GENERIC_READ + of fmWrite, fmAppend: + result = GENERIC_WRITE + of fmReadWrite, fmReadWriteExisting: + result = GENERIC_READ or GENERIC_WRITE + + proc getCreationDisposition(mode: TFileMode, filename: string): int32 = + case mode + of fmRead, fmReadWriteExisting: + OPEN_EXISTING + of fmAppend, fmReadWrite, fmWrite: + if fileExists(filename): + OPEN_EXISTING + else: + CREATE_NEW +else: + proc getPosixFlags(mode: TFileMode): cint = + case mode + of fmRead: + result = O_RDONLY + of fmWrite: + result = O_WRONLY or O_CREAT + of fmAppend: + result = O_WRONLY or O_CREAT or O_APPEND + of fmReadWrite: + result = O_RDWR or O_CREAT + of fmReadWriteExisting: + result = O_RDWR + result = result or O_NONBLOCK + +proc getFileSize(f: AsyncFile): int64 = + ## Retrieves the specified file's size. + when defined(windows): + var high: DWord + let low = getFileSize(f.fd.THandle, addr high) + if low == INVALID_FILE_SIZE: + raiseOSError() + return (high shl 32) or low + +proc openAsync*(filename: string, mode = fmRead): AsyncFile = + ## Opens a file specified by the path in ``filename`` using + ## the specified ``mode`` asynchronously. + new result + when defined(windows): + let flags = FILE_FLAG_OVERLAPPED or FILE_ATTRIBUTE_NORMAL + let desiredAccess = getDesiredAccess(mode) + let creationDisposition = getCreationDisposition(mode, filename) + when useWinUnicode: + result.fd = createFileW(newWideCString(filename), desiredAccess, + FILE_SHARE_READ, + nil, creationDisposition, flags, 0).TAsyncFd + else: + result.fd = createFileA(filename, desiredAccess, + FILE_SHARE_READ, + nil, creationDisposition, flags, 0).TAsyncFd + + if result.fd.THandle == INVALID_HANDLE_VALUE: + raiseOSError() + + register(result.fd) + + if mode == fmAppend: + result.offset = getFileSize(result) + + else: + let flags = getPosixFlags(mode) + # RW (Owner), RW (Group), R (Other) + 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() + + register(result.fd) + +proc read*(f: AsyncFile, size: int): Future[string] = + ## Read ``size`` bytes from the specified file asynchronously starting at + ## the current position of the file pointer. + ## + ## If the file pointer is past the end of the file then an empty string is + ## returned. + var retFuture = newFuture[string]("asyncfile.read") + + when defined(windows): + var buffer = alloc0(size) + + var ol = PCustomOverlapped() + GC_ref(ol) + ol.data = TCompletionData(fd: f.fd, cb: + proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) = + if not retFuture.finished: + if errcode == OSErrorCode(-1): + assert bytesCount > 0 + assert bytesCount <= size + var data = newString(bytesCount) + copyMem(addr data[0], buffer, bytesCount) + f.offset.inc bytesCount + retFuture.complete($data) + else: + if errcode.int32 == ERROR_HANDLE_EOF: + retFuture.complete("") + else: + retFuture.fail(newException(OSError, osErrorMsg(errcode))) + if buffer != nil: + dealloc buffer + buffer = nil + ) + ol.offset = DWord(f.offset and 0xffffffff) + ol.offsetHigh = DWord(f.offset shr 32) + + # According to MSDN we're supposed to pass nil to lpNumberOfBytesRead. + let ret = readFile(f.fd.THandle, buffer, size.int32, nil, + cast[POVERLAPPED](ol)) + if not ret.bool: + let err = osLastError() + if err.int32 != ERROR_IO_PENDING: + if buffer != nil: + dealloc buffer + buffer = nil + GC_unref(ol) + retFuture.fail(newException(OSError, osErrorMsg(err))) + else: + # Request completed immediately. + var bytesRead: DWord + let overlappedRes = getOverlappedResult(f.fd.THandle, + cast[POverlapped](ol)[], bytesRead, false.WinBool) + if not overlappedRes.bool: + let err = osLastError() + if err.int32 == ERROR_HANDLE_EOF: + retFuture.complete("") + else: + retFuture.fail(newException(OSError, osErrorMsg(osLastError()))) + else: + assert bytesRead > 0 + assert bytesRead <= size + var data = newString(bytesRead) + copyMem(addr data[0], buffer, bytesRead) + f.offset.inc bytesRead + retFuture.complete($data) + else: + var readBuffer = newString(size) + + proc cb(fd: TAsyncFD): bool = + result = true + let res = read(fd.cint, addr readBuffer[0], size.cint) + if res < 0: + let lastError = osLastError() + if lastError.int32 != EAGAIN: + retFuture.fail(newException(EOS, osErrorMsg(lastError))) + else: + result = false # We still want this callback to be called. + elif res == 0: + # EOF + retFuture.complete("") + else: + readBuffer.setLen(res) + f.offset.inc(res) + retFuture.complete(readBuffer) + + if not cb(f.fd): + addRead(f.fd, cb) + + return retFuture + +proc readLine*(f: AsyncFile): Future[string] {.async.} = + ## Reads a single line from the specified file asynchronously. + result = "" + while true: + var c = await read(f, 1) + if c[0] == '\c': + c = await read(f, 1) + break + if c[0] == '\L' or c == "": + break + else: + result.add(c) + +proc getFilePos*(f: AsyncFile): int64 = + ## Retrieves the current position of the file pointer that is + ## used to read from the specified file. The file's first byte has the + ## index zero. + f.offset + +proc setFilePos*(f: AsyncFile, pos: int64) = + ## Sets the position of the file pointer that is used for read/write + ## operations. The file's first byte has the index zero. + f.offset = pos + when not defined(windows): + let ret = lseek(f.fd.cint, pos, SEEK_SET) + if ret == -1: + raiseOSError() + +proc readAll*(f: AsyncFile): Future[string] {.async.} = + ## Reads all data from the specified file. + result = "" + while true: + let data = await read(f, 4000) + if data.len == 0: + return + result.add data + +proc write*(f: AsyncFile, data: string): Future[void] = + ## Writes ``data`` to the file specified asynchronously. + ## + ## The returned Future will complete once all data has been written to the + ## specified file. + var retFuture = newFuture[void]("asyncfile.write") + var copy = data + when defined(windows): + var buffer = alloc0(data.len) + copyMem(buffer, addr copy[0], data.len) + + var ol = PCustomOverlapped() + GC_ref(ol) + ol.data = TCompletionData(fd: f.fd, cb: + proc (fd: TAsyncFD, bytesCount: DWord, errcode: OSErrorCode) = + if not retFuture.finished: + if errcode == OSErrorCode(-1): + assert bytesCount == data.len.int32 + f.offset.inc(data.len) + retFuture.complete() + else: + retFuture.fail(newException(OSError, osErrorMsg(errcode))) + if buffer != nil: + dealloc buffer + buffer = nil + ) + ol.offset = DWord(f.offset and 0xffffffff) + ol.offsetHigh = DWord(f.offset shr 32) + + # According to MSDN we're supposed to pass nil to lpNumberOfBytesWritten. + let ret = writeFile(f.fd.THandle, buffer, data.len.int32, nil, + cast[POVERLAPPED](ol)) + if not ret.bool: + let err = osLastError() + if err.int32 != ERROR_IO_PENDING: + if buffer != nil: + dealloc buffer + buffer = nil + GC_unref(ol) + retFuture.fail(newException(OSError, osErrorMsg(err))) + else: + # Request completed immediately. + var bytesWritten: DWord + let overlappedRes = getOverlappedResult(f.fd.THandle, + cast[POverlapped](ol)[], bytesWritten, false.WinBool) + if not overlappedRes.bool: + retFuture.fail(newException(OSError, osErrorMsg(osLastError()))) + else: + assert bytesWritten == data.len.int32 + f.offset.inc(data.len) + retFuture.complete() + else: + var written = 0 + + proc cb(fd: TAsyncFD): bool = + result = true + let remainderSize = data.len-written + let res = write(fd.cint, addr copy[written], remainderSize.cint) + if res < 0: + let lastError = osLastError() + if lastError.int32 != EAGAIN: + retFuture.fail(newException(EOS, osErrorMsg(lastError))) + else: + result = false # We still want this callback to be called. + else: + written.inc res + f.offset.inc res + if res != remainderSize: + result = false # We still have data to write. + else: + retFuture.complete() + + if not cb(f.fd): + addWrite(f.fd, cb) + return retFuture + +proc close*(f: AsyncFile) = + ## Closes the file specified. + when defined(windows): + if not closeHandle(f.fd.THandle).bool: + raiseOSError() + else: + if close(f.fd.cint) == -1: + raiseOSError() + diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index f1b1d1400..fc38dc31a 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -1,28 +1,46 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # See the file "copying.txt", included in this # distribution, for details about the copyright. # +## This module implement an asynchronous FTP client. +## +## Examples +## -------- +## +## .. code-block::nim +## +## var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") +## proc main(ftp: AsyncFtpClient) {.async.} = +## await ftp.connect() +## echo await ftp.pwd() +## echo await ftp.listDirs() +## await ftp.store("payload.jpg", "payload.jpg") +## await ftp.retrFile("payload.jpg", "payload2.jpg") +## echo("Finished") +## +## waitFor main(ftp) + import asyncdispatch, asyncnet, strutils, parseutils, os, times -from ftpclient import TFtpBase, EInvalidReply, TFtpEvent -from net import bufferSize +from ftpclient import FtpBaseObj, ReplyError, FtpEvent +from net import BufferSize type - TAsyncFtpClient* = TFtpBase[PAsyncSocket] - PAsyncFtpClient* = ref TAsyncFtpClient + AsyncFtpClientObj* = FtpBaseObj[AsyncSocket] + AsyncFtpClient* = ref AsyncFtpClientObj ProgressChangedProc* = proc (total, progress: BiggestInt, speed: float): - PFuture[void] {.closure, gcsafe.} + Future[void] {.closure, gcsafe.} -proc expectReply(ftp: PAsyncFtpClient): PFuture[TaintedString] = +proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] = result = ftp.csock.recvLine() -proc send*(ftp: PAsyncFtpClient, m: string): PFuture[TaintedString] {.async.} = +proc send*(ftp: AsyncFtpClient, m: string): Future[TaintedString] {.async.} = ## Send a message to the server, and wait for a primary reply. ## ``\c\L`` is added for you. await ftp.csock.send(m & "\c\L") @@ -31,11 +49,11 @@ proc send*(ftp: PAsyncFtpClient, m: string): PFuture[TaintedString] {.async.} = 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]) -proc pasv(ftp: PAsyncFtpClient) {.async.} = +proc pasv(ftp: AsyncFtpClient) {.async.} = ## Negotiate a data connection. ftp.dsock = newAsyncSocket() @@ -46,13 +64,13 @@ proc pasv(ftp: PAsyncFtpClient) {.async.} = var ip = nums[0.. -3] var port = nums[-2.. -1] var properPort = port[0].parseInt()*256+port[1].parseInt() - await ftp.dsock.connect(ip.join("."), TPort(properPort.toU16)) - ftp.dsockConnected = True + await ftp.dsock.connect(ip.join("."), Port(properPort.toU16)) + ftp.dsockConnected = true proc normalizePathSep(path: string): string = return replace(path, '\\', '/') -proc connect*(ftp: PAsyncFtpClient) {.async.} = +proc connect*(ftp: AsyncFtpClient) {.async.} = ## Connect to the FTP server specified by ``ftp``. await ftp.csock.connect(ftp.address, ftp.port) @@ -69,21 +87,21 @@ proc connect*(ftp: PAsyncFtpClient) {.async.} = if ftp.pass != "": assertReply(await(ftp.send("PASS " & ftp.pass)), "230") -proc pwd*(ftp: PAsyncFtpClient): PFuture[TaintedString] {.async.} = +proc pwd*(ftp: AsyncFtpClient): Future[TaintedString] {.async.} = ## Returns the current working directory. let wd = await ftp.send("PWD") assertReply wd, "257" return wd.string.captureBetween('"').TaintedString # " -proc cd*(ftp: PAsyncFtpClient, dir: string) {.async.} = +proc cd*(ftp: AsyncFtpClient, dir: string) {.async.} = ## Changes the current directory on the remote FTP server to ``dir``. assertReply(await(ftp.send("CWD " & dir.normalizePathSep)), "250") -proc cdup*(ftp: PAsyncFtpClient) {.async.} = +proc cdup*(ftp: AsyncFtpClient) {.async.} = ## Changes the current directory to the parent of the current directory. assertReply(await(ftp.send("CDUP")), "200") -proc getLines(ftp: PAsyncFtpClient): PFuture[string] {.async.} = +proc getLines(ftp: AsyncFtpClient): Future[string] {.async.} = ## Downloads text data in ASCII mode result = "" assert ftp.dsockConnected @@ -96,7 +114,7 @@ proc getLines(ftp: PAsyncFtpClient): PFuture[string] {.async.} = assertReply(await(ftp.expectReply()), "226") -proc listDirs*(ftp: PAsyncFtpClient, dir = ""): PFuture[seq[string]] {.async.} = +proc listDirs*(ftp: AsyncFtpClient, dir = ""): Future[seq[string]] {.async.} = ## Returns a list of filenames in the given directory. If ``dir`` is "", ## the current directory is used. If ``async`` is true, this ## function will return immediately and it will be your job to @@ -107,13 +125,13 @@ proc listDirs*(ftp: PAsyncFtpClient, dir = ""): PFuture[seq[string]] {.async.} = result = splitLines(await ftp.getLines()) -proc existsFile*(ftp: PAsyncFtpClient, file: string): PFuture[bool] {.async.} = +proc existsFile*(ftp: AsyncFtpClient, file: string): Future[bool] {.async.} = ## Determines whether ``file`` exists. var files = await ftp.listDirs() for f in items(files): if f.normalizePathSep == file.normalizePathSep: return true -proc createDir*(ftp: PAsyncFtpClient, dir: string, recursive = false){.async.} = +proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} = ## Creates a directory ``dir``. If ``recursive`` is true, the topmost ## subdirectory of ``dir`` will be created first, following the secondmost... ## etc. this allows you to give a full path as the ``dir`` without worrying @@ -123,14 +141,14 @@ proc createDir*(ftp: PAsyncFtpClient, dir: string, recursive = false){.async.} = else: var reply = TaintedString"" var previousDirs = "" - for p in split(dir, {os.dirSep, os.altSep}): + for p in split(dir, {os.DirSep, os.AltSep}): if p != "": previousDirs.add(p) reply = await ftp.send("MKD " & previousDirs) previousDirs.add('/') assertReply reply, "257" -proc chmod*(ftp: PAsyncFtpClient, path: string, +proc chmod*(ftp: AsyncFtpClient, path: string, permissions: set[TFilePermission]) {.async.} = ## Changes permission of ``path`` to ``permissions``. var userOctal = 0 @@ -152,7 +170,7 @@ proc chmod*(ftp: PAsyncFtpClient, path: string, assertReply(await(ftp.send("SITE CHMOD " & perm & " " & path.normalizePathSep)), "200") -proc list*(ftp: PAsyncFtpClient, dir = ""): PFuture[string] {.async.} = +proc list*(ftp: AsyncFtpClient, dir = ""): Future[string] {.async.} = ## Lists all files in ``dir``. If ``dir`` is ``""``, uses the current ## working directory. await ftp.pasv() @@ -162,7 +180,7 @@ proc list*(ftp: PAsyncFtpClient, dir = ""): PFuture[string] {.async.} = result = await ftp.getLines() -proc retrText*(ftp: PAsyncFtpClient, file: string): PFuture[string] {.async.} = +proc retrText*(ftp: AsyncFtpClient, file: string): Future[string] {.async.} = ## Retrieves ``file``. File must be ASCII text. await ftp.pasv() let reply = await ftp.send("RETR " & file.normalizePathSep) @@ -170,13 +188,13 @@ proc retrText*(ftp: PAsyncFtpClient, file: string): PFuture[string] {.async.} = result = await ftp.getLines() -proc getFile(ftp: PAsyncFtpClient, file: TFile, total: BiggestInt, +proc getFile(ftp: AsyncFtpClient, file: TFile, total: BiggestInt, onProgressChanged: ProgressChangedProc) {.async.} = assert ftp.dsockConnected var progress = 0 var progressInSecond = 0 var countdownFut = sleepAsync(1000) - var dataFut = ftp.dsock.recv(bufferSize) + var dataFut = ftp.dsock.recv(BufferSize) while ftp.dsockConnected: await dataFut or countdownFut if countdownFut.finished: @@ -191,20 +209,20 @@ proc getFile(ftp: PAsyncFtpClient, file: TFile, total: BiggestInt, progress.inc(data.len) progressInSecond.inc(data.len) file.write(data) - dataFut = ftp.dsock.recv(bufferSize) + dataFut = ftp.dsock.recv(BufferSize) else: - ftp.dsockConnected = False + ftp.dsockConnected = false assertReply(await(ftp.expectReply()), "226") proc defaultOnProgressChanged*(total, progress: BiggestInt, - speed: float): PFuture[void] {.nimcall,gcsafe.} = + speed: float): Future[void] {.nimcall,gcsafe.} = ## Default FTP ``onProgressChanged`` handler. Does nothing. result = newFuture[void]() #echo(total, " ", progress, " ", speed) result.complete() -proc retrFile*(ftp: PAsyncFtpClient, file, dest: string, +proc retrFile*(ftp: AsyncFtpClient, file, dest: string, onProgressChanged = defaultOnProgressChanged) {.async.} = ## Downloads ``file`` and saves it to ``dest``. ## The ``EvRetr`` event is passed to the specified ``handleEvent`` function @@ -215,14 +233,14 @@ proc retrFile*(ftp: PAsyncFtpClient, file, dest: string, var reply = await ftp.send("RETR " & file.normalizePathSep) assertReply reply, ["125", "150"] if {'(', ')'} notin reply.string: - raise newException(EInvalidReply, "Reply has no file size.") - var fileSize: biggestInt + 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.") await getFile(ftp, destFile, fileSize, onProgressChanged) -proc doUpload(ftp: PAsyncFtpClient, file: TFile, +proc doUpload(ftp: AsyncFtpClient, file: TFile, onProgressChanged: ProgressChangedProc) {.async.} = assert ftp.dsockConnected @@ -231,7 +249,7 @@ proc doUpload(ftp: PAsyncFtpClient, file: TFile, var progress = 0 var progressInSecond = 0 var countdownFut = sleepAsync(1000) - var sendFut: PFuture[void] = nil + var sendFut: Future[void] = nil while ftp.dsockConnected: if sendFut == nil or sendFut.finished: progress.inc(data.len) @@ -255,7 +273,7 @@ proc doUpload(ftp: PAsyncFtpClient, file: TFile, await countdownFut or sendFut -proc storeFile*(ftp: PAsyncFtpClient, file, dest: string, +proc store*(ftp: AsyncFtpClient, file, dest: string, onProgressChanged = defaultOnProgressChanged) {.async.} = ## Uploads ``file`` to ``dest`` on the remote FTP server. Usage of this ## function asynchronously is recommended to view the progress of @@ -271,9 +289,9 @@ proc storeFile*(ftp: PAsyncFtpClient, file, dest: string, await doUpload(ftp, destFile, onProgressChanged) -proc newAsyncFtpClient*(address: string, port = TPort(21), - user, pass = ""): PAsyncFtpClient = - ## Creates a new ``PAsyncFtpClient`` object. +proc newAsyncFtpClient*(address: string, port = Port(21), + user, pass = ""): AsyncFtpClient = + ## Creates a new ``AsyncFtpClient`` object. new result result.user = user result.pass = pass @@ -284,11 +302,11 @@ proc newAsyncFtpClient*(address: string, port = TPort(21), when isMainModule: var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test") - proc main(ftp: PAsyncFtpClient) {.async.} = + proc main(ftp: AsyncFtpClient) {.async.} = await ftp.connect() echo await ftp.pwd() echo await ftp.listDirs() - await ftp.storeFile("payload.jpg", "payload.jpg") + await ftp.store("payload.jpg", "payload.jpg") await ftp.retrFile("payload.jpg", "payload2.jpg") echo("Finished") diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index c8bd5cfc1..257fbaeb5 100644 --- a/lib/pure/asynchttpserver.nim +++ b/lib/pure/asynchttpserver.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # # See the file "copying.txt", included in this @@ -9,11 +9,24 @@ ## This module implements a high performance asynchronous HTTP server. ## -## **Note:** This module is still largely experimental. +## Examples +## -------- +## +## This example will create an HTTP server on port 8080. The server will +## respond to all requests with a ``200 OK`` response code and "Hello World" +## as the response body. +## +## .. code-block::nim +## var server = newAsyncHttpServer() +## proc cb(req: TRequest) {.async.} = +## await req.respond(Http200, "Hello World") +## +## asyncCheck server.serve(Port(8080), cb) +## runForever() import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils type - TRequest* = object + Request* = object client*: PAsyncSocket # TODO: Separate this into a Response object? reqMethod*: string headers*: PStringTable @@ -22,10 +35,10 @@ type hostname*: string ## The hostname of the client that made the request. body*: string - PAsyncHttpServer* = ref object + AsyncHttpServer* = ref object socket: PAsyncSocket - THttpCode* = enum + HttpCode* = enum Http200 = "200 OK", Http303 = "303 Moved", Http400 = "400 Bad Request", @@ -33,10 +46,13 @@ type Http500 = "500 Internal Server Error", Http502 = "502 Bad Gateway" - THttpVersion* = enum + HttpVersion* = enum HttpVer11, HttpVer10 +{.deprecated: [TRequest: Request, PAsyncHttpServer: AsyncHttpServer, + THttpCode: HttpCode, THttpVersion: HttpVersion].} + proc `==`*(protocol: tuple[orig: string, major, minor: int], ver: THttpVersion): bool = let major = @@ -49,13 +65,14 @@ proc `==`*(protocol: tuple[orig: string, major, minor: int], result = protocol.major == major and protocol.minor == minor proc newAsyncHttpServer*(): PAsyncHttpServer = + ## Creates a new ``AsyncHttpServer`` instance. new result proc addHeaders(msg: var string, headers: PStringTable) = for k, v in headers: msg.add(k & ": " & v & "\c\L") -proc sendHeaders*(req: TRequest, headers: PStringTable): PFuture[void] = +proc sendHeaders*(req: TRequest, headers: PStringTable): Future[void] = ## Sends the specified headers to the requesting client. var msg = "" addHeaders(msg, headers) @@ -93,13 +110,13 @@ proc parseProtocol(protocol: string): tuple[orig: string, major, minor: int] = i.inc # Skip . i.inc protocol.parseInt(result.minor, i) -proc sendStatus(client: PAsyncSocket, status: string): PFuture[void] = +proc sendStatus(client: PAsyncSocket, status: string): Future[void] = client.send("HTTP/1.1 " & status & "\c\L") proc processClient(client: PAsyncSocket, address: string, callback: proc (request: TRequest): - PFuture[void] {.closure, gcsafe.}) {.async.} = - while true: + Future[void] {.closure, gcsafe.}) {.async.} = + while not client.closed: # GET /path HTTP/1.1 # Header: val # \n @@ -180,12 +197,13 @@ proc processClient(client: PAsyncSocket, address: string, # header states otherwise. # In HTTP 1.0 we assume that the connection should not be persistent. # Unless the connection header states otherwise. + discard else: request.client.close() break -proc serve*(server: PAsyncHttpServer, port: TPort, - callback: proc (request: TRequest): PFuture[void] {.closure,gcsafe.}, +proc serve*(server: PAsyncHttpServer, port: Port, + callback: proc (request: TRequest): Future[void] {.closure,gcsafe.}, address = "") {.async.} = ## Starts the process of listening for incoming HTTP connections on the ## specified address and port. @@ -217,6 +235,6 @@ when isMainModule: "Content-type": "text/plain; charset=utf-8"} await req.respond(Http200, "Hello World", headers.newStringTable()) - asyncCheck server.serve(TPort(5555), cb) + asyncCheck server.serve(Port(5555), cb) runForever() main() diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim index 6b67bf4b5..bb0d29fc4 100644 --- a/lib/pure/asyncio.nim +++ b/lib/pure/asyncio.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf, Dominik Picheta # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -10,8 +10,8 @@ include "system/inclrtl" import sockets, os -## This module implements an asynchronous event loop together with asynchronous sockets -## which use this event loop. +## This module implements an asynchronous event loop together with asynchronous +## sockets which use this event loop. ## It is akin to Python's asyncore module. Many modules that use sockets ## have an implementation for this module, those modules should all have a ## ``register`` function which you should use to add the desired objects to a @@ -31,10 +31,10 @@ import sockets, os ## ## Most (if not all) modules that use asyncio provide a userArg which is passed ## on with the events. The type that you set userArg to must be inheriting from -## TObject! +## ``RootObj``! ## ## **Note:** If you want to provide async ability to your module please do not -## use the ``TDelegate`` object, instead use ``PAsyncSocket``. It is possible +## use the ``Delegate`` object, instead use ``AsyncSocket``. It is possible ## that in the future this type's fields will not be exported therefore breaking ## your code. ## @@ -44,10 +44,10 @@ import sockets, os ## Asynchronous sockets ## ==================== ## -## For most purposes you do not need to worry about the ``TDelegate`` type. The -## ``PAsyncSocket`` is what you are after. It's a reference to the ``TAsyncSocket`` -## object. This object defines events which you should overwrite by your own -## procedures. +## For most purposes you do not need to worry about the ``Delegate`` type. The +## ``AsyncSocket`` is what you are after. It's a reference to +## the ``AsyncSocketObj`` object. This object defines events which you should +## overwrite by your own procedures. ## ## For server sockets the only event you need to worry about is the ``handleAccept`` ## event, in your handleAccept proc you should call ``accept`` on the server @@ -57,13 +57,13 @@ import sockets, os ## ## An example ``handleAccept`` follows: ## -## .. code-block:: nimrod +## .. code-block:: nim ## -## var disp: PDispatcher = newDispatcher() +## var disp = newDispatcher() ## ... -## proc handleAccept(s: PAsyncSocket) = +## proc handleAccept(s: AsyncSocket) = ## echo("Accepted client.") -## var client: PAsyncSocket +## var client: AsyncSocket ## new(client) ## s.accept(client) ## client.handleRead = ... @@ -76,103 +76,111 @@ import sockets, os ## the socket has established a connection to a server socket; from that point ## it can be safely written to. ## -## Getting a blocking client from a PAsyncSocket +## Getting a blocking client from an AsyncSocket ## ============================================= ## ## If you need a asynchronous server socket but you wish to process the clients -## synchronously then you can use the ``getSocket`` converter to get a TSocket -## object from the PAsyncSocket object, this can then be combined with ``accept`` -## like so: +## synchronously then you can use the ``getSocket`` converter to get +## a ``Socket`` from the ``AsyncSocket`` object, this can then be combined +## with ``accept`` like so: ## -## .. code-block:: nimrod +## .. code-block:: nim ## -## proc handleAccept(s: PAsyncSocket) = -## var client: TSocket +## proc handleAccept(s: AsyncSocket) = +## var client: Socket ## getSocket(s).accept(client) when defined(windows): - from winlean import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select + from winlean import TimeVal, SocketHandle, fdSet, FD_ZERO, TFdSet, + fdSet, FD_ISSET, select else: - from posix import TTimeVal, TSocketHandle, TFdSet, FD_ZERO, FD_SET, FD_ISSET, select + from posix import TimeVal, SocketHandle, fdSet, FD_ZERO, TFdSet, + fdSet, FD_ISSET, select type - TDelegate* = object - fd*: TSocketHandle - deleVal*: PObject - - handleRead*: proc (h: PObject) {.nimcall, gcsafe.} - handleWrite*: proc (h: PObject) {.nimcall, gcsafe.} - handleError*: proc (h: PObject) {.nimcall, gcsafe.} - hasDataBuffered*: proc (h: PObject): bool {.nimcall, gcsafe.} + DelegateObj* = object + fd*: SocketHandle + deleVal*: RootRef + + handleRead*: proc (h: RootRef) {.nimcall, gcsafe.} + handleWrite*: proc (h: RootRef) {.nimcall, gcsafe.} + handleError*: proc (h: RootRef) {.nimcall, gcsafe.} + hasDataBuffered*: proc (h: RootRef): bool {.nimcall, gcsafe.} open*: bool - task*: proc (h: PObject) {.nimcall, gcsafe.} - mode*: TFileMode + task*: proc (h: RootRef) {.nimcall, gcsafe.} + mode*: FileMode - PDelegate* = ref TDelegate + Delegate* = ref DelegateObj - PDispatcher* = ref TDispatcher - TDispatcher = object - delegates: seq[PDelegate] + Dispatcher* = ref DispatcherObj + DispatcherObj = object + delegates: seq[Delegate] - PAsyncSocket* = ref TAsyncSocket - TAsyncSocket* = object of TObject - socket: TSocket - info: TInfo + AsyncSocket* = ref AsyncSocketObj + AsyncSocketObj* = object of RootObj + socket: Socket + info: SocketStatus - handleRead*: proc (s: PAsyncSocket) {.closure, gcsafe.} - handleWrite: proc (s: PAsyncSocket) {.closure, gcsafe.} - handleConnect*: proc (s: PAsyncSocket) {.closure, gcsafe.} + handleRead*: proc (s: AsyncSocket) {.closure, gcsafe.} + handleWrite: proc (s: AsyncSocket) {.closure, gcsafe.} + handleConnect*: proc (s: AsyncSocket) {.closure, gcsafe.} - handleAccept*: proc (s: PAsyncSocket) {.closure, gcsafe.} + handleAccept*: proc (s: AsyncSocket) {.closure, gcsafe.} - handleTask*: proc (s: PAsyncSocket) {.closure, gcsafe.} + handleTask*: proc (s: AsyncSocket) {.closure, gcsafe.} lineBuffer: TaintedString ## Temporary storage for ``readLine`` sendBuffer: string ## Temporary storage for ``send`` sslNeedAccept: bool - proto: TProtocol - deleg: PDelegate + proto: Protocol + deleg: Delegate - TInfo* = enum + SocketStatus* = enum SockIdle, SockConnecting, SockConnected, SockListening, SockClosed, SockUDPBound -proc newDelegate*(): PDelegate = +{.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate, + TInfo: SocketStatus, PAsyncSocket: AsyncSocket, TAsyncSocket: AsyncSocketObj, + TDispatcher: DispatcherObj, PDispatcher: Dispatcher, + ].} + + +proc newDelegate*(): Delegate = ## Creates a new delegate. new(result) - result.handleRead = (proc (h: PObject) = discard) - result.handleWrite = (proc (h: PObject) = discard) - result.handleError = (proc (h: PObject) = discard) - result.hasDataBuffered = (proc (h: PObject): bool = return false) - result.task = (proc (h: PObject) = discard) + result.handleRead = (proc (h: RootRef) = discard) + result.handleWrite = (proc (h: RootRef) = discard) + result.handleError = (proc (h: RootRef) = discard) + result.hasDataBuffered = (proc (h: RootRef): bool = return false) + result.task = (proc (h: RootRef) = discard) result.mode = fmRead -proc newAsyncSocket(): PAsyncSocket = +proc newAsyncSocket(): AsyncSocket = new(result) result.info = SockIdle - result.handleRead = (proc (s: PAsyncSocket) = discard) + result.handleRead = (proc (s: AsyncSocket) = discard) result.handleWrite = nil - result.handleConnect = (proc (s: PAsyncSocket) = discard) - result.handleAccept = (proc (s: PAsyncSocket) = discard) - result.handleTask = (proc (s: PAsyncSocket) = discard) + result.handleConnect = (proc (s: AsyncSocket) = discard) + result.handleAccept = (proc (s: AsyncSocket) = discard) + result.handleTask = (proc (s: AsyncSocket) = discard) result.lineBuffer = "".TaintedString result.sendBuffer = "" -proc asyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, - protocol: TProtocol = IPPROTO_TCP, - buffered = true): PAsyncSocket = +proc asyncSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP, + buffered = true): AsyncSocket = ## Initialises an AsyncSocket object. If a socket cannot be initialised ## EOS is raised. result = newAsyncSocket() result.socket = socket(domain, typ, protocol, buffered) result.proto = protocol - if result.socket == invalidSocket: osError(osLastError()) + if result.socket == invalidSocket: raiseOSError(osLastError()) result.socket.setBlocking(false) -proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket = +proc toAsyncSocket*(sock: Socket, state: SocketStatus = SockConnected): PAsyncSocket = ## Wraps an already initialized ``TSocket`` into a PAsyncSocket. ## This is useful if you want to use an already connected TSocket as an ## asynchronous PAsyncSocket in asyncio's event loop. @@ -203,57 +211,58 @@ proc toAsyncSocket*(sock: TSocket, state: TInfo = SockConnected): PAsyncSocket = result.socket.setBlocking(false) result.info = state -proc asyncSockHandleRead(h: PObject) = +proc asyncSockHandleRead(h: RootRef) = when defined(ssl): if PAsyncSocket(h).socket.isSSL and not PAsyncSocket(h).socket.gotHandshake: return - if PAsyncSocket(h).info != SockListening: - if PAsyncSocket(h).info != SockConnecting: - PAsyncSocket(h).handleRead(PAsyncSocket(h)) + if AsyncSocket(h).info != SockListening: + if AsyncSocket(h).info != SockConnecting: + AsyncSocket(h).handleRead(AsyncSocket(h)) else: - PAsyncSocket(h).handleAccept(PAsyncSocket(h)) + AsyncSocket(h).handleAccept(AsyncSocket(h)) -proc close*(sock: PAsyncSocket) {.gcsafe.} -proc asyncSockHandleWrite(h: PObject) = +proc close*(sock: AsyncSocket) {.gcsafe.} +proc asyncSockHandleWrite(h: RootRef) = when defined(ssl): if PAsyncSocket(h).socket.isSSL and not PAsyncSocket(h).socket.gotHandshake: return - if PAsyncSocket(h).info == SockConnecting: - PAsyncSocket(h).handleConnect(PAsyncSocket(h)) - PAsyncSocket(h).info = SockConnected + if AsyncSocket(h).info == SockConnecting: + AsyncSocket(h).handleConnect(AsyncSocket(h)) + AsyncSocket(h).info = SockConnected # Stop receiving write events if there is no handleWrite event. - if PAsyncSocket(h).handleWrite == nil: - PAsyncSocket(h).deleg.mode = fmRead + if AsyncSocket(h).handleWrite == nil: + AsyncSocket(h).deleg.mode = fmRead else: - PAsyncSocket(h).deleg.mode = fmReadWrite + AsyncSocket(h).deleg.mode = fmReadWrite else: - if PAsyncSocket(h).sendBuffer != "": - let sock = PAsyncSocket(h) + if AsyncSocket(h).sendBuffer != "": + let sock = AsyncSocket(h) try: let bytesSent = sock.socket.sendAsync(sock.sendBuffer) if bytesSent == 0: # Apparently the socket cannot be written to. Even though select # just told us that it can be... This used to be an assert. Just # do nothing instead. + discard elif bytesSent != sock.sendBuffer.len: sock.sendBuffer = sock.sendBuffer[bytesSent .. -1] elif bytesSent == sock.sendBuffer.len: sock.sendBuffer = "" - if PAsyncSocket(h).handleWrite != nil: - PAsyncSocket(h).handleWrite(PAsyncSocket(h)) - except EOS: + if AsyncSocket(h).handleWrite != nil: + AsyncSocket(h).handleWrite(AsyncSocket(h)) + except OSError: # Most likely the socket closed before the full buffer could be sent to it. sock.close() # TODO: Provide a handleError for users? else: - if PAsyncSocket(h).handleWrite != nil: - PAsyncSocket(h).handleWrite(PAsyncSocket(h)) + if AsyncSocket(h).handleWrite != nil: + AsyncSocket(h).handleWrite(AsyncSocket(h)) else: - PAsyncSocket(h).deleg.mode = fmRead + AsyncSocket(h).deleg.mode = fmRead when defined(ssl): proc asyncSockDoHandshake(h: PObject) {.gcsafe.} = @@ -270,13 +279,13 @@ when defined(ssl): discard PAsyncSocket(h).socket.handshake() -proc asyncSockTask(h: PObject) = +proc asyncSockTask(h: RootRef) = when defined(ssl): h.asyncSockDoHandshake() - PAsyncSocket(h).handleTask(PAsyncSocket(h)) + AsyncSocket(h).handleTask(AsyncSocket(h)) -proc toDelegate(sock: PAsyncSocket): PDelegate = +proc toDelegate(sock: AsyncSocket): Delegate = result = newDelegate() result.deleVal = sock result.fd = getFD(sock.socket) @@ -289,8 +298,8 @@ proc toDelegate(sock: PAsyncSocket): PDelegate = #result.handleError = (proc (h: PObject) = assert(false)) result.hasDataBuffered = - proc (h: PObject): bool {.nimcall.} = - return PAsyncSocket(h).socket.hasDataBuffered() + proc (h: RootRef): bool {.nimcall.} = + return AsyncSocket(h).socket.hasDataBuffered() sock.deleg = result if sock.info notin {SockIdle, SockClosed}: @@ -298,22 +307,22 @@ proc toDelegate(sock: PAsyncSocket): PDelegate = else: sock.deleg.open = false -proc connect*(sock: PAsyncSocket, name: string, port = TPort(0), - af: TDomain = AF_INET) = +proc connect*(sock: AsyncSocket, name: string, port = Port(0), + af: Domain = AF_INET) = ## Begins connecting ``sock`` to ``name``:``port``. sock.socket.connectAsync(name, port, af) sock.info = SockConnecting if sock.deleg != nil: sock.deleg.open = true -proc close*(sock: PAsyncSocket) = +proc close*(sock: AsyncSocket) = ## Closes ``sock``. Terminates any current connections. sock.socket.close() sock.info = SockClosed if sock.deleg != nil: sock.deleg.open = false -proc bindAddr*(sock: PAsyncSocket, port = TPort(0), address = "") = +proc bindAddr*(sock: AsyncSocket, port = Port(0), address = "") = ## Equivalent to ``sockets.bindAddr``. sock.socket.bindAddr(port, address) if sock.proto == IPPROTO_UDP: @@ -321,14 +330,14 @@ proc bindAddr*(sock: PAsyncSocket, port = TPort(0), address = "") = if sock.deleg != nil: sock.deleg.open = true -proc listen*(sock: PAsyncSocket) = +proc listen*(sock: AsyncSocket) = ## Equivalent to ``sockets.listen``. sock.socket.listen() sock.info = SockListening if sock.deleg != nil: sock.deleg.open = true -proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket, +proc acceptAddr*(server: AsyncSocket, client: var AsyncSocket, address: var string) = ## Equivalent to ``sockets.acceptAddr``. This procedure should be called in ## a ``handleAccept`` event handler **only** once. @@ -336,7 +345,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket, ## **Note**: ``client`` needs to be initialised. assert(client != nil) client = newAsyncSocket() - var c: TSocket + var c: Socket new(c) when defined(ssl): if server.socket.isSSL: @@ -359,7 +368,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket, client.sslNeedAccept = false client.info = SockConnected - if c == invalidSocket: socketError(server.socket) + if c == invalidSocket: raiseSocketError(server.socket) c.setBlocking(false) # TODO: Needs to be tested. # deleg.open is set in ``toDelegate``. @@ -369,12 +378,12 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket, client.sendBuffer = "" client.info = SockConnected -proc accept*(server: PAsyncSocket, client: var PAsyncSocket) = +proc accept*(server: AsyncSocket, client: var AsyncSocket) = ## Equivalent to ``sockets.accept``. var dummyAddr = "" server.acceptAddr(client, dummyAddr) -proc acceptAddr*(server: PAsyncSocket): tuple[sock: PAsyncSocket, +proc acceptAddr*(server: AsyncSocket): tuple[sock: AsyncSocket, address: string] {.deprecated.} = ## Equivalent to ``sockets.acceptAddr``. ## @@ -384,7 +393,7 @@ proc acceptAddr*(server: PAsyncSocket): tuple[sock: PAsyncSocket, acceptAddr(server, client, address) return (client, address) -proc accept*(server: PAsyncSocket): PAsyncSocket {.deprecated.} = +proc accept*(server: AsyncSocket): AsyncSocket {.deprecated.} = ## Equivalent to ``sockets.accept``. ## ## **Deprecated since version 0.9.0:** Please use the function above. @@ -392,54 +401,54 @@ proc accept*(server: PAsyncSocket): PAsyncSocket {.deprecated.} = var address = "" server.acceptAddr(result, address) -proc newDispatcher*(): PDispatcher = +proc newDispatcher*(): Dispatcher = new(result) result.delegates = @[] -proc register*(d: PDispatcher, deleg: PDelegate) = +proc register*(d: Dispatcher, deleg: Delegate) = ## Registers delegate ``deleg`` with dispatcher ``d``. d.delegates.add(deleg) -proc register*(d: PDispatcher, sock: PAsyncSocket): PDelegate {.discardable.} = +proc register*(d: Dispatcher, sock: AsyncSocket): Delegate {.discardable.} = ## Registers async socket ``sock`` with dispatcher ``d``. result = sock.toDelegate() d.register(result) -proc unregister*(d: PDispatcher, deleg: PDelegate) = +proc unregister*(d: Dispatcher, deleg: Delegate) = ## Unregisters deleg ``deleg`` from dispatcher ``d``. for i in 0..len(d.delegates)-1: if d.delegates[i] == deleg: d.delegates.del(i) return - raise newException(EInvalidIndex, "Could not find delegate.") + raise newException(IndexError, "Could not find delegate.") -proc isWriteable*(s: PAsyncSocket): bool = +proc isWriteable*(s: AsyncSocket): bool = ## Determines whether socket ``s`` is ready to be written to. var writeSock = @[s.socket] return selectWrite(writeSock, 1) != 0 and s.socket notin writeSock -converter getSocket*(s: PAsyncSocket): TSocket = +converter getSocket*(s: AsyncSocket): Socket = return s.socket -proc isConnected*(s: PAsyncSocket): bool = +proc isConnected*(s: AsyncSocket): bool = ## Determines whether ``s`` is connected. return s.info == SockConnected -proc isListening*(s: PAsyncSocket): bool = +proc isListening*(s: AsyncSocket): bool = ## Determines whether ``s`` is listening for incoming connections. return s.info == SockListening -proc isConnecting*(s: PAsyncSocket): bool = +proc isConnecting*(s: AsyncSocket): bool = ## Determines whether ``s`` is connecting. return s.info == SockConnecting -proc isClosed*(s: PAsyncSocket): bool = +proc isClosed*(s: AsyncSocket): bool = ## Determines whether ``s`` has been closed. return s.info == SockClosed -proc isSendDataBuffered*(s: PAsyncSocket): bool = +proc isSendDataBuffered*(s: AsyncSocket): bool = ## Determines whether ``s`` has data waiting to be sent, i.e. whether this ## socket's sendBuffer contains data. return s.sendBuffer.len != 0 -proc setHandleWrite*(s: PAsyncSocket, - handleWrite: proc (s: PAsyncSocket) {.closure, gcsafe.}) = +proc setHandleWrite*(s: AsyncSocket, + handleWrite: proc (s: AsyncSocket) {.closure, gcsafe.}) = ## Setter for the ``handleWrite`` event. ## ## To remove this event you should use the ``delHandleWrite`` function. @@ -449,12 +458,12 @@ proc setHandleWrite*(s: PAsyncSocket, s.deleg.mode = fmReadWrite s.handleWrite = handleWrite -proc delHandleWrite*(s: PAsyncSocket) = +proc delHandleWrite*(s: AsyncSocket) = ## Removes the ``handleWrite`` event handler on ``s``. s.handleWrite = nil {.push warning[deprecated]: off.} -proc recvLine*(s: PAsyncSocket, line: var TaintedString): bool {.deprecated.} = +proc recvLine*(s: AsyncSocket, line: var TaintedString): bool {.deprecated.} = ## Behaves similar to ``sockets.recvLine``, however it handles non-blocking ## sockets properly. This function guarantees that ``line`` is a full line, ## if this function can only retrieve some data; it will save this data and @@ -483,11 +492,11 @@ proc recvLine*(s: PAsyncSocket, line: var TaintedString): bool {.deprecated.} = of RecvDisconnected: result = true of RecvFail: - s.socketError(async = true) + s.raiseSocketError(async = true) result = false {.pop.} -proc readLine*(s: PAsyncSocket, line: var TaintedString): bool = +proc readLine*(s: AsyncSocket, line: var TaintedString): bool = ## Behaves similar to ``sockets.readLine``, however it handles non-blocking ## sockets properly. This function guarantees that ``line`` is a full line, ## if this function can only retrieve some data; it will save this data and @@ -517,7 +526,7 @@ proc readLine*(s: PAsyncSocket, line: var TaintedString): bool = of ReadDisconnected: result = true -proc send*(sock: PAsyncSocket, data: string) = +proc send*(sock: AsyncSocket, data: string) = ## Sends ``data`` to socket ``sock``. This is basically a nicer implementation ## of ``sockets.sendAsync``. ## @@ -537,19 +546,19 @@ proc send*(sock: PAsyncSocket, data: string) = sock.sendBuffer.add(data[bytesSent .. -1]) sock.deleg.mode = fmReadWrite -proc timeValFromMilliseconds(timeout = 500): TTimeVal = +proc timeValFromMilliseconds(timeout = 500): Timeval = if timeout != -1: var seconds = timeout div 1000 result.tv_sec = seconds.int32 result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 -proc createFdSet(fd: var TFdSet, s: seq[PDelegate], m: var int) = +proc createFdSet(fd: var TFdSet, s: seq[Delegate], m: var int) = FD_ZERO(fd) for i in items(s): m = max(m, int(i.fd)) - FD_SET(i.fd, fd) + fdSet(i.fd, fd) -proc pruneSocketSet(s: var seq[PDelegate], fd: var TFdSet) = +proc pruneSocketSet(s: var seq[Delegate], fd: var TFdSet) = var i = 0 var L = s.len while i < L: @@ -560,9 +569,9 @@ proc pruneSocketSet(s: var seq[PDelegate], fd: var TFdSet) = inc(i) setLen(s, L) -proc select(readfds, writefds, exceptfds: var seq[PDelegate], +proc select(readfds, writefds, exceptfds: var seq[Delegate], timeout = 500): int = - var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout) + var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) var rd, wr, ex: TFdSet var m = 0 @@ -579,7 +588,7 @@ proc select(readfds, writefds, exceptfds: var seq[PDelegate], pruneSocketSet(writefds, (wr)) pruneSocketSet(exceptfds, (ex)) -proc poll*(d: PDispatcher, timeout: int = 500): bool = +proc poll*(d: Dispatcher, timeout: int = 500): bool = ## This function checks for events on all the delegates in the `PDispatcher`. ## It then proceeds to call the correct event handler. ## @@ -592,7 +601,7 @@ proc poll*(d: PDispatcher, timeout: int = 500): bool = ## only be executed after one or more file descriptors becomes readable or ## writeable. result = true - var readDg, writeDg, errorDg: seq[PDelegate] = @[] + var readDg, writeDg, errorDg: seq[Delegate] = @[] var len = d.delegates.len var dc = 0 @@ -640,7 +649,7 @@ proc poll*(d: PDispatcher, timeout: int = 500): bool = for i in items(d.delegates): i.task(i.deleVal) -proc len*(disp: PDispatcher): int = +proc len*(disp: Dispatcher): int = ## Retrieves the amount of delegates in ``disp``. return disp.delegates.len @@ -674,7 +683,7 @@ when isMainModule: proc main = var d = newDispatcher() - var s = AsyncSocket() + var s = asyncSocket() s.connect("amber.tenthbit.net", TPort(6667)) s.handleConnect = proc (s: PAsyncSocket) = @@ -684,7 +693,7 @@ when isMainModule: testRead(s, 1) d.register(s) - var server = AsyncSocket() + var server = asyncSocket() server.handleAccept = proc (s: PAsyncSocket) = testAccept(s, d, 78) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 5095d9461..72fe51a7e 100644 --- a/lib/pure/asyncnet.nim +++ b/lib/pure/asyncnet.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # # See the file "copying.txt", included in this @@ -10,26 +10,39 @@ ## This module implements a high-level asynchronous sockets API based on the ## asynchronous dispatcher defined in the ``asyncdispatch`` module. ## -## Example -## ======= +## SSL +## --- +## +## SSL can be enabled by compiling with the ``-d:ssl`` flag. +## +## You must create a new SSL context with the ``newContext`` function defined +## in the ``net`` module. You may then call ``wrapSocket`` on your socket using +## the newly created SSL context to get an SSL socket. +## +## Examples +## -------- +## +## Chat server +## ^^^^^^^^^^^ ## ## The following example demonstrates a simple chat server. ## -## .. code-block::nimrod +## .. code-block::nim ## ## import asyncnet, asyncdispatch ## -## var clients: seq[PAsyncSocket] = @[] +## var clients {.threadvar.}: seq[AsyncSocket] ## -## proc processClient(client: PAsyncSocket) {.async.} = +## proc processClient(client: AsyncSocket) {.async.} = ## while true: ## let line = await client.recvLine() ## for c in clients: ## await c.send(line & "\c\L") ## ## proc serve() {.async.} = +## clients = @[] ## var server = newAsyncSocket() -## server.bindAddr(TPort(12345)) +## server.bindAddr(Port(12345)) ## server.listen() ## ## while true: @@ -41,12 +54,11 @@ ## asyncCheck serve() ## runForever() ## -## -## **Note:** This module is still largely experimental. import asyncdispatch import rawsockets import net +import os when defined(ssl): import openssl @@ -54,15 +66,33 @@ when defined(ssl): type # TODO: I would prefer to just do: # PAsyncSocket* {.borrow: `.`.} = distinct PSocket. But that doesn't work. - TAsyncSocket {.borrow: `.`.} = distinct TSocketImpl - PAsyncSocket* = ref TAsyncSocket + AsyncSocketDesc = object + fd*: SocketHandle + closed*: bool ## determines whether this socket has been closed + case isBuffered*: bool ## determines whether this socket is buffered. + of true: + buffer*: array[0..BufferSize, char] + currPos*: int # current index in buffer + bufLen*: int # current length of buffer + of false: nil + case isSsl: bool + of true: + when defined(ssl): + sslHandle: SslPtr + sslContext: SslContext + bioIn: BIO + bioOut: BIO + of false: nil + AsyncSocket* = ref AsyncSocketDesc + +{.deprecated: [PAsyncSocket: AsyncSocket].} # TODO: Save AF, domain etc info and reuse it in procs which need it like connect. proc newSocket(fd: TAsyncFD, isBuff: bool): PAsyncSocket = assert fd != osInvalidSocket.TAsyncFD - new(result.PSocket) - result.fd = fd.TSocketHandle + new(result) + result.fd = fd.SocketHandle result.isBuffered = isBuff if isBuff: result.currPos = 0 @@ -72,29 +102,114 @@ proc newAsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, ## Creates a new asynchronous socket. result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered) +proc newAsyncSocket*(domain, typ, protocol: cint, buffered = true): PAsyncSocket = + ## Creates a new asynchronous socket. + result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered) + +when defined(ssl): + proc getSslError(handle: SslPtr, err: cint): cint = + assert err < 0 + var ret = SSLGetError(handle, err.cint) + case ret + of SSL_ERROR_ZERO_RETURN: + raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: + return ret + of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ: + return ret + of SSL_ERROR_WANT_X509_LOOKUP: + raiseSSLError("Function for x509 lookup has been called.") + of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: + raiseSSLError() + else: raiseSSLError("Unknown Error") + + proc sendPendingSslData(socket: AsyncSocket, + flags: set[TSocketFlags]) {.async.} = + let len = bioCtrlPending(socket.bioOut) + if len > 0: + var data = newStringOfCap(len) + let read = bioRead(socket.bioOut, addr data[0], len) + assert read != 0 + if read < 0: + raiseSslError() + data.setLen(read) + await socket.fd.TAsyncFd.send(data, flags) + + proc appeaseSsl(socket: AsyncSocket, flags: set[TSocketFlags], + sslError: cint) {.async.} = + case sslError + of SSL_ERROR_WANT_WRITE: + await sendPendingSslData(socket, flags) + of SSL_ERROR_WANT_READ: + var data = await recv(socket.fd.TAsyncFD, BufferSize, flags) + let ret = bioWrite(socket.bioIn, addr data[0], data.len.cint) + if ret < 0: + raiseSSLError() + else: + raiseSSLError("Cannot appease SSL.") + + template sslLoop(socket: AsyncSocket, flags: set[TSocketFlags], + op: expr) = + var opResult {.inject.} = -1.cint + while opResult < 0: + opResult = op + # Bit hackish here. + # TODO: Introduce an async template transformation pragma? + yield sendPendingSslData(socket, flags) + if opResult < 0: + let err = getSslError(socket.sslHandle, opResult.cint) + yield appeaseSsl(socket, flags, err.cint) + proc connect*(socket: PAsyncSocket, address: string, port: TPort, - af = AF_INET): PFuture[void] = + af = AF_INET) {.async.} = ## Connects ``socket`` to server at ``address:port``. ## - ## Returns a ``PFuture`` which will complete when the connection succeeds + ## Returns a ``Future`` which will complete when the connection succeeds ## or an error occurs. - result = connect(socket.fd.TAsyncFD, address, port, af) + await connect(socket.fd.TAsyncFD, address, port, af) + let flags = {TSocketFlags.SafeDisconn} + if socket.isSsl: + when defined(ssl): + sslSetConnectState(socket.sslHandle) + sslLoop(socket, flags, sslDoHandshake(socket.sslHandle)) + +proc readInto(buf: cstring, size: int, socket: PAsyncSocket, + flags: set[TSocketFlags]): Future[int] {.async.} = + if socket.isSsl: + when defined(ssl): + # SSL mode. + sslLoop(socket, flags, + sslRead(socket.sslHandle, buf, size.cint)) + result = opResult + else: + var data = await recv(socket.fd.TAsyncFD, size, flags) + if data.len != 0: + copyMem(buf, addr data[0], data.len) + # Not in SSL mode. + result = data.len proc readIntoBuf(socket: PAsyncSocket, - flags: set[TSocketFlags]): PFuture[int] {.async.} = - var data = await recv(socket.fd.TAsyncFD, BufferSize, flags) - if data.len != 0: - copyMem(addr socket.buffer[0], addr data[0], data.len) - socket.bufLen = data.len + flags: set[TSocketFlags]): Future[int] {.async.} = + result = await readInto(addr socket.buffer[0], BufferSize, socket, flags) socket.currPos = 0 - result = data.len + socket.bufLen = result proc recv*(socket: PAsyncSocket, size: int, - flags = {TSocketFlags.SafeDisconn}): PFuture[string] {.async.} = - ## Reads ``size`` bytes from ``socket``. Returned future will complete once - ## all of the requested data is read. If socket is disconnected during the + flags = {TSocketFlags.SafeDisconn}): Future[string] {.async.} = + ## Reads **up to** ``size`` bytes from ``socket``. + ## + ## For buffered sockets this function will attempt to read all the requested + ## data. It will read this data in ``BufferSize`` chunks. + ## + ## For unbuffered sockets this function makes no effort to read + ## all the data requested. It will return as much data as the operating system + ## gives it. + ## + ## If socket is disconnected during the ## recv operation then the future may complete with only a part of the - ## requested data read. If socket is disconnected and no data is available + ## requested data. + ## + ## If socket is disconnected and no data is available ## to be read then the future will complete with a value of ``""``. if socket.isBuffered: result = newString(size) @@ -126,24 +241,33 @@ proc recv*(socket: PAsyncSocket, size: int, socket.currPos = originalBufPos result.setLen(read) else: - result = await recv(socket.fd.TAsyncFD, size, flags) + result = newString(size) + let read = await readInto(addr result[0], size, socket, flags) + result.setLen(read) proc send*(socket: PAsyncSocket, data: string, - flags = {TSocketFlags.SafeDisconn}): PFuture[void] = + flags = {TSocketFlags.SafeDisconn}) {.async.} = ## Sends ``data`` to ``socket``. The returned future will complete once all ## data has been sent. assert socket != nil - result = send(socket.fd.TAsyncFD, data, flags) + if socket.isSsl: + when defined(ssl): + var copy = data + sslLoop(socket, flags, + sslWrite(socket.sslHandle, addr copy[0], copy.len.cint)) + await sendPendingSslData(socket, flags) + else: + await send(socket.fd.TAsyncFD, data, flags) proc acceptAddr*(socket: PAsyncSocket, flags = {TSocketFlags.SafeDisconn}): - PFuture[tuple[address: string, client: PAsyncSocket]] = + Future[tuple[address: string, client: PAsyncSocket]] = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection and the remote address of the client. ## The future will complete when the connection is successfully accepted. var retFuture = newFuture[tuple[address: string, client: PAsyncSocket]]("asyncnet.acceptAddr") var fut = acceptAddr(socket.fd.TAsyncFD, flags) fut.callback = - proc (future: PFuture[tuple[address: string, client: TAsyncFD]]) = + proc (future: Future[tuple[address: string, client: TAsyncFD]]) = assert future.finished if future.failed: retFuture.fail(future.readError) @@ -154,14 +278,14 @@ proc acceptAddr*(socket: PAsyncSocket, flags = {TSocketFlags.SafeDisconn}): return retFuture proc accept*(socket: PAsyncSocket, - flags = {TSocketFlags.SafeDisconn}): PFuture[PAsyncSocket] = + flags = {TSocketFlags.SafeDisconn}): Future[PAsyncSocket] = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection. ## The future will complete when the connection is successfully accepted. var retFut = newFuture[PAsyncSocket]("asyncnet.accept") var fut = acceptAddr(socket, flags) fut.callback = - proc (future: PFuture[tuple[address: string, client: PAsyncSocket]]) = + proc (future: Future[tuple[address: string, client: PAsyncSocket]]) = assert future.finished if future.failed: retFut.fail(future.readError) @@ -170,7 +294,7 @@ proc accept*(socket: PAsyncSocket, return retFut proc recvLine*(socket: PAsyncSocket, - flags = {TSocketFlags.SafeDisconn}): PFuture[string] {.async.} = + flags = {TSocketFlags.SafeDisconn}): Future[string] {.async.} = ## Reads a line of data from ``socket``. Returned future will complete once ## a full line is read or an error occurs. ## @@ -185,6 +309,9 @@ proc recvLine*(socket: PAsyncSocket, ## The partial line **will be lost**. ## ## **Warning**: The ``Peek`` flag is not yet implemented. + ## + ## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol + ## uses ``\r\L`` to delimit a new line. template addNLIfEmpty(): stmt = if result.len == 0: result.add("\c\L") @@ -227,10 +354,8 @@ proc recvLine*(socket: PAsyncSocket, if c.len == 0: return "" if c == "\r": - c = await recv(socket, 1, flags + {TSocketFlags.Peek}) - if c.len > 0 and c == "\L": - let dummy = await recv(socket, 1, flags) - assert dummy == "\L" + c = await recv(socket, 1, flags) # Skip \L + assert c == "\L" addNLIfEmpty() return elif c == "\L": @@ -238,24 +363,68 @@ proc recvLine*(socket: PAsyncSocket, return add(result.string, c) -proc bindAddr*(socket: PAsyncSocket, port = TPort(0), address = "") = - ## Binds ``address``:``port`` to the socket. - ## - ## If ``address`` is "" then ADDR_ANY will be bound. - socket.PSocket.bindAddr(port, address) - -proc listen*(socket: PAsyncSocket, backlog = SOMAXCONN) = +proc listen*(socket: PAsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} = ## Marks ``socket`` as accepting connections. ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. ## ## Raises an EOS error upon failure. - socket.PSocket.listen(backlog) + if listen(socket.fd, backlog) < 0'i32: raiseOSError(osLastError()) + +proc bindAddr*(socket: PAsyncSocket, port = Port(0), address = "") {. + tags: [ReadIOEffect].} = + ## Binds ``address``:``port`` to the socket. + ## + ## If ``address`` is "" then ADDR_ANY will be bound. + + if address == "": + var name: Sockaddr_in + when defined(Windows) or defined(nimdoc): + name.sin_family = toInt(AF_INET).int16 + else: + name.sin_family = toInt(AF_INET) + name.sin_port = htons(int16(port)) + name.sin_addr.s_addr = htonl(INADDR_ANY) + if bindAddr(socket.fd, cast[ptr SockAddr](addr(name)), + sizeof(name).Socklen) < 0'i32: + raiseOSError(osLastError()) + else: + var aiList = getAddrInfo(address, port, AF_INET) + if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32: + dealloc(aiList) + raiseOSError(osLastError()) + dealloc(aiList) proc close*(socket: PAsyncSocket) = ## Closes the socket. socket.fd.TAsyncFD.closeSocket() - # TODO SSL + when defined(ssl): + if socket.isSSL: + let res = SslShutdown(socket.sslHandle) + if res == 0: + if SslShutdown(socket.sslHandle) != 1: + raiseSslError() + elif res != 1: + raiseSslError() + socket.closed = true # TODO: Add extra debugging checks for this. + +when defined(ssl): + proc wrapSocket*(ctx: SslContext, socket: AsyncSocket) = + ## Wraps a socket in an SSL context. This function effectively turns + ## ``socket`` into an SSL socket. + ## + ## **Disclaimer**: This code is not well tested, may be very unsafe and + ## prone to security vulnerabilities. + socket.isSsl = true + socket.sslContext = ctx + socket.sslHandle = SSLNew(PSSLCTX(socket.sslContext)) + if socket.sslHandle == nil: + raiseSslError() + + socket.bioIn = bioNew(bio_s_mem()) + socket.bioOut = bioNew(bio_s_mem()) + sslSetBio(socket.sslHandle, socket.bioIn, socket.bioOut) + when isMainModule: type @@ -280,23 +449,23 @@ when isMainModule: var sock = newAsyncSocket() var f = connect(sock, "irc.freenode.net", TPort(6667)) f.callback = - proc (future: PFuture[void]) = + proc (future: Future[void]) = echo("Connected in future!") for i in 0 .. 50: var recvF = recv(sock, 10) recvF.callback = - proc (future: PFuture[string]) = + proc (future: Future[string]) = echo("Read ", future.read.len, ": ", future.read.repr) elif test == LowServer: var sock = newAsyncSocket() sock.bindAddr(TPort(6667)) sock.listen() - proc onAccept(future: PFuture[PAsyncSocket]) = + proc onAccept(future: Future[PAsyncSocket]) = let client = future.read echo "Accepted ", client.fd.cint var t = send(client, "test\c\L") t.callback = - proc (future: PFuture[void]) = + proc (future: Future[void]) = echo("Send") client.close() diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 7b3b0e6f5..41d19dc0f 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.nim @@ -1,127 +1,128 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2010 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module implements a base64 encoder and decoder. - -const - cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" - -template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediate.} = - ## encodes `s` into base64 representation. After `lineLen` characters, a - ## `newline` is added. - var total = ((len(s) + 2) div 3) * 4 - var numLines = (total + lineLen - 1) div lineLen - if numLines > 0: inc(total, (numLines-1) * newLine.len) - - result = newString(total) - var i = 0 - var r = 0 - var currLine = 0 - while i < s.len - 2: - var a = ord(s[i]) - var b = ord(s[i+1]) - var c = ord(s[i+2]) - result[r] = cb64[a shr 2] - result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] - result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)] - result[r+3] = cb64[c and 0x3F] - inc(r, 4) - inc(i, 3) - inc(currLine, 4) - if currLine >= lineLen and i != s.len-2: - for x in items(newLine): - result[r] = x - inc(r) - currLine = 0 - - if i < s.len-1: - var a = ord(s[i]) - var b = ord(s[i+1]) - result[r] = cb64[a shr 2] - result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] - result[r+2] = cb64[((b and 0x0F) shl 2)] - result[r+3] = '=' - if r+4 != result.len: - setLen(result, r+4) - elif i < s.len: - var a = ord(s[i]) - result[r] = cb64[a shr 2] - result[r+1] = cb64[(a and 3) shl 4] - result[r+2] = '=' - result[r+3] = '=' - if r+4 != result.len: - setLen(result, r+4) - else: - #assert(r == result.len) - -proc encode*[T:TInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string = - ## encodes `s` into base64 representation. After `lineLen` characters, a - ## `newline` is added. - encodeInternal(s, lineLen, newLine) - -proc encode*(s: string, lineLen = 75, newLine="\13\10"): string = - ## encodes `s` into base64 representation. After `lineLen` characters, a - ## `newline` is added. - encodeInternal(s, lineLen, newLine) - -proc decodeByte(b: char): int {.inline.} = - case b - of '+': result = ord('>') - of '0'..'9': result = ord(b) + 4 - of 'A'..'Z': result = ord(b) - ord('A') - of 'a'..'z': result = ord(b) - 71 - else: result = 63 - -proc decode*(s: string): string = - ## decodes a string in base64 representation back into its original form. - ## Whitespace is skipped. - const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'} - var total = ((len(s) + 3) div 4) * 3 - # total is an upper bound, as we will skip arbitrary whitespace: - result = newString(total) - - var i = 0 - var r = 0 - while true: - while s[i] in Whitespace: inc(i) - if i < s.len-3: - var a = s[i].decodeByte - var b = s[i+1].decodeByte - var c = s[i+2].decodeByte - var d = s[i+3].decodeByte - - result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03)) - result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F)) - result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F)) - inc(r, 3) - inc(i, 4) - else: break - assert i == s.len - # adjust the length: - if i > 0 and s[i-1] == '=': - dec(r) - if i > 1 and s[i-2] == '=': dec(r) - setLen(result, r) - -when isMainModule: - assert encode("leasure.") == "bGVhc3VyZS4=" - assert encode("easure.") == "ZWFzdXJlLg==" - assert encode("asure.") == "YXN1cmUu" - assert encode("sure.") == "c3VyZS4=" - - const longText = """Man is distinguished, not only by his reason, but by this - singular passion from other animals, which is a lust of the mind, - that by a perseverance of delight in the continued and indefatigable - generation of knowledge, exceeds the short vehemence of any carnal - pleasure.""" - const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.", - "asure.", longText] - for t in items(tests): - assert decode(encode(t)) == t - +# +# +# Nim's Runtime Library +# (c) Copyright 2010 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements a base64 encoder and decoder. + +const + cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediate.} = + ## encodes `s` into base64 representation. After `lineLen` characters, a + ## `newline` is added. + var total = ((len(s) + 2) div 3) * 4 + var numLines = (total + lineLen - 1) div lineLen + if numLines > 0: inc(total, (numLines-1) * newLine.len) + + result = newString(total) + var i = 0 + var r = 0 + var currLine = 0 + while i < s.len - 2: + var a = ord(s[i]) + var b = ord(s[i+1]) + var c = ord(s[i+2]) + result[r] = cb64[a shr 2] + result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] + result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)] + result[r+3] = cb64[c and 0x3F] + inc(r, 4) + inc(i, 3) + inc(currLine, 4) + if currLine >= lineLen and i != s.len-2: + for x in items(newLine): + result[r] = x + inc(r) + currLine = 0 + + if i < s.len-1: + var a = ord(s[i]) + var b = ord(s[i+1]) + result[r] = cb64[a shr 2] + result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)] + result[r+2] = cb64[((b and 0x0F) shl 2)] + result[r+3] = '=' + if r+4 != result.len: + setLen(result, r+4) + elif i < s.len: + var a = ord(s[i]) + result[r] = cb64[a shr 2] + result[r+1] = cb64[(a and 3) shl 4] + result[r+2] = '=' + result[r+3] = '=' + if r+4 != result.len: + setLen(result, r+4) + else: + #assert(r == result.len) + discard + +proc encode*[T:SomeInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string = + ## encodes `s` into base64 representation. After `lineLen` characters, a + ## `newline` is added. + encodeInternal(s, lineLen, newLine) + +proc encode*(s: string, lineLen = 75, newLine="\13\10"): string = + ## encodes `s` into base64 representation. After `lineLen` characters, a + ## `newline` is added. + encodeInternal(s, lineLen, newLine) + +proc decodeByte(b: char): int {.inline.} = + case b + of '+': result = ord('>') + of '0'..'9': result = ord(b) + 4 + of 'A'..'Z': result = ord(b) - ord('A') + of 'a'..'z': result = ord(b) - 71 + else: result = 63 + +proc decode*(s: string): string = + ## decodes a string in base64 representation back into its original form. + ## Whitespace is skipped. + const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'} + var total = ((len(s) + 3) div 4) * 3 + # total is an upper bound, as we will skip arbitrary whitespace: + result = newString(total) + + var i = 0 + var r = 0 + while true: + while s[i] in Whitespace: inc(i) + if i < s.len-3: + var a = s[i].decodeByte + var b = s[i+1].decodeByte + var c = s[i+2].decodeByte + var d = s[i+3].decodeByte + + result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03)) + result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F)) + result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F)) + inc(r, 3) + inc(i, 4) + else: break + assert i == s.len + # adjust the length: + if i > 0 and s[i-1] == '=': + dec(r) + if i > 1 and s[i-2] == '=': dec(r) + setLen(result, r) + +when isMainModule: + assert encode("leasure.") == "bGVhc3VyZS4=" + assert encode("easure.") == "ZWFzdXJlLg==" + assert encode("asure.") == "YXN1cmUu" + assert encode("sure.") == "c3VyZS4=" + + const longText = """Man is distinguished, not only by his reason, but by this + singular passion from other animals, which is a lust of the mind, + that by a perseverance of delight in the continued and indefatigable + generation of knowledge, exceeds the short vehemence of any carnal + pleasure.""" + const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.", + "asure.", longText] + for t in items(tests): + assert decode(encode(t)) == t + diff --git a/lib/pure/basic2d.nim b/lib/pure/basic2d.nim index f8391a368..f2fc1566b 100644 --- a/lib/pure/basic2d.nim +++ b/lib/pure/basic2d.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Robert Persson # # See the file "copying.txt", included in this @@ -92,7 +92,7 @@ proc point2d*(x,y:float):TPoint2d {.noInit,inline.} let IDMATRIX*:TMatrix2d=matrix2d(1.0,0.0,0.0,1.0,0.0,0.0) ## Quick access to an identity matrix - ORIGO*:TPoint2d=Point2d(0.0,0.0) + ORIGO*:TPoint2d=point2d(0.0,0.0) ## Quick acces to point (0,0) XAXIS*:TVector2d=vector2d(1.0,0.0) ## Quick acces to an 2d x-axis unit vector @@ -212,7 +212,7 @@ proc mirror*(v:TVector2d):TMatrix2d {.noInit.} = xy2=v.x*v.y*2.0*nd sqd=nd*(sqx-sqy) - if nd==inf or nd==neginf: + if nd==Inf or nd==NegInf: return IDMATRIX #mirroring around a zero vector is arbitrary=>just use identity result.setElements( @@ -231,7 +231,7 @@ proc mirror*(org:TPoint2d,v:TVector2d):TMatrix2d {.noInit.} = xy2=v.x*v.y*2.0*nd sqd=nd*(sqx-sqy) - if nd==inf or nd==neginf: + if nd==Inf or nd==NegInf: return IDMATRIX #mirroring around a zero vector is arbitrary=>just use identity result.setElements( @@ -285,7 +285,7 @@ proc inverse*(m:TMatrix2d):TMatrix2d {.noInit.} = ## will be raised. let d=m.determinant if d==0.0: - raise newException(EDivByZero,"Cannot invert a zero determinant matrix") + raise newException(DivByZeroError,"Cannot invert a zero determinant matrix") result.setElements( m.by/d,-m.ay/d, @@ -360,7 +360,7 @@ proc `len=`*(v:var TVector2d,newlen:float) {.noInit.} = v.y=0.0 return - if fac==inf or fac==neginf: + if fac==Inf or fac==NegInf: #to short for float accuracy #do as good as possible: v.x=newlen @@ -431,7 +431,7 @@ proc normalize*(v:var TVector2d) {.inline.}= ## Modifies `v` to have a length of 1.0, keeping its angle. ## If `v` has zero length, an EDivByZero will be raised. if not tryNormalize(v): - raise newException(EDivByZero,"Cannot normalize zero length vector") + raise newException(DivByZeroError,"Cannot normalize zero length vector") proc transformNorm*(v:var TVector2d,t:TMatrix2d)= ## Applies a normal direction transformation `t` onto `v` in place. @@ -447,7 +447,7 @@ proc transformNorm*(v:var TVector2d,t:TMatrix2d)= # | | 0 0 1 | | let d=t.determinant if(d==0.0): - raise newException(EDivByZero,"Matrix is not invertible") + raise newException(DivByZeroError,"Matrix is not invertible") let newx = (t.by*v.x-t.ay*v.y)/d v.y = (t.ax*v.y-t.bx*v.x)/d v.x = newx @@ -461,7 +461,7 @@ proc transformInv*(v:var TVector2d,t:TMatrix2d)= let d=t.determinant if(d==0.0): - raise newException(EDivByZero,"Matrix is not invertible") + raise newException(DivByZeroError,"Matrix is not invertible") let newx=(t.by*v.x-t.bx*v.y)/d v.y = (t.ax*v.y-t.ay*v.x)/d @@ -531,7 +531,7 @@ proc mirror*(v:var TVector2d,mirrvec:TVector2d)= xy2=mirrvec.x*mirrvec.y*2.0*nd sqd=nd*(sqx-sqy) - if nd==inf or nd==neginf: + if nd==Inf or nd==NegInf: return #mirroring around a zero vector is arbitrary=>keep as is is fastest let newx=xy2*v.y+sqd*v.x @@ -703,7 +703,7 @@ proc transformInv*(p:var TPoint2d,t:TMatrix2d){.inline.}= # | TX TY 1 | let d=t.determinant if d==0.0: - raise newException(EDivByZero,"Cannot invert a zero determinant matrix") + raise newException(DivByZeroError,"Cannot invert a zero determinant matrix") let newx= (t.bx*t.ty-t.by*t.tx+p.x*t.by-p.y*t.bx)/d p.y = -(t.ax*t.ty-t.ay*t.tx+p.x*t.ay-p.y*t.ax)/d @@ -820,11 +820,11 @@ proc closestPoint*(p:TPoint2d,pts:varargs[TPoint2d]):TPoint2d= var bestidx=0 - bestdist=p.sqrdist(pts[0]) + bestdist=p.sqrDist(pts[0]) curdist:float for idx in 1..high(pts): - curdist=p.sqrdist(pts[idx]) + curdist=p.sqrDist(pts[idx]) if curdist<bestdist: bestidx=idx bestdist=curdist @@ -852,4 +852,4 @@ proc radToDeg*(rad:float):float {.inline.}= ## converts `rad` radians to degrees rad * RAD2DEGCONST - \ No newline at end of file + diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim index 540d53fd9..c00764fc5 100644 --- a/lib/pure/basic3d.nim +++ b/lib/pure/basic3d.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Robert Persson # # See the file "copying.txt", included in this @@ -220,7 +220,7 @@ proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}= var normax=axis if not normax.tryNormalize: #simplifies matrix computation below a lot - raise newException(EDivByZero,"Cannot rotate around zero length axis") + raise newException(DivByZeroError,"Cannot rotate around zero length axis") let cs=cos(angle) @@ -251,7 +251,7 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}= var normax=axis if not normax.tryNormalize: #simplifies matrix computation below a lot - raise newException(EDivByZero,"Cannot rotate around zero length axis") + raise newException(DivByZeroError,"Cannot rotate around zero length axis") let u=normax.x @@ -348,7 +348,7 @@ proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}= # https://en.wikipedia.org/wiki/Transformation_matrix var n=planeperp if not n.tryNormalize: - raise newException(EDivByZero,"Cannot mirror over a plane with a zero length normal") + raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal") let a=n.x @@ -375,7 +375,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}= # With some fiddling this becomes reasonably simple: var n=planeperp if not n.tryNormalize: - raise newException(EDivByZero,"Cannot mirror over a plane with a zero length normal") + raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal") let a=n.x @@ -448,7 +448,7 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}= O19=m.bx*m.cy-m.by*m.cx if det==0.0: - raise newException(EDivByZero,"Cannot normalize zero length vector") + raise newException(DivByZeroError,"Cannot normalize zero length vector") result.setElements( (m.bw*O4+m.by*O3-m.bz*O2)/det , (-m.aw*O4-m.ay*O3+m.az*O2)/det, @@ -537,7 +537,7 @@ proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)= # *************************************** # TVector3d implementation # *************************************** -proc Vector3d*(x,y,z:float):TVector3d= +proc vector3d*(x,y,z:float):TVector3d= result.x=x result.y=y result.z=z @@ -559,7 +559,7 @@ proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} = v.z=0.0 return - if fac==inf or fac==neginf: + if fac==Inf or fac==NegInf: #to short for float accuracy #do as good as possible: v.x=newlen @@ -670,7 +670,7 @@ proc normalize*(v:var TVector3d) {.inline.}= ## Modifies `v` to have a length of 1.0, keeping its angle. ## If `v` has zero length, an EDivByZero will be raised. if not tryNormalize(v): - raise newException(EDivByZero,"Cannot normalize zero length vector") + raise newException(DivByZeroError,"Cannot normalize zero length vector") proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)= ## Rotates `vec` in place, with `angle` radians over `axis`, which passes @@ -681,7 +681,7 @@ proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)= var normax=axis if not normax.tryNormalize: - raise newException(EDivByZero,"Cannot rotate around zero length axis") + raise newException(DivByZeroError,"Cannot rotate around zero length axis") let cs=cos(angle) @@ -842,9 +842,9 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}= # there are actually inifinitely many bisectors, we select just # one of them. result=v1.cross(XAXIS) - if result.sqrlen<1.0e-9: + if result.sqrLen<1.0e-9: result=v1.cross(YAXIS) - if result.sqrlen<1.0e-9: + if result.sqrLen<1.0e-9: result=v1.cross(ZAXIS) # now we should be guaranteed to have succeeded result.normalize @@ -853,7 +853,7 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}= # *************************************** # TPoint3d implementation # *************************************** -proc Point3d*(x,y,z:float):TPoint3d= +proc point3d*(x,y,z:float):TPoint3d= result.x=x result.y=y result.z=z diff --git a/lib/pure/browsers.nim b/lib/pure/browsers.nim index 3a8429f81..52035ee48 100644 --- a/lib/pure/browsers.nim +++ b/lib/pure/browsers.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -44,5 +44,5 @@ proc openDefaultBrowser*(url: string) = # we use ``startProcess`` here because we don't want to block! discard startProcess(command=b, args=[url], options={poUseShell}) return - except EOS: + except OSError: discard diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim index 31fb24eef..e8977b80b 100644 --- a/lib/pure/cgi.nim +++ b/lib/pure/cgi.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -9,7 +9,7 @@ ## This module implements helper procs for CGI applications. Example: ## -## .. code-block:: Nimrod +## .. code-block:: Nim ## ## import strtabs, cgi ## @@ -31,7 +31,7 @@ import strutils, os, strtabs, cookies -proc URLencode*(s: string): string = +proc encodeUrl*(s: string): string = ## Encodes a value to be HTTP safe: This means that characters in the set ## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result, ## a space is converted to ``'+'`` and every other character is encoded as @@ -52,7 +52,7 @@ proc handleHexChar(c: char, x: var int) {.inline.} = of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) else: assert(false) -proc URLdecode*(s: string): string = +proc decodeUrl*(s: string): string = ## Decodes a value from its HTTP representation: This means that a ``'+'`` ## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal ## value) is converted to the character with ordinal number ``xx``, and @@ -74,6 +74,8 @@ proc URLdecode*(s: string): string = inc(j) setLen(result, j) +{.deprecated: [URLDecode: decodeUrl, URLEncode: encodeUrl].} + proc addXmlChar(dest: var string, c: char) {.inline.} = case c of '&': add(dest, "&") @@ -82,7 +84,7 @@ proc addXmlChar(dest: var string, c: char) {.inline.} = of '\"': add(dest, """) else: add(dest, c) -proc XMLencode*(s: string): string = +proc xmlEncode*(s: string): string = ## Encodes a value to be XML safe: ## * ``"`` is replaced by ``"`` ## * ``<`` is replaced by ``<`` @@ -93,32 +95,35 @@ proc XMLencode*(s: string): string = for i in 0..len(s)-1: addXmlChar(result, s[i]) type - ECgi* = object of EIO ## the exception that is raised, if a CGI error occurs - TRequestMethod* = enum ## the used request method + CgiError* = object of IOError ## exception that is raised if a CGI error occurs + RequestMethod* = enum ## the used request method methodNone, ## no REQUEST_METHOD environment variable methodPost, ## query uses the POST method methodGet ## query uses the GET method +{.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError, + XMLencode: xmlEncode].} + proc cgiError*(msg: string) {.noreturn.} = ## raises an ECgi exception with message `msg`. - var e: ref ECgi + var e: ref CgiError new(e) e.msg = msg raise e -proc getEncodedData(allowedMethods: set[TRequestMethod]): string = - case getenv("REQUEST_METHOD").string +proc getEncodedData(allowedMethods: set[RequestMethod]): string = + case getEnv("REQUEST_METHOD").string of "POST": if methodPost notin allowedMethods: cgiError("'REQUEST_METHOD' 'POST' is not supported") - var L = parseInt(getenv("CONTENT_LENGTH").string) + var L = parseInt(getEnv("CONTENT_LENGTH").string) result = newString(L) if readBuffer(stdin, addr(result[0]), L) != L: cgiError("cannot read from stdin") of "GET": if methodGet notin allowedMethods: cgiError("'REQUEST_METHOD' 'GET' is not supported") - result = getenv("QUERY_STRING").string + result = getEnv("QUERY_STRING").string else: if methodNone notin allowedMethods: cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'") @@ -165,7 +170,7 @@ iterator decodeData*(data: string): tuple[key, value: TaintedString] = elif data[i] == '\0': break else: cgiError("'&' expected") -iterator decodeData*(allowedMethods: set[TRequestMethod] = +iterator decodeData*(allowedMethods: set[RequestMethod] = {methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] = ## Reads and decodes CGI data and yields the (name, value) pairs the ## data consists of. If the client does not use a method listed in the @@ -175,15 +180,15 @@ iterator decodeData*(allowedMethods: set[TRequestMethod] = for key, value in decodeData(data): yield (key, value) -proc readData*(allowedMethods: set[TRequestMethod] = - {methodNone, methodPost, methodGet}): PStringTable = +proc readData*(allowedMethods: set[RequestMethod] = + {methodNone, methodPost, methodGet}): StringTableRef = ## Read CGI data. If the client does not use a method listed in the ## `allowedMethods` set, an `ECgi` exception is raised. result = newStringTable() for name, value in decodeData(allowedMethods): result[name.string] = value.string -proc validateData*(data: PStringTable, validKeys: varargs[string]) = +proc validateData*(data: StringTableRef, validKeys: varargs[string]) = ## validates data; raises `ECgi` if this fails. This checks that each variable ## name of the CGI `data` occurs in the `validKeys` array. for key, val in pairs(data): @@ -192,155 +197,155 @@ proc validateData*(data: PStringTable, validKeys: varargs[string]) = proc getContentLength*(): string = ## returns contents of the ``CONTENT_LENGTH`` environment variable - return getenv("CONTENT_LENGTH").string + return getEnv("CONTENT_LENGTH").string proc getContentType*(): string = ## returns contents of the ``CONTENT_TYPE`` environment variable - return getenv("CONTENT_Type").string + return getEnv("CONTENT_Type").string proc getDocumentRoot*(): string = ## returns contents of the ``DOCUMENT_ROOT`` environment variable - return getenv("DOCUMENT_ROOT").string + return getEnv("DOCUMENT_ROOT").string proc getGatewayInterface*(): string = ## returns contents of the ``GATEWAY_INTERFACE`` environment variable - return getenv("GATEWAY_INTERFACE").string + return getEnv("GATEWAY_INTERFACE").string proc getHttpAccept*(): string = ## returns contents of the ``HTTP_ACCEPT`` environment variable - return getenv("HTTP_ACCEPT").string + return getEnv("HTTP_ACCEPT").string proc getHttpAcceptCharset*(): string = ## returns contents of the ``HTTP_ACCEPT_CHARSET`` environment variable - return getenv("HTTP_ACCEPT_CHARSET").string + return getEnv("HTTP_ACCEPT_CHARSET").string proc getHttpAcceptEncoding*(): string = ## returns contents of the ``HTTP_ACCEPT_ENCODING`` environment variable - return getenv("HTTP_ACCEPT_ENCODING").string + return getEnv("HTTP_ACCEPT_ENCODING").string proc getHttpAcceptLanguage*(): string = ## returns contents of the ``HTTP_ACCEPT_LANGUAGE`` environment variable - return getenv("HTTP_ACCEPT_LANGUAGE").string + return getEnv("HTTP_ACCEPT_LANGUAGE").string proc getHttpConnection*(): string = ## returns contents of the ``HTTP_CONNECTION`` environment variable - return getenv("HTTP_CONNECTION").string + return getEnv("HTTP_CONNECTION").string proc getHttpCookie*(): string = ## returns contents of the ``HTTP_COOKIE`` environment variable - return getenv("HTTP_COOKIE").string + return getEnv("HTTP_COOKIE").string proc getHttpHost*(): string = ## returns contents of the ``HTTP_HOST`` environment variable - return getenv("HTTP_HOST").string + return getEnv("HTTP_HOST").string proc getHttpReferer*(): string = ## returns contents of the ``HTTP_REFERER`` environment variable - return getenv("HTTP_REFERER").string + return getEnv("HTTP_REFERER").string proc getHttpUserAgent*(): string = ## returns contents of the ``HTTP_USER_AGENT`` environment variable - return getenv("HTTP_USER_AGENT").string + return getEnv("HTTP_USER_AGENT").string proc getPathInfo*(): string = ## returns contents of the ``PATH_INFO`` environment variable - return getenv("PATH_INFO").string + return getEnv("PATH_INFO").string proc getPathTranslated*(): string = ## returns contents of the ``PATH_TRANSLATED`` environment variable - return getenv("PATH_TRANSLATED").string + return getEnv("PATH_TRANSLATED").string proc getQueryString*(): string = ## returns contents of the ``QUERY_STRING`` environment variable - return getenv("QUERY_STRING").string + return getEnv("QUERY_STRING").string proc getRemoteAddr*(): string = ## returns contents of the ``REMOTE_ADDR`` environment variable - return getenv("REMOTE_ADDR").string + return getEnv("REMOTE_ADDR").string proc getRemoteHost*(): string = ## returns contents of the ``REMOTE_HOST`` environment variable - return getenv("REMOTE_HOST").string + return getEnv("REMOTE_HOST").string proc getRemoteIdent*(): string = ## returns contents of the ``REMOTE_IDENT`` environment variable - return getenv("REMOTE_IDENT").string + return getEnv("REMOTE_IDENT").string proc getRemotePort*(): string = ## returns contents of the ``REMOTE_PORT`` environment variable - return getenv("REMOTE_PORT").string + return getEnv("REMOTE_PORT").string proc getRemoteUser*(): string = ## returns contents of the ``REMOTE_USER`` environment variable - return getenv("REMOTE_USER").string + return getEnv("REMOTE_USER").string proc getRequestMethod*(): string = ## returns contents of the ``REQUEST_METHOD`` environment variable - return getenv("REQUEST_METHOD").string + return getEnv("REQUEST_METHOD").string proc getRequestURI*(): string = ## returns contents of the ``REQUEST_URI`` environment variable - return getenv("REQUEST_URI").string + return getEnv("REQUEST_URI").string proc getScriptFilename*(): string = ## returns contents of the ``SCRIPT_FILENAME`` environment variable - return getenv("SCRIPT_FILENAME").string + return getEnv("SCRIPT_FILENAME").string proc getScriptName*(): string = ## returns contents of the ``SCRIPT_NAME`` environment variable - return getenv("SCRIPT_NAME").string + return getEnv("SCRIPT_NAME").string proc getServerAddr*(): string = ## returns contents of the ``SERVER_ADDR`` environment variable - return getenv("SERVER_ADDR").string + return getEnv("SERVER_ADDR").string proc getServerAdmin*(): string = ## returns contents of the ``SERVER_ADMIN`` environment variable - return getenv("SERVER_ADMIN").string + return getEnv("SERVER_ADMIN").string proc getServerName*(): string = ## returns contents of the ``SERVER_NAME`` environment variable - return getenv("SERVER_NAME").string + return getEnv("SERVER_NAME").string proc getServerPort*(): string = ## returns contents of the ``SERVER_PORT`` environment variable - return getenv("SERVER_PORT").string + return getEnv("SERVER_PORT").string proc getServerProtocol*(): string = ## returns contents of the ``SERVER_PROTOCOL`` environment variable - return getenv("SERVER_PROTOCOL").string + return getEnv("SERVER_PROTOCOL").string proc getServerSignature*(): string = ## returns contents of the ``SERVER_SIGNATURE`` environment variable - return getenv("SERVER_SIGNATURE").string + return getEnv("SERVER_SIGNATURE").string proc getServerSoftware*(): string = ## returns contents of the ``SERVER_SOFTWARE`` environment variable - return getenv("SERVER_SOFTWARE").string + return getEnv("SERVER_SOFTWARE").string proc setTestData*(keysvalues: varargs[string]) = ## fills the appropriate environment variables to test your CGI application. ## This can only simulate the 'GET' request method. `keysvalues` should ## provide embedded (name, value)-pairs. Example: ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## setTestData("name", "Hanz", "password", "12345") - putenv("REQUEST_METHOD", "GET") + putEnv("REQUEST_METHOD", "GET") var i = 0 var query = "" while i < keysvalues.len: - add(query, URLencode(keysvalues[i])) + add(query, encodeUrl(keysvalues[i])) add(query, '=') - add(query, URLencode(keysvalues[i+1])) + add(query, encodeUrl(keysvalues[i+1])) add(query, '&') inc(i, 2) - putenv("QUERY_STRING", query) + putEnv("QUERY_STRING", query) proc writeContentType*() = ## call this before starting to send your HTML data to `stdout`. This ## implements this part of the CGI protocol: ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## write(stdout, "Content-type: text/html\n\n") write(stdout, "Content-type: text/html\n\n") @@ -364,11 +369,11 @@ proc writeErrorMessage*(data: string) = stdout.write(data) proc setStackTraceStdout*() = - ## Makes Nimrod output stacktraces to stdout, instead of server log. + ## Makes Nim output stacktraces to stdout, instead of server log. errorMessageWriter = writeErrorMessage proc setStackTraceNewLine*() {.deprecated.} = - ## Makes Nimrod output stacktraces to stdout, instead of server log. + ## Makes Nim output stacktraces to stdout, instead of server log. ## Depracated alias for setStackTraceStdout. setStackTraceStdout() @@ -377,7 +382,7 @@ proc setCookie*(name, value: string) = write(stdout, "Set-Cookie: ", name, "=", value, "\n") var - gcookies {.threadvar.}: PStringTable + gcookies {.threadvar.}: StringTableRef proc getCookie*(name: string): TaintedString = ## Gets a cookie. If no cookie of `name` exists, "" is returned. @@ -391,5 +396,5 @@ proc existsCookie*(name: string): bool = when isMainModule: const test1 = "abc\L+def xyz" - assert UrlEncode(test1) == "abc%0A%2Bdef+xyz" - assert UrlDecode(UrlEncode(test1)) == test1 + assert encodeUrl(test1) == "abc%0A%2Bdef+xyz" + assert decodeUrl(encodeUrl(test1)) == test1 diff --git a/lib/pure/collections/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim index b94b542ff..5640838b1 100644 --- a/lib/pure/collections/LockFreeHash.nim +++ b/lib/pure/collections/LockFreeHash.nim @@ -1,8 +1,40 @@ -#nimrod c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim +#nim c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim -import baseutils, unsigned, math, hashes +import unsigned, math, hashes +#------------------------------------------------------------------------------ +## Memory Utility Functions + +proc newHeap*[T](): ptr T = + result = cast[ptr T](alloc0(sizeof(T))) + +proc copyNew*[T](x: var T): ptr T = + var + size = sizeof(T) + mem = alloc(size) + copyMem(mem, x.addr, size) + return cast[ptr T](mem) + +proc copyTo*[T](val: var T, dest: int) = + copyMem(pointer(dest), val.addr, sizeof(T)) + +proc allocType*[T](): pointer = alloc(sizeof(T)) + +proc newShared*[T](): ptr T = + result = cast[ptr T](allocShared0(sizeof(T))) + +proc copyShared*[T](x: var T): ptr T = + var + size = sizeof(T) + mem = allocShared(size) + copyMem(mem, x.addr, size) + return cast[ptr T](mem) +#------------------------------------------------------------------------------ +## Pointer arithmetic + +proc `+`*(p: pointer, i: int): pointer {.inline.} = + cast[pointer](cast[int](p) + i) const minTableSize = 8 @@ -194,7 +226,7 @@ proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable #Prevent new values from appearing in the old table by priming oldVal = atomic_load_n(oldTbl[idx].value.addr, ATOMIC_RELAXED) while not isPrime(oldVal): - var box = if oldVal == NULL or isTomb(oldVal) : oldVal.setTomb.setPrime + var box = if oldVal == 0 or isTomb(oldVal) : oldVal.setTomb.setPrime else: oldVal.setPrime if atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr, box, false, ATOMIC_RELAXED, ATOMIC_RELAXED): @@ -209,8 +241,8 @@ proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable return false if isTomb(oldVal): echo("oldVal is Tomb!!!, should not happen") - if pop(oldVal) != NULL: - result = setVal(newTbl, pop(oldKey), pop(oldVal), NULL, true) == NULL + if pop(oldVal) != 0: + result = setVal(newTbl, pop(oldKey), pop(oldVal), 0, true) == 0 if result: #echo("Copied a Slot! idx= " & $idx & " key= " & $oldKey & " val= " & $oldVal) else: @@ -323,7 +355,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int, idx = idx and (table.len - 1) #echo("try set idx = " & $idx & "for" & $key) var - probedKey = NULL + probedKey = 0 openKey = atomic_compare_exchange_n(table[idx].key.addr, probedKey.addr, key, false, ATOMIC_RELAXED, ATOMIC_RELAXED) if openKey: @@ -339,7 +371,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int, if keyEQ[K](probedKey, key): #echo("we found the matching slot") break # We found a matching slot - if (not(expVal != NULL and match)) and (probes >= reProbeLimit or key.isTomb): + if (not(expVal != 0 and match)) and (probes >= reProbeLimit or key.isTomb): if key.isTomb: echo("Key is Tombstone") #if probes >= reProbeLimit: echo("Too much probing " & $probes) #echo("try to resize") @@ -361,7 +393,7 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int, return oldVal nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST) if nextTable == nil and - ((oldVal == NULL and + ((oldVal == 0 and (probes >= reProbeLimit or table.used / table.len > 0.8)) or (isPrime(oldVal))): if table.used / table.len > 0.8: echo("resize because usage ratio = " & @@ -380,12 +412,12 @@ proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int, if atomic_compare_exchange_n(table[idx].value.addr, oldVal.addr, val, false, ATOMIC_RELEASE, ATOMIC_RELAXED): #echo("val set at table " & $cast[int](table)) - if expVal != NULL: - if (oldVal == NULL or isTomb(oldVal)) and not isTomb(val): + if expVal != 0: + if (oldVal == 0 or isTomb(oldVal)) and not isTomb(val): discard atomic_add_fetch(table.active.addr, 1, ATOMIC_RELAXED) - elif not (oldVal == NULL or isTomb(oldVal)) and isTomb(val): + elif not (oldVal == 0 or isTomb(oldVal)) and isTomb(val): discard atomic_add_fetch(table.active.addr, -1, ATOMIC_RELAXED) - if oldVal == NULL and expVal != NULL: + if oldVal == 0 and expVal != 0: return setTomb(oldVal) else: return oldVal if isPrime(oldVal): @@ -415,7 +447,7 @@ proc getVal[K,V](table: var PConcTable[K,V], key: int): int = if not isPrime(val): if isTomb(val): #echo("val was tomb but not prime") - return NULL + return 0 else: #echo("-GotIt- idx = ", idx, " key = ", key, " val ", val ) return val @@ -427,7 +459,7 @@ proc getVal[K,V](table: var PConcTable[K,V], key: int): int = if probes >= reProbeLimit*4 or key.isTomb: if newTable == nil: #echo("too many probes and no new table ", key, " ", idx ) - return NULL + return 0 else: newTable = helpCopy(table) return getVal(newTable, key) @@ -437,10 +469,10 @@ proc getVal[K,V](table: var PConcTable[K,V], key: int): int = #------------------------------------------------------------------------------ #proc set*(table: var PConcTable[TRaw,TRaw], key: TRaw, val: TRaw) = -# discard setVal(table, pack(key), pack(key), NULL, false) +# discard setVal(table, pack(key), pack(key), 0, false) #proc set*[V](table: var PConcTable[TRaw,V], key: TRaw, val: ptr V) = -# discard setVal(table, pack(key), cast[int](val), NULL, false) +# discard setVal(table, pack(key), cast[int](val), 0, false) proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) = when not (K is TRaw): @@ -451,10 +483,10 @@ proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) = var newVal = cast[int](copyShared(val)) else: var newVal = pack(val) - var oldPtr = pop(setVal(table, newKey, newVal, NULL, false)) + var oldPtr = pop(setVal(table, newKey, newVal, 0, false)) #echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr)) when not (V is TRaw): - if newVal != oldPtr and oldPtr != NULL: + if newVal != oldPtr and oldPtr != 0: deallocShared(cast[ptr V](oldPtr)) @@ -573,10 +605,3 @@ when isMainModule: # echo(i, " = ", hashInt(i) and 8191) deleteConcTable(table) - - - - - - - diff --git a/lib/pure/collections/baseutils.nim b/lib/pure/collections/baseutils.nim deleted file mode 100644 index 565a89ccb..000000000 --- a/lib/pure/collections/baseutils.nim +++ /dev/null @@ -1,41 +0,0 @@ - - - -#------------------------------------------------------------------------------ -## Useful Constants -const NULL* = 0 - - -#------------------------------------------------------------------------------ -## Memory Utility Functions - -proc newHeap*[T](): ptr T = - result = cast[ptr T](alloc0(sizeof(T))) - -proc copyNew*[T](x: var T): ptr T = - var - size = sizeof(T) - mem = alloc(size) - copyMem(mem, x.addr, size) - return cast[ptr T](mem) - -proc copyTo*[T](val: var T, dest: int) = - copyMem(pointer(dest), val.addr, sizeof(T)) - -proc allocType*[T](): pointer = alloc(sizeof(T)) - -proc newShared*[T](): ptr T = - result = cast[ptr T](allocShared0(sizeof(T))) - -proc copyShared*[T](x: var T): ptr T = - var - size = sizeof(T) - mem = allocShared(size) - copyMem(mem, x.addr, size) - return cast[ptr T](mem) - -#------------------------------------------------------------------------------ -## Pointer arithmetic - -proc `+`*(p: pointer, i: int): pointer {.inline.} = - cast[pointer](cast[int](p) + i) \ No newline at end of file diff --git a/lib/pure/collections/critbits.nim b/lib/pure/collections/critbits.nim index 1fde1f419..8f506409b 100644 --- a/lib/pure/collections/critbits.nim +++ b/lib/pure/collections/critbits.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,30 +12,32 @@ ## by Adam Langley. type - TNode[T] = object {.pure, final, acyclic.} + NodeObj[T] = object {.pure, final, acyclic.} byte: int ## byte index of the difference otherbits: char case isLeaf: bool - of false: child: array[0..1, ref TNode[T]] + of false: child: array[0..1, ref NodeObj[T]] of true: key: string when T isnot void: val: T - PNode[T] = ref TNode[T] - TCritBitTree*[T] = object {. + Node[T] = ref NodeObj[T] + CritBitTree*[T] = object {. pure, final.} ## The crit bit tree can either be used ## as a mapping from strings to ## some type ``T`` or as a set of ## strings if ``T`` is void. - root: PNode[T] + root: Node[T] count: int - -proc len*[T](c: TCritBitTree[T]): int = + +{.deprecated: [TCritBitTree: CritBitTree].} + +proc len*[T](c: CritBitTree[T]): int = ## returns the number of elements in `c` in O(1). result = c.count -proc rawGet[T](c: TCritBitTree[T], key: string): PNode[T] = +proc rawGet[T](c: CritBitTree[T], key: string): Node[T] = var it = c.root while it != nil: if not it.isLeaf: @@ -45,15 +47,15 @@ proc rawGet[T](c: TCritBitTree[T], key: string): PNode[T] = else: return if it.key == key: it else: nil -proc contains*[T](c: TCritBitTree[T], key: string): bool {.inline.} = +proc contains*[T](c: CritBitTree[T], key: string): bool {.inline.} = ## returns true iff `c` contains the given `key`. result = rawGet(c, key) != nil -proc hasKey*[T](c: TCritBitTree[T], key: string): bool {.inline.} = +proc hasKey*[T](c: CritBitTree[T], key: string): bool {.inline.} = ## alias for `contains`. result = rawGet(c, key) != nil -proc rawInsert[T](c: var TCritBitTree[T], key: string): PNode[T] = +proc rawInsert[T](c: var CritBitTree[T], key: string): Node[T] = if c.root == nil: new c.root c.root.isleaf = true @@ -84,7 +86,7 @@ proc rawInsert[T](c: var TCritBitTree[T], key: string): PNode[T] = let ch = it.key[newByte] let dir = (1 + (ord(ch) or newOtherBits)) shr 8 - var inner: PNode[T] + var inner: Node[T] new inner new result result.isLeaf = true @@ -106,7 +108,7 @@ proc rawInsert[T](c: var TCritBitTree[T], key: string): PNode[T] = wherep[] = inner inc c.count -proc containsOrIncl*[T](c: var TCritBitTree[T], key: string, val: T): bool = +proc containsOrIncl*[T](c: var CritBitTree[T], key: string, val: T): bool = ## returns true iff `c` contains the given `key`. If the key does not exist ## ``c[key] = val`` is performed. let oldCount = c.count @@ -115,23 +117,23 @@ proc containsOrIncl*[T](c: var TCritBitTree[T], key: string, val: T): bool = when T isnot void: if not result: n.val = val -proc containsOrIncl*(c: var TCritBitTree[void], key: string): bool = +proc containsOrIncl*(c: var CritBitTree[void], key: string): bool = ## returns true iff `c` contains the given `key`. If the key does not exist ## it is inserted into `c`. let oldCount = c.count var n = rawInsert(c, key) result = c.count == oldCount -proc incl*(c: var TCritBitTree[void], key: string) = +proc incl*(c: var CritBitTree[void], key: string) = ## includes `key` in `c`. discard rawInsert(c, key) -proc `[]=`*[T](c: var TCritBitTree[T], key: string, val: T) = +proc `[]=`*[T](c: var CritBitTree[T], key: string, val: T) = ## puts a (key, value)-pair into `t`. var n = rawInsert(c, key) n.val = val -proc `[]`*[T](c: TCritBitTree[T], key: string): T {.inline.} = +proc `[]`*[T](c: CritBitTree[T], key: string): T {.inline.} = ## retrieves the value at ``c[key]``. If `key` is not in `t`, ## default empty value for the type `B` is returned ## and no exception is raised. One can check with ``hasKey`` whether the key @@ -139,22 +141,22 @@ proc `[]`*[T](c: TCritBitTree[T], key: string): T {.inline.} = let n = rawGet(c, key) if n != nil: result = n.val -proc mget*[T](c: var TCritBitTree[T], key: string): var T {.inline.} = +proc mget*[T](c: var CritBitTree[T], key: string): var T {.inline.} = ## retrieves the value at ``c[key]``. The value can be modified. - ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. + ## If `key` is not in `t`, the ``KeyError`` exception is raised. let n = rawGet(c, key) if n != nil: result = n.val - else: raise newException(EInvalidKey, "key not found: " & $key) + else: raise newException(KeyError, "key not found: " & $key) -proc excl*[T](c: var TCritBitTree[T], key: string) = +proc excl*[T](c: var CritBitTree[T], key: string) = ## removes `key` (and its associated value) from the set `c`. ## If the `key` does not exist, nothing happens. var p = c.root var wherep = addr(c.root) - var whereq: ptr PNode = nil + var whereq: ptr Node[T] = nil if p == nil: return var dir = 0 - var q: PNode + var q: Node[T] while not p.isLeaf: whereq = wherep q = p @@ -170,7 +172,7 @@ proc excl*[T](c: var TCritBitTree[T], key: string) = whereq[] = q.child[1 - dir] dec c.count -iterator leaves[T](n: PNode[T]): PNode[T] = +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). @@ -183,33 +185,33 @@ iterator leaves[T](n: PNode[T]): PNode[T] = assert(it != nil) yield it -iterator keys*[T](c: TCritBitTree[T]): string = +iterator keys*[T](c: CritBitTree[T]): string = ## yields all keys in lexicographical order. for x in leaves(c.root): yield x.key -iterator values*[T](c: TCritBitTree[T]): T = +iterator values*[T](c: CritBitTree[T]): T = ## yields all values of `c` in the lexicographical order of the ## corresponding keys. for x in leaves(c.root): yield x.val -iterator mvalues*[T](c: var TCritBitTree[T]): var T = +iterator mvalues*[T](c: var CritBitTree[T]): var T = ## yields all values of `c` in the lexicographical order of the ## corresponding keys. The values can be modified. for x in leaves(c.root): yield x.val -iterator items*[T](c: TCritBitTree[T]): string = +iterator items*[T](c: CritBitTree[T]): string = ## yields all keys in lexicographical order. for x in leaves(c.root): yield x.key -iterator pairs*[T](c: TCritBitTree[T]): tuple[key: string, val: T] = +iterator pairs*[T](c: CritBitTree[T]): tuple[key: string, val: T] = ## yields all (key, value)-pairs of `c`. for x in leaves(c.root): yield (x.key, x.val) -iterator mpairs*[T](c: var TCritBitTree[T]): tuple[key: string, val: var T] = +iterator mpairs*[T](c: var CritBitTree[T]): tuple[key: string, val: var T] = ## yields all (key, value)-pairs of `c`. The yielded values can be modified. for x in leaves(c.root): yield (x.key, x.val) -proc allprefixedAux[T](c: TCritBitTree[T], key: string): PNode[T] = +proc allprefixedAux[T](c: CritBitTree[T], key: string): Node[T] = var p = c.root var top = p if p != nil: @@ -223,42 +225,42 @@ proc allprefixedAux[T](c: TCritBitTree[T], key: string): PNode[T] = if p.key[i] != key[i]: return result = top -iterator itemsWithPrefix*[T](c: TCritBitTree[T], prefix: string): string = +iterator itemsWithPrefix*[T](c: CritBitTree[T], prefix: string): string = ## yields all keys starting with `prefix`. let top = allprefixedAux(c, prefix) for x in leaves(top): yield x.key -iterator keysWithPrefix*[T](c: TCritBitTree[T], prefix: string): string = +iterator keysWithPrefix*[T](c: CritBitTree[T], prefix: string): string = ## yields all keys starting with `prefix`. let top = allprefixedAux(c, prefix) for x in leaves(top): yield x.key -iterator valuesWithPrefix*[T](c: TCritBitTree[T], prefix: string): T = +iterator valuesWithPrefix*[T](c: CritBitTree[T], prefix: string): T = ## yields all values of `c` starting with `prefix` of the ## corresponding keys. let top = allprefixedAux(c, prefix) for x in leaves(top): yield x.val -iterator mvaluesWithPrefix*[T](c: var TCritBitTree[T], prefix: string): var T = +iterator mvaluesWithPrefix*[T](c: var CritBitTree[T], prefix: string): var T = ## yields all values of `c` starting with `prefix` of the ## corresponding keys. The values can be modified. let top = allprefixedAux(c, prefix) for x in leaves(top): yield x.val -iterator pairsWithPrefix*[T](c: TCritBitTree[T], +iterator pairsWithPrefix*[T](c: CritBitTree[T], prefix: string): tuple[key: string, val: T] = ## yields all (key, value)-pairs of `c` starting with `prefix`. let top = allprefixedAux(c, prefix) for x in leaves(top): yield (x.key, x.val) -iterator mpairsWithPrefix*[T](c: var TCritBitTree[T], +iterator mpairsWithPrefix*[T](c: var CritBitTree[T], prefix: string): tuple[key: string, val: var T] = ## yields all (key, value)-pairs of `c` starting with `prefix`. ## The yielded values can be modified. let top = allprefixedAux(c, prefix) for x in leaves(top): yield (x.key, x.val) -proc `$`*[T](c: TCritBitTree[T]): string = +proc `$`*[T](c: CritBitTree[T]): string = ## turns `c` into a string representation. Example outputs: ## ``{keyA: value, keyB: value}``, ``{:}`` ## If `T` is void the outputs look like: @@ -285,7 +287,7 @@ proc `$`*[T](c: TCritBitTree[T]): string = result.add("}") when isMainModule: - var r: TCritBitTree[void] + var r: CritBitTree[void] r.incl "abc" r.incl "xyz" r.incl "def" diff --git a/lib/pure/collections/intsets.nim b/lib/pure/collections/intsets.nim index f1e67fc0e..5d9c3f445 100644 --- a/lib/pure/collections/intsets.nim +++ b/lib/pure/collections/intsets.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -9,7 +9,7 @@ ## The ``intsets`` module implements an efficient int set implemented as a ## sparse bit set. -## **Note**: Since Nimrod currently does not allow the assignment operator to +## **Note**: Since Nim currently does not allow the assignment operator to ## be overloaded, ``=`` for int sets performs some rather meaningless shallow ## copy; use ``assign`` to get a deep copy. @@ -17,7 +17,7 @@ import os, hashes, math type - TBitScalar = int + BitScalar = int const InitIntSetSize = 8 # must be a power of two! @@ -25,8 +25,8 @@ const BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and # divisible by 64 TrunkMask = BitsPerTrunk - 1 - IntsPerTrunk = BitsPerTrunk div (sizeof(TBitScalar) * 8) - IntShift = 5 + ord(sizeof(TBitScalar) == 8) # 5 or 6, depending on int width + IntsPerTrunk = BitsPerTrunk div (sizeof(BitScalar) * 8) + IntShift = 5 + ord(sizeof(BitScalar) == 8) # 5 or 6, depending on int width IntMask = 1 shl IntShift - 1 type @@ -34,15 +34,16 @@ type TTrunk {.final.} = object next: PTrunk # all nodes are connected with this pointer key: int # start address at bit 0 - bits: array[0..IntsPerTrunk - 1, TBitScalar] # a bit vector + bits: array[0..IntsPerTrunk - 1, BitScalar] # a bit vector TTrunkSeq = seq[PTrunk] - TIntSet* {.final.} = object ## an efficient set of 'int' implemented as a - ## sparse bit set + IntSet* = object ## an efficient set of 'int' implemented as a sparse bit set counter, max: int head: PTrunk data: TTrunkSeq +{.deprecated: [TIntSet: IntSet].} + proc mustRehash(length, counter: int): bool {.inline.} = assert(length > counter) result = (length * 2 < counter * 3) or (length - counter < 4) @@ -50,7 +51,7 @@ proc mustRehash(length, counter: int): bool {.inline.} = proc nextTry(h, maxHash: THash): THash {.inline.} = result = ((5 * h) + 1) and maxHash -proc intSetGet(t: TIntSet, key: int): PTrunk = +proc intSetGet(t: IntSet, key: int): PTrunk = var h = key and t.max while t.data[h] != nil: if t.data[h].key == key: @@ -58,7 +59,7 @@ proc intSetGet(t: TIntSet, key: int): PTrunk = h = nextTry(h, t.max) result = nil -proc intSetRawInsert(t: TIntSet, data: var TTrunkSeq, desc: PTrunk) = +proc intSetRawInsert(t: IntSet, data: var TTrunkSeq, desc: PTrunk) = var h = desc.key and t.max while data[h] != nil: assert(data[h] != desc) @@ -66,7 +67,7 @@ proc intSetRawInsert(t: TIntSet, data: var TTrunkSeq, desc: PTrunk) = assert(data[h] == nil) data[h] = desc -proc intSetEnlarge(t: var TIntSet) = +proc intSetEnlarge(t: var IntSet) = var n: TTrunkSeq var oldMax = t.max t.max = ((t.max + 1) * 2) - 1 @@ -75,7 +76,7 @@ proc intSetEnlarge(t: var TIntSet) = if t.data[i] != nil: intSetRawInsert(t, n, t.data[i]) swap(t.data, n) -proc intSetPut(t: var TIntSet, key: int): PTrunk = +proc intSetPut(t: var IntSet, key: int): PTrunk = var h = key and t.max while t.data[h] != nil: if t.data[h].key == key: @@ -92,7 +93,7 @@ proc intSetPut(t: var TIntSet, key: int): PTrunk = t.head = result t.data[h] = result -proc contains*(s: TIntSet, key: int): bool = +proc contains*(s: IntSet, key: int): bool = ## returns true iff `key` is in `s`. var t = intSetGet(s, `shr`(key, TrunkShift)) if t != nil: @@ -101,14 +102,14 @@ proc contains*(s: TIntSet, key: int): bool = else: result = false -proc incl*(s: var TIntSet, key: int) = +proc incl*(s: var IntSet, key: int) = ## includes an element `key` in `s`. var t = intSetPut(s, `shr`(key, TrunkShift)) var u = key and TrunkMask t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or `shl`(1, u and IntMask) -proc excl*(s: var TIntSet, key: int) = +proc excl*(s: var IntSet, key: int) = ## excludes `key` from the set `s`. var t = intSetGet(s, `shr`(key, TrunkShift)) if t != nil: @@ -116,7 +117,7 @@ proc excl*(s: var TIntSet, key: int) = t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and not `shl`(1, u and IntMask) -proc containsOrIncl*(s: var TIntSet, key: int): bool = +proc containsOrIncl*(s: var IntSet, key: int): bool = ## returns true if `s` contains `key`, otherwise `key` is included in `s` ## and false is returned. var t = intSetGet(s, `shr`(key, TrunkShift)) @@ -130,14 +131,14 @@ proc containsOrIncl*(s: var TIntSet, key: int): bool = incl(s, key) result = false -proc initIntSet*: TIntSet = +proc initIntSet*: IntSet = ## creates a new int set that is empty. newSeq(result.data, InitIntSetSize) result.max = InitIntSetSize-1 result.counter = 0 result.head = nil -proc assign*(dest: var TIntSet, src: TIntSet) = +proc assign*(dest: var IntSet, src: IntSet) = ## copies `src` to `dest`. `dest` does not need to be initialized by ## `initIntSet`. dest.counter = src.counter @@ -161,7 +162,7 @@ proc assign*(dest: var TIntSet, src: TIntSet) = it = it.next -iterator items*(s: TIntSet): int {.inline.} = +iterator items*(s: IntSet): int {.inline.} = ## iterates over any included element of `s`. var r = s.head while r != nil: @@ -186,11 +187,11 @@ template dollarImpl(): stmt = result.add($key) result.add("}") -proc `$`*(s: TIntSet): string = +proc `$`*(s: IntSet): string = ## The `$` operator for int sets. dollarImpl() -proc empty*(s: TIntSet): bool {.inline.} = +proc empty*(s: IntSet): bool {.inline.} = ## returns true if `s` is empty. This is safe to call even before ## the set has been initialized with `initIntSet`. result = s.counter == 0 diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index b8f8d20b5..929de5973 100644 --- a/lib/pure/collections/lists.nim +++ b/lib/pure/collections/lists.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -15,52 +15,59 @@ when not defined(nimhygiene): {.pragma: dirty.} type - TDoublyLinkedNode* {.pure, - final.}[T] = object ## a node a doubly linked list consists of - next*, prev*: ref TDoublyLinkedNode[T] + DoublyLinkedNodeObj*[T] = object ## a node a doubly linked list consists of + next*, prev*: ref DoublyLinkedNodeObj[T] value*: T - PDoublyLinkedNode*[T] = ref TDoublyLinkedNode[T] + DoublyLinkedNode*[T] = ref DoublyLinkedNodeObj[T] - TSinglyLinkedNode* {.pure, - final.}[T] = object ## a node a singly linked list consists of - next*: ref TSinglyLinkedNode[T] + SinglyLinkedNodeObj*[T] = object ## a node a singly linked list consists of + next*: ref SinglyLinkedNodeObj[T] value*: T - PSinglyLinkedNode*[T] = ref TSinglyLinkedNode[T] + SinglyLinkedNode*[T] = ref SinglyLinkedNodeObj[T] - TSinglyLinkedList* {.pure, final.}[T] = object ## a singly linked list - head*, tail*: PSinglyLinkedNode[T] + SinglyLinkedList*[T] = object ## a singly linked list + head*, tail*: SinglyLinkedNode[T] - TDoublyLinkedList* {.pure, final.}[T] = object ## a doubly linked list - head*, tail*: PDoublyLinkedNode[T] + DoublyLinkedList*[T] = object ## a doubly linked list + head*, tail*: DoublyLinkedNode[T] - TSinglyLinkedRing* {.pure, final.}[T] = object ## a singly linked ring - head*: PSinglyLinkedNode[T] + SinglyLinkedRing*[T] = object ## a singly linked ring + head*: SinglyLinkedNode[T] - TDoublyLinkedRing* {.pure, final.}[T] = object ## a doubly linked ring - head*: PDoublyLinkedNode[T] - -proc initSinglyLinkedList*[T](): TSinglyLinkedList[T] = + DoublyLinkedRing*[T] = object ## a doubly linked ring + head*: DoublyLinkedNode[T] + +{.deprecated: [TDoublyLinkedNode: DoublyLinkedNodeObj, + PDoublyLinkedNode: DoublyLinkedNode, + TSinglyLinkedNode: SinglyLinkedNodeObj, + PSinglyLinkedNode: SinglyLinkedNode, + TDoublyLinkedList: DoublyLinkedList, + TSinglyLinkedRing: SinglyLinkedRing, + TDoublyLinkedRing: DoublyLinkedRing, + TSinglyLinkedList: SinglyLinkedList].} + +proc initSinglyLinkedList*[T](): SinglyLinkedList[T] = ## creates a new singly linked list that is empty. discard -proc initDoublyLinkedList*[T](): TDoublyLinkedList[T] = +proc initDoublyLinkedList*[T](): DoublyLinkedList[T] = ## creates a new doubly linked list that is empty. discard -proc initSinglyLinkedRing*[T](): TSinglyLinkedRing[T] = +proc initSinglyLinkedRing*[T](): SinglyLinkedRing[T] = ## creates a new singly linked ring that is empty. discard -proc initDoublyLinkedRing*[T](): TDoublyLinkedRing[T] = +proc initDoublyLinkedRing*[T](): DoublyLinkedRing[T] = ## creates a new doubly linked ring that is empty. discard -proc newDoublyLinkedNode*[T](value: T): PDoublyLinkedNode[T] = +proc newDoublyLinkedNode*[T](value: T): DoublyLinkedNode[T] = ## creates a new doubly linked node with the given `value`. new(result) result.value = value -proc newSinglyLinkedNode*[T](value: T): PSinglyLinkedNode[T] = +proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] = ## creates a new singly linked node with the given `value`. new(result) result.value = value @@ -99,38 +106,38 @@ template findImpl() {.dirty.} = for x in nodes(L): if x.value == value: return x -iterator items*[T](L: TDoublyLinkedList[T]): T = +iterator items*[T](L: DoublyLinkedList[T]): T = ## yields every value of `L`. itemsListImpl() -iterator items*[T](L: TSinglyLinkedList[T]): T = +iterator items*[T](L: SinglyLinkedList[T]): T = ## yields every value of `L`. itemsListImpl() -iterator items*[T](L: TSinglyLinkedRing[T]): T = +iterator items*[T](L: SinglyLinkedRing[T]): T = ## yields every value of `L`. itemsRingImpl() -iterator items*[T](L: TDoublyLinkedRing[T]): T = +iterator items*[T](L: DoublyLinkedRing[T]): T = ## yields every value of `L`. itemsRingImpl() -iterator nodes*[T](L: TSinglyLinkedList[T]): PSinglyLinkedNode[T] = +iterator nodes*[T](L: SinglyLinkedList[T]): SinglyLinkedNode[T] = ## iterates over every node of `x`. Removing the current node from the ## list during traversal is supported. nodesListImpl() -iterator nodes*[T](L: TDoublyLinkedList[T]): PDoublyLinkedNode[T] = +iterator nodes*[T](L: DoublyLinkedList[T]): DoublyLinkedNode[T] = ## iterates over every node of `x`. Removing the current node from the ## list during traversal is supported. nodesListImpl() -iterator nodes*[T](L: TSinglyLinkedRing[T]): PSinglyLinkedNode[T] = +iterator nodes*[T](L: SinglyLinkedRing[T]): SinglyLinkedNode[T] = ## iterates over every node of `x`. Removing the current node from the ## list during traversal is supported. nodesRingImpl() -iterator nodes*[T](L: TDoublyLinkedRing[T]): PDoublyLinkedNode[T] = +iterator nodes*[T](L: DoublyLinkedRing[T]): DoublyLinkedNode[T] = ## iterates over every node of `x`. Removing the current node from the ## list during traversal is supported. nodesRingImpl() @@ -142,73 +149,73 @@ template dollarImpl() {.dirty.} = result.add($x.value) result.add("]") -proc `$`*[T](L: TSinglyLinkedList[T]): string = +proc `$`*[T](L: SinglyLinkedList[T]): string = ## turns a list into its string representation. dollarImpl() -proc `$`*[T](L: TDoublyLinkedList[T]): string = +proc `$`*[T](L: DoublyLinkedList[T]): string = ## turns a list into its string representation. dollarImpl() -proc `$`*[T](L: TSinglyLinkedRing[T]): string = +proc `$`*[T](L: SinglyLinkedRing[T]): string = ## turns a list into its string representation. dollarImpl() -proc `$`*[T](L: TDoublyLinkedRing[T]): string = +proc `$`*[T](L: DoublyLinkedRing[T]): string = ## turns a list into its string representation. dollarImpl() -proc find*[T](L: TSinglyLinkedList[T], value: T): PSinglyLinkedNode[T] = +proc find*[T](L: SinglyLinkedList[T], value: T): SinglyLinkedNode[T] = ## searches in the list for a value. Returns nil if the value does not ## exist. findImpl() -proc find*[T](L: TDoublyLinkedList[T], value: T): PDoublyLinkedNode[T] = +proc find*[T](L: DoublyLinkedList[T], value: T): DoublyLinkedNode[T] = ## searches in the list for a value. Returns nil if the value does not ## exist. findImpl() -proc find*[T](L: TSinglyLinkedRing[T], value: T): PSinglyLinkedNode[T] = +proc find*[T](L: SinglyLinkedRing[T], value: T): SinglyLinkedNode[T] = ## searches in the list for a value. Returns nil if the value does not ## exist. findImpl() -proc find*[T](L: TDoublyLinkedRing[T], value: T): PDoublyLinkedNode[T] = +proc find*[T](L: DoublyLinkedRing[T], value: T): DoublyLinkedNode[T] = ## searches in the list for a value. Returns nil if the value does not ## exist. findImpl() -proc contains*[T](L: TSinglyLinkedList[T], value: T): bool {.inline.} = +proc contains*[T](L: SinglyLinkedList[T], value: T): bool {.inline.} = ## searches in the list for a value. Returns false if the value does not ## exist, true otherwise. result = find(L, value) != nil -proc contains*[T](L: TDoublyLinkedList[T], value: T): bool {.inline.} = +proc contains*[T](L: DoublyLinkedList[T], value: T): bool {.inline.} = ## searches in the list for a value. Returns false if the value does not ## exist, true otherwise. result = find(L, value) != nil -proc contains*[T](L: TSinglyLinkedRing[T], value: T): bool {.inline.} = +proc contains*[T](L: SinglyLinkedRing[T], value: T): bool {.inline.} = ## searches in the list for a value. Returns false if the value does not ## exist, true otherwise. result = find(L, value) != nil -proc contains*[T](L: TDoublyLinkedRing[T], value: T): bool {.inline.} = +proc contains*[T](L: DoublyLinkedRing[T], value: T): bool {.inline.} = ## searches in the list for a value. Returns false if the value does not ## exist, true otherwise. result = find(L, value) != nil -proc prepend*[T](L: var TSinglyLinkedList[T], - n: PSinglyLinkedNode[T]) {.inline.} = +proc prepend*[T](L: var SinglyLinkedList[T], + n: SinglyLinkedNode[T]) {.inline.} = ## prepends a node to `L`. Efficiency: O(1). n.next = L.head L.head = n -proc prepend*[T](L: var TSinglyLinkedList[T], value: T) {.inline.} = +proc prepend*[T](L: var SinglyLinkedList[T], value: T) {.inline.} = ## prepends a node to `L`. Efficiency: O(1). prepend(L, newSinglyLinkedNode(value)) -proc append*[T](L: var TDoublyLinkedList[T], n: PDoublyLinkedNode[T]) = +proc append*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## appends a node `n` to `L`. Efficiency: O(1). n.next = nil n.prev = L.tail @@ -218,11 +225,11 @@ proc append*[T](L: var TDoublyLinkedList[T], n: PDoublyLinkedNode[T]) = L.tail = n if L.head == nil: L.head = n -proc append*[T](L: var TDoublyLinkedList[T], value: T) = +proc append*[T](L: var DoublyLinkedList[T], value: T) = ## appends a value to `L`. Efficiency: O(1). append(L, newDoublyLinkedNode(value)) -proc prepend*[T](L: var TDoublyLinkedList[T], n: PDoublyLinkedNode[T]) = +proc prepend*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## prepends a node `n` to `L`. Efficiency: O(1). n.prev = nil n.next = L.head @@ -232,11 +239,11 @@ proc prepend*[T](L: var TDoublyLinkedList[T], n: PDoublyLinkedNode[T]) = L.head = n if L.tail == nil: L.tail = n -proc prepend*[T](L: var TDoublyLinkedList[T], value: T) = +proc prepend*[T](L: var DoublyLinkedList[T], value: T) = ## prepends a value to `L`. Efficiency: O(1). prepend(L, newDoublyLinkedNode(value)) -proc remove*[T](L: var TDoublyLinkedList[T], n: PDoublyLinkedNode[T]) = +proc remove*[T](L: var DoublyLinkedList[T], n: DoublyLinkedNode[T]) = ## removes `n` from `L`. Efficiency: O(1). if n == L.tail: L.tail = n.prev if n == L.head: L.head = n.next @@ -244,7 +251,7 @@ proc remove*[T](L: var TDoublyLinkedList[T], n: PDoublyLinkedNode[T]) = if n.prev != nil: n.prev.next = n.next -proc prepend*[T](L: var TSinglyLinkedRing[T], n: PSinglyLinkedNode[T]) = +proc prepend*[T](L: var SinglyLinkedRing[T], n: SinglyLinkedNode[T]) = ## prepends a node `n` to `L`. Efficiency: O(1). if L.head != nil: n.next = L.head @@ -253,11 +260,11 @@ proc prepend*[T](L: var TSinglyLinkedRing[T], n: PSinglyLinkedNode[T]) = n.next = n L.head = n -proc prepend*[T](L: var TSinglyLinkedRing[T], value: T) = +proc prepend*[T](L: var SinglyLinkedRing[T], value: T) = ## prepends a value to `L`. Efficiency: O(1). prepend(L, newSinglyLinkedNode(value)) -proc append*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) = +proc append*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = ## appends a node `n` to `L`. Efficiency: O(1). if L.head != nil: n.next = L.head @@ -269,11 +276,11 @@ proc append*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) = n.next = n L.head = n -proc append*[T](L: var TDoublyLinkedRing[T], value: T) = +proc append*[T](L: var DoublyLinkedRing[T], value: T) = ## appends a value to `L`. Efficiency: O(1). append(L, newDoublyLinkedNode(value)) -proc prepend*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) = +proc prepend*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = ## prepends a node `n` to `L`. Efficiency: O(1). if L.head != nil: n.next = L.head @@ -285,11 +292,11 @@ proc prepend*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) = n.next = n L.head = n -proc prepend*[T](L: var TDoublyLinkedRing[T], value: T) = +proc prepend*[T](L: var DoublyLinkedRing[T], value: T) = ## prepends a value to `L`. Efficiency: O(1). prepend(L, newDoublyLinkedNode(value)) -proc remove*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) = +proc remove*[T](L: var DoublyLinkedRing[T], n: DoublyLinkedNode[T]) = ## removes `n` from `L`. Efficiency: O(1). n.next.prev = n.prev n.prev.next = n.next @@ -300,5 +307,3 @@ proc remove*[T](L: var TDoublyLinkedRing[T], n: PDoublyLinkedNode[T]) = L.head = nil else: L.head = L.head.prev - - diff --git a/lib/pure/collections/queues.nim b/lib/pure/collections/queues.nim index 5481272f0..d1c94868a 100644 --- a/lib/pure/collections/queues.nim +++ b/lib/pure/collections/queues.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,13 +12,15 @@ import math type - TQueue* {.pure, final.}[T] = object ## a queue + Queue*[T] = object ## a queue data: seq[T] rd, wr, count, mask: int - + +{.deprecated: [TQueue: Queue].} + proc initQueue*[T](initialSize=4): TQueue[T] = ## creates a new queue. `initialSize` needs to be a power of 2. - assert IsPowerOfTwo(initialSize) + assert isPowerOfTwo(initialSize) result.mask = initialSize-1 newSeq(result.data, initialSize) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 2629e9f40..b824210a5 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2011 Alex Mitchell # # See the file "copying.txt", included in this @@ -31,7 +31,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] = ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let ## s1 = @[1, 2, 3] ## s2 = @[4, 5] @@ -50,7 +50,7 @@ proc concat*[T](seqs: varargs[seq[T]]): seq[T] = proc deduplicate*[T](seq1: seq[T]): seq[T] = ## Returns a new sequence without duplicates. ## - ## .. code-block:: nimrod + ## .. code-block:: ## let ## dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4] ## dup2 = @["a", "a", "c", "d", "d"] @@ -61,6 +61,8 @@ proc deduplicate*[T](seq1: seq[T]): seq[T] = result = @[] for itm in items(seq1): if not result.contains(itm): result.add(itm) + +{.deprecated: [distnct: deduplicate].} proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] = ## Returns a new sequence with a combination of the two input sequences. @@ -69,7 +71,7 @@ proc zip*[S, T](seq1: seq[S], seq2: seq[T]): seq[tuple[a: S, b: T]] = ## fields `a` and `b`. If one sequence is shorter, the remaining items in the ## longer sequence are discarded. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let ## short = @[1, 2, 3] ## long = @[6, 5, 4, 3, 2, 1] @@ -104,7 +106,7 @@ proc distribute*[T](s: seq[T], num: int, spread = true): seq[seq[T]] = ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let numbers = @[1, 2, 3, 4, 5, 6, 7] ## assert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]] ## assert numbers.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]] @@ -155,7 +157,7 @@ iterator filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): T = ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let numbers = @[1, 4, 5, 8, 9, 7, 4] ## for n in filter(numbers, proc (x: int): bool = x mod 2 == 0): ## echo($n) @@ -169,7 +171,7 @@ proc filter*[T](seq1: seq[T], pred: proc(item: T): bool {.closure.}): seq[T] = ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let ## colors = @["red", "yellow", "black"] ## f1 = filter(colors, proc(x: string): bool = x.len < 6) @@ -184,7 +186,7 @@ proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) = ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1] ## keepIf(floats, proc(x: float): bool = x > 10) ## assert floats == @[13.0, 12.5, 10.1] @@ -202,7 +204,7 @@ proc delete*[T](s: var seq[T], first=0, last=0) = ## ## Example: ## - ##.. code-block:: nimrod + ##.. code-block:: ## let outcome = @[1,1,1,1,1,1,1,1] ## var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1] ## dest.delete(3, 8) @@ -223,7 +225,7 @@ proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) = ## ## Example: ## - ##.. code-block:: nimrod + ##.. code-block:: ## var dest = @[1,1,1,1,1,1,1,1] ## let ## src = @[2,2,2,2,2,2] @@ -254,7 +256,7 @@ template filterIt*(seq1, pred: expr): expr {.immediate.} = ## the ``it`` variable for testing, like: ``filterIt("abcxyz", it == 'x')``. ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let ## temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44] ## acceptable = filterIt(temperatures, it < 50 and it > -10) @@ -273,7 +275,7 @@ template keepItIf*(varSeq, pred: expr) = ## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``. ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## var candidates = @["foo", "bar", "baz", "foobar"] ## keepItIf(candidates, it.len == 3 and it[0] == 'b') ## assert candidates == @["bar", "baz"] @@ -292,7 +294,7 @@ template toSeq*(iter: expr): expr {.immediate.} = ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let ## numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9] ## odd_numbers = toSeq(filter(numeric) do (x: int) -> bool: @@ -318,18 +320,18 @@ template foldl*(sequence, operation: expr): expr = ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) - ## 3). Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let ## numbers = @[5, 9, 11] ## addition = foldl(numbers, a + b) ## substraction = foldl(numbers, a - b) ## multiplication = foldl(numbers, a * b) - ## words = @["nim", "rod", "is", "cool"] + ## 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 multiplication == 495, "Multiplication is (((5)*9)*11)" - ## assert concatenation == "nimrodiscool" + ## assert concatenation == "nimiscool" assert sequence.len > 0, "Can't fold empty sequences" var result {.gensym.}: type(sequence[0]) result = sequence[0] @@ -354,18 +356,18 @@ template foldr*(sequence, operation: expr): expr = ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 - ## (3))). Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let ## numbers = @[5, 9, 11] ## addition = foldr(numbers, a + b) ## substraction = foldr(numbers, a - b) ## multiplication = foldr(numbers, a * b) - ## words = @["nim", "rod", "is", "cool"] + ## 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 multiplication == 495, "Multiplication is (5*(9*(11)))" - ## assert concatenation == "nimrodiscool" + ## assert concatenation == "nimiscool" assert sequence.len > 0, "Can't fold empty sequences" var result {.gensym.}: type(sequence[0]) result = sequence[sequence.len - 1] @@ -384,7 +386,7 @@ template mapIt*(seq1, typ, pred: expr): expr = ## since the new returned sequence can have a different type than the ## original. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let ## nums = @[1, 2, 3, 4] ## strings = nums.mapIt(string, $(4 * it)) @@ -401,7 +403,7 @@ template mapIt*(varSeq, pred: expr) = ## expression. The expression has to return the same type as the sequence you ## are mutating. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## var nums = @[1, 2, 3, 4] ## nums.mapIt(it * 3) ## assert nums[0] + nums[3] == 15 @@ -412,7 +414,7 @@ template mapIt*(varSeq, pred: expr) = template newSeqWith*(len: int, init: expr): expr = ## creates a new sequence, calling `init` to initialize each value. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## var seq2D = newSeqWith(20, newSeq[bool](10)) ## seq2D[0][0] = true ## seq2D[1][0] = true @@ -503,12 +505,12 @@ when isMainModule: addition = foldl(numbers, a + b) substraction = foldl(numbers, a - b) multiplication = foldl(numbers, a * b) - words = @["nim", "rod", "is", "cool"] + 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 multiplication == 495, "Multiplication is (((5)*9)*11)" - assert concatenation == "nimrodiscool" + assert concatenation == "nimiscool" block: # foldr tests let @@ -516,12 +518,12 @@ when isMainModule: addition = foldr(numbers, a + b) substraction = foldr(numbers, a - b) multiplication = foldr(numbers, a * b) - words = @["nim", "rod", "is", "cool"] + 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 multiplication == 495, "Multiplication is (5*(9*(11)))" - assert concatenation == "nimrodiscool" + assert concatenation == "nimiscool" block: # delete tests let outcome = @[1,1,1,1,1,1,1,1] diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim index ce901963e..92ef3152d 100644 --- a/lib/pure/collections/sets.nim +++ b/lib/pure/collections/sets.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -24,18 +24,20 @@ when not defined(nimhygiene): {.pragma: dirty.} type - TSlotEnum = enum seEmpty, seFilled, seDeleted - TKeyValuePair[A] = tuple[slot: TSlotEnum, key: A] - TKeyValuePairSeq[A] = seq[TKeyValuePair[A]] - TSet* {.final, myShallow.}[A] = object ## \ + SlotEnum = enum seEmpty, seFilled, seDeleted + KeyValuePair[A] = tuple[slot: SlotEnum, key: A] + KeyValuePairSeq[A] = seq[KeyValuePair[A]] + HashSet* {.myShallow.}[A] = object ## \ ## A generic hash set. ## - ## Use `init() <#init,TSet[A],int>`_ or `initSet[type]() <#initSet>`_ + ## Use `init() <#init,HashSet[A],int>`_ or `initSet[type]() <#initSet>`_ ## before calling other procs on it. - data: TKeyValuePairSeq[A] + data: KeyValuePairSeq[A] counter: int -proc isValid*[A](s: TSet[A]): bool = +{.deprecated: [TSet: HashSet].} + +proc isValid*[A](s: HashSet[A]): bool = ## Returns `true` if the set has been initialized with `initSet <#initSet>`_. ## ## Most operations over an uninitialized set will crash at runtime and @@ -43,13 +45,13 @@ proc isValid*[A](s: TSet[A]): bool = ## your own procs to verify that sets passed to your procs are correctly ## initialized. Example: ## - ## .. code-block :: nimrod + ## .. code-block :: ## proc savePreferences(options: TSet[string]) = ## assert options.isValid, "Pass an initialized set!" ## # Do stuff here, may crash in release builds! result = not s.data.isNil -proc len*[A](s: TSet[A]): int = +proc len*[A](s: HashSet[A]): int = ## Returns the number of keys in `s`. ## ## Due to an implementation detail you can call this proc on variables which @@ -63,14 +65,14 @@ proc len*[A](s: TSet[A]): int = ## assert values.len == 0 result = s.counter -proc card*[A](s: TSet[A]): int = +proc card*[A](s: HashSet[A]): int = ## Alias for `len() <#len,TSet[A]>`_. ## ## Card stands for the `cardinality ## <http://en.wikipedia.org/wiki/Cardinality>`_ of a set. result = s.counter -iterator items*[A](s: TSet[A]): A = +iterator items*[A](s: HashSet[A]): A = ## Iterates over keys in the set `s`. ## ## If you need a sequence with the keys you can use `sequtils.toSeq() @@ -118,10 +120,10 @@ template rawInsertImpl() {.dirty.} = data[h].key = key data[h].slot = seFilled -proc rawGet[A](s: TSet[A], key: A): int = +proc rawGet[A](s: HashSet[A], key: A): int = rawGetImpl() -proc mget*[A](s: var TSet[A], key: A): var A = +proc mget*[A](s: var HashSet[A], key: A): var A = ## returns the element that is actually stored in 's' which has the same ## value as 'key' or raises the ``EInvalidKey`` exception. This is useful ## when one overloaded 'hash' and '==' but still needs reference semantics @@ -129,9 +131,9 @@ proc mget*[A](s: var TSet[A], key: A): var A = assert s.isValid, "The set needs to be initialized." var index = rawGet(s, key) if index >= 0: result = s.data[index].key - else: raise newException(EInvalidKey, "key not found: " & $key) + else: raise newException(KeyError, "key not found: " & $key) -proc contains*[A](s: TSet[A], key: A): bool = +proc contains*[A](s: HashSet[A], key: A): bool = ## Returns true iff `key` is in `s`. ## ## Example: @@ -147,11 +149,11 @@ proc contains*[A](s: TSet[A], key: A): bool = var index = rawGet(s, key) result = index >= 0 -proc rawInsert[A](s: var TSet[A], data: var TKeyValuePairSeq[A], key: A) = +proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A) = rawInsertImpl() -proc enlarge[A](s: var TSet[A]) = - var n: TKeyValuePairSeq[A] +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) @@ -173,7 +175,7 @@ template containsOrInclImpl() {.dirty.} = rawInsert(s, s.data, key) inc(s.counter) -proc incl*[A](s: var TSet[A], key: A) = +proc incl*[A](s: var HashSet[A], key: A) = ## Includes an element `key` in `s`. ## ## This doesn't do anything if `key` is already in `s`. Example: @@ -186,7 +188,7 @@ proc incl*[A](s: var TSet[A], key: A) = assert s.isValid, "The set needs to be initialized." inclImpl() -proc incl*[A](s: var TSet[A], other: TSet[A]) = +proc incl*[A](s: var HashSet[A], other: HashSet[A]) = ## Includes all elements from `other` into `s`. ## ## Example: @@ -201,7 +203,7 @@ proc incl*[A](s: var TSet[A], other: TSet[A]) = assert other.isValid, "The set `other` needs to be initialized." for item in other: incl(s, item) -proc excl*[A](s: var TSet[A], key: A) = +proc excl*[A](s: var HashSet[A], key: A) = ## Excludes `key` from the set `s`. ## ## This doesn't do anything if `key` is not found in `s`. Example: @@ -217,7 +219,7 @@ proc excl*[A](s: var TSet[A], key: A) = s.data[index].slot = seDeleted dec(s.counter) -proc excl*[A](s: var TSet[A], other: TSet[A]) = +proc excl*[A](s: var HashSet[A], other: HashSet[A]) = ## Excludes everything in `other` from `s`. ## ## Example: @@ -233,7 +235,7 @@ proc excl*[A](s: var TSet[A], other: TSet[A]) = assert other.isValid, "The set `other` needs to be initialized." for item in other: excl(s, item) -proc containsOrIncl*[A](s: var TSet[A], key: A): bool = +proc containsOrIncl*[A](s: var HashSet[A], key: A): bool = ## Includes `key` in the set `s` and tells if `key` was added to `s`. ## ## The difference with regards to the `incl() <#incl,TSet[A],A>`_ proc is @@ -248,7 +250,7 @@ proc containsOrIncl*[A](s: var TSet[A], key: A): bool = assert s.isValid, "The set needs to be initialized." containsOrInclImpl() -proc init*[A](s: var TSet[A], initialSize=64) = +proc init*[A](s: var HashSet[A], initialSize=64) = ## Initializes a hash set. ## ## The `initialSize` parameter needs to be a power of too. You can use @@ -271,7 +273,7 @@ proc init*[A](s: var TSet[A], initialSize=64) = s.counter = 0 newSeq(s.data, initialSize) -proc initSet*[A](initialSize=64): TSet[A] = +proc initSet*[A](initialSize=64): HashSet[A] = ## Wrapper around `init() <#init,TSet[A],int>`_ for initialization of hash ## sets. ## @@ -283,7 +285,7 @@ proc initSet*[A](initialSize=64): TSet[A] = ## a.incl(2) result.init(initialSize) -proc toSet*[A](keys: openArray[A]): TSet[A] = +proc toSet*[A](keys: openArray[A]): HashSet[A] = ## Creates a new hash set that contains the given `keys`. ## ## Example: @@ -302,7 +304,7 @@ template dollarImpl(): stmt {.dirty.} = result.add($key) result.add("}") -proc `$`*[A](s: TSet[A]): string = +proc `$`*[A](s: HashSet[A]): string = ## Converts the set `s` to a string, mostly for logging purposes. ## ## Don't use this proc for serialization, the representation may change at @@ -318,7 +320,7 @@ proc `$`*[A](s: TSet[A]): string = assert s.isValid, "The set needs to be initialized." dollarImpl() -proc union*[A](s1, s2: TSet[A]): TSet[A] = +proc union*[A](s1, s2: HashSet[A]): HashSet[A] = ## Returns the union of the sets `s1` and `s2`. ## ## The union of two sets is represented mathematically as *A ∪ B* and is the @@ -335,7 +337,7 @@ proc union*[A](s1, s2: TSet[A]): TSet[A] = result = s1 incl(result, s2) -proc intersection*[A](s1, s2: TSet[A]): TSet[A] = +proc intersection*[A](s1, s2: HashSet[A]): HashSet[A] = ## Returns the intersection of the sets `s1` and `s2`. ## ## The intersection of two sets is represented mathematically as *A ∩ B* and @@ -354,7 +356,7 @@ proc intersection*[A](s1, s2: TSet[A]): TSet[A] = for item in s1: if item in s2: incl(result, item) -proc difference*[A](s1, s2: TSet[A]): TSet[A] = +proc difference*[A](s1, s2: HashSet[A]): HashSet[A] = ## Returns the difference of the sets `s1` and `s2`. ## ## The difference of two sets is represented mathematically as *A \ B* and is @@ -374,7 +376,7 @@ proc difference*[A](s1, s2: TSet[A]): TSet[A] = if not contains(s2, item): incl(result, item) -proc symmetricDifference*[A](s1, s2: TSet[A]): TSet[A] = +proc symmetricDifference*[A](s1, s2: HashSet[A]): HashSet[A] = ## Returns the symmetric difference of the sets `s1` and `s2`. ## ## The symmetric difference of two sets is represented mathematically as *A â–³ @@ -393,23 +395,23 @@ proc symmetricDifference*[A](s1, s2: TSet[A]): TSet[A] = for item in s2: if containsOrIncl(result, item): excl(result, item) -proc `+`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} = +proc `+`*[A](s1, s2: HashSet[A]): HashSet[A] {.inline.} = ## Alias for `union(s1, s2) <#union>`_. result = union(s1, s2) -proc `*`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} = +proc `*`*[A](s1, s2: HashSet[A]): HashSet[A] {.inline.} = ## Alias for `intersection(s1, s2) <#intersection>`_. result = intersection(s1, s2) -proc `-`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} = +proc `-`*[A](s1, s2: HashSet[A]): HashSet[A] {.inline.} = ## Alias for `difference(s1, s2) <#difference>`_. result = difference(s1, s2) -proc `-+-`*[A](s1, s2: TSet[A]): TSet[A] {.inline.} = +proc `-+-`*[A](s1, s2: HashSet[A]): HashSet[A] {.inline.} = ## Alias for `symmetricDifference(s1, s2) <#symmetricDifference>`_. result = symmetricDifference(s1, s2) -proc disjoint*[A](s1, s2: TSet[A]): bool = +proc disjoint*[A](s1, s2: HashSet[A]): bool = ## Returns true iff the sets `s1` and `s2` have no items in common. ## ## Example: @@ -426,7 +428,7 @@ proc disjoint*[A](s1, s2: TSet[A]): bool = if item in s2: return false return true -proc `<`*[A](s, t: TSet[A]): bool = +proc `<`*[A](s, t: HashSet[A]): bool = ## Returns true if `s` is a strict or proper subset of `t`. ## ## A strict or proper subset `s` has all of its members in `t` but `t` has @@ -441,7 +443,7 @@ proc `<`*[A](s, t: TSet[A]): bool = ## assert((a < a) == false) s.counter != t.counter and s <= t -proc `<=`*[A](s, t: TSet[A]): bool = +proc `<=`*[A](s, t: HashSet[A]): bool = ## Returns true if `s` is subset of `t`. ## ## A subset `s` has all of its members in `t` and `t` doesn't necessarily @@ -462,7 +464,7 @@ proc `<=`*[A](s, t: TSet[A]): bool = result = false return -proc `==`*[A](s, t: TSet[A]): bool = +proc `==`*[A](s, t: HashSet[A]): bool = ## Returns true if both `s` and `t` have the same members and set size. ## ## Example: @@ -475,7 +477,7 @@ proc `==`*[A](s, t: TSet[A]): bool = ## assert a == b s.counter == t.counter and s <= t -proc map*[A, B](data: TSet[A], op: proc (x: A): B {.closure.}): TSet[B] = +proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] = ## Returns a new set after applying `op` on each of the elements of `data`. ## ## You can use this proc to transform the elements from a set. Example: @@ -490,19 +492,20 @@ proc map*[A, B](data: TSet[A], op: proc (x: A): B {.closure.}): TSet[B] = # ------------------------------ ordered set ------------------------------ type - TOrderedKeyValuePair[A] = tuple[ - slot: TSlotEnum, next: int, key: A] - TOrderedKeyValuePairSeq[A] = seq[TOrderedKeyValuePair[A]] - TOrderedSet* {. - final, myShallow.}[A] = object ## \ + OrderedKeyValuePair[A] = tuple[ + slot: SlotEnum, next: int, key: A] + OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]] + OrderedSet* {.myShallow.}[A] = object ## \ ## A generic hash set that remembers insertion order. ## - ## Use `init() <#init,TOrderedSet[A],int>`_ or `initOrderedSet[type]() + ## Use `init() <#init,OrderedSet[A],int>`_ or `initOrderedSet[type]() ## <#initOrderedSet>`_ before calling other procs on it. - data: TOrderedKeyValuePairSeq[A] + data: OrderedKeyValuePairSeq[A] counter, first, last: int -proc isValid*[A](s: TOrderedSet[A]): bool = +{.deprecated: [TOrderedSet: OrderedSet].} + +proc isValid*[A](s: OrderedSet[A]): bool = ## Returns `true` if the ordered set has been initialized with `initSet ## <#initOrderedSet>`_. ## @@ -511,13 +514,13 @@ proc isValid*[A](s: TOrderedSet[A]): bool = ## in your own procs to verify that ordered sets passed to your procs are ## correctly initialized. Example: ## - ## .. code-block :: nimrod + ## .. code-block:: ## proc saveTarotCards(cards: TOrderedSet[int]) = ## assert cards.isValid, "Pass an initialized set!" ## # Do stuff here, may crash in release builds! result = not s.data.isNil -proc len*[A](s: TOrderedSet[A]): int {.inline.} = +proc len*[A](s: OrderedSet[A]): int {.inline.} = ## Returns the number of keys in `s`. ## ## Due to an implementation detail you can call this proc on variables which @@ -531,7 +534,7 @@ proc len*[A](s: TOrderedSet[A]): int {.inline.} = ## assert values.len == 0 result = s.counter -proc card*[A](s: TOrderedSet[A]): int {.inline.} = +proc card*[A](s: OrderedSet[A]): int {.inline.} = ## Alias for `len() <#len,TOrderedSet[A]>`_. ## ## Card stands for the `cardinality @@ -545,7 +548,7 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} = if s.data[h].slot == seFilled: yieldStmt h = nxt -iterator items*[A](s: TOrderedSet[A]): A = +iterator items*[A](s: OrderedSet[A]): A = ## Iterates over keys in the ordered set `s` in insertion order. ## ## If you need a sequence with the keys you can use `sequtils.toSeq() @@ -567,10 +570,10 @@ iterator items*[A](s: TOrderedSet[A]): A = forAllOrderedPairs: yield s.data[h].key -proc rawGet[A](s: TOrderedSet[A], key: A): int = +proc rawGet[A](s: OrderedSet[A], key: A): int = rawGetImpl() -proc contains*[A](s: TOrderedSet[A], key: A): bool = +proc contains*[A](s: OrderedSet[A], key: A): bool = ## Returns true iff `key` is in `s`. ## ## Example: @@ -584,16 +587,16 @@ proc contains*[A](s: TOrderedSet[A], key: A): bool = var index = rawGet(s, key) result = index >= 0 -proc rawInsert[A](s: var TOrderedSet[A], - data: var TOrderedKeyValuePairSeq[A], key: A) = +proc rawInsert[A](s: var OrderedSet[A], + data: var OrderedKeyValuePairSeq[A], key: A) = rawInsertImpl() data[h].next = -1 if s.first < 0: s.first = h if s.last >= 0: data[s.last].next = h s.last = h -proc enlarge[A](s: var TOrderedSet[A]) = - var n: TOrderedKeyValuePairSeq[A] +proc enlarge[A](s: var OrderedSet[A]) = + var n: OrderedKeyValuePairSeq[A] newSeq(n, len(s.data) * growthFactor) var h = s.first s.first = -1 @@ -605,7 +608,7 @@ proc enlarge[A](s: var TOrderedSet[A]) = h = nxt swap(s.data, n) -proc incl*[A](s: var TOrderedSet[A], key: A) = +proc incl*[A](s: var OrderedSet[A], key: A) = ## Includes an element `key` in `s`. ## ## This doesn't do anything if `key` is already in `s`. Example: @@ -618,7 +621,7 @@ proc incl*[A](s: var TOrderedSet[A], key: A) = assert s.isValid, "The set needs to be initialized." inclImpl() -proc incl*[A](s: var TSet[A], other: TOrderedSet[A]) = +proc incl*[A](s: var HashSet[A], other: OrderedSet[A]) = ## Includes all elements from `other` into `s`. ## ## Example: @@ -633,7 +636,7 @@ proc incl*[A](s: var TSet[A], other: TOrderedSet[A]) = assert other.isValid, "The set `other` needs to be initialized." for item in other: incl(s, item) -proc containsOrIncl*[A](s: var TOrderedSet[A], key: A): bool = +proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool = ## Includes `key` in the set `s` and tells if `key` was added to `s`. ## ## The difference with regards to the `incl() <#incl,TOrderedSet[A],A>`_ proc @@ -648,7 +651,7 @@ proc containsOrIncl*[A](s: var TOrderedSet[A], key: A): bool = assert s.isValid, "The set needs to be initialized." containsOrInclImpl() -proc init*[A](s: var TOrderedSet[A], initialSize=64) = +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 @@ -673,7 +676,7 @@ proc init*[A](s: var TOrderedSet[A], initialSize=64) = s.last = -1 newSeq(s.data, initialSize) -proc initOrderedSet*[A](initialSize=64): TOrderedSet[A] = +proc initOrderedSet*[A](initialSize=64): OrderedSet[A] = ## Wrapper around `init() <#init,TOrderedSet[A],int>`_ for initialization of ## ordered hash sets. ## @@ -685,7 +688,7 @@ proc initOrderedSet*[A](initialSize=64): TOrderedSet[A] = ## a.incl(2) result.init(initialSize) -proc toOrderedSet*[A](keys: openArray[A]): TOrderedSet[A] = +proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] = ## Creates a new ordered hash set that contains the given `keys`. ## ## Example: @@ -697,7 +700,7 @@ proc toOrderedSet*[A](keys: openArray[A]): TOrderedSet[A] = result = initOrderedSet[A](nextPowerOfTwo(keys.len+10)) for key in items(keys): result.incl(key) -proc `$`*[A](s: TOrderedSet[A]): string = +proc `$`*[A](s: OrderedSet[A]): string = ## Converts the ordered hash set `s` to a string, mostly for logging purposes. ## ## Don't use this proc for serialization, the representation may change at @@ -713,7 +716,7 @@ proc `$`*[A](s: TOrderedSet[A]): string = assert s.isValid, "The set needs to be initialized." dollarImpl() -proc `==`*[A](s, t: TOrderedSet[A]): bool = +proc `==`*[A](s, t: OrderedSet[A]): bool = ## Equality for ordered sets. if s.counter != t.counter: return false var h = s.first @@ -734,14 +737,14 @@ proc `==`*[A](s, t: TOrderedSet[A]): bool = proc testModule() = ## Internal micro test to validate docstrings and such. block isValidTest: - var options: TSet[string] - proc savePreferences(options: TSet[string]) = + var options: HashSet[string] + proc savePreferences(options: HashSet[string]) = assert options.isValid, "Pass an initialized set!" options = initSet[string]() options.savePreferences block lenTest: - var values: TSet[int] + var values: HashSet[int] assert(not values.isValid) assert values.len == 0 assert values.card == 0 @@ -835,14 +838,14 @@ proc testModule() = assert b == toSet(["1", "2", "3"]) block isValidTest: - var cards: TOrderedSet[string] - proc saveTarotCards(cards: TOrderedSet[string]) = + var cards: OrderedSet[string] + proc saveTarotCards(cards: OrderedSet[string]) = assert cards.isValid, "Pass an initialized set!" cards = initOrderedSet[string]() cards.saveTarotCards block lenTest: - var values: TOrderedSet[int] + var values: OrderedSet[int] assert(not values.isValid) assert values.len == 0 assert values.card == 0 @@ -879,7 +882,7 @@ proc testModule() = assert(a == b) # https://github.com/Araq/Nimrod/issues/1413 block initBlocks: - var a: TOrderedSet[int] + var a: OrderedSet[int] a.init(4) a.incl(2) a.init @@ -888,7 +891,7 @@ proc testModule() = a.incl(2) assert a.len == 1 - var b: TSet[int] + var b: HashSet[int] b.init(4) b.incl(2) b.init diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index dcf2ab481..41dfdaca6 100644 --- a/lib/pure/collections/tables.nim +++ b/lib/pure/collections/tables.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -28,7 +28,7 @@ ## you add such a proc for your custom type everything will work. See this ## example: ## -## .. code-block:: nimrod +## .. code-block:: ## type ## Person = object ## firstName, lastName: string @@ -61,43 +61,45 @@ import {.pragma: myShallow.} type - TSlotEnum = enum seEmpty, seFilled, seDeleted - TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B] - TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]] - TTable* {.final, myShallow.}[A, B] = object ## generic hash table - data: TKeyValuePairSeq[A, B] + SlotEnum = enum seEmpty, seFilled, seDeleted + KeyValuePair[A, B] = tuple[slot: SlotEnum, key: A, val: B] + KeyValuePairSeq[A, B] = seq[KeyValuePair[A, B]] + Table* {.myShallow.}[A, B] = object ## generic hash table + data: KeyValuePairSeq[A, B] counter: int - PTable*[A,B] = ref TTable[A, B] + TableRef*[A,B] = ref Table[A, B] + +{.deprecated: [TTable: Table, PTable: TableRef].} when not defined(nimhygiene): {.pragma: dirty.} -proc len*[A, B](t: TTable[A, B]): int = +proc len*[A, B](t: Table[A, B]): int = ## returns the number of keys in `t`. result = t.counter -iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] = +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) -iterator mpairs*[A, B](t: var TTable[A, B]): tuple[key: A, val: var B] = +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) -iterator keys*[A, B](t: TTable[A, B]): A = +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 -iterator values*[A, B](t: TTable[A, B]): B = +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 -iterator mvalues*[A, B](t: var TTable[A, B]): var B = +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 @@ -128,10 +130,10 @@ template rawInsertImpl() {.dirty.} = data[h].val = val data[h].slot = seFilled -proc rawGet[A, B](t: TTable[A, B], key: A): int = +proc rawGet[A, B](t: Table[A, B], key: A): int = rawGetImpl() -proc `[]`*[A, B](t: TTable[A, B], key: A): B = +proc `[]`*[A, B](t: Table[A, B], key: A): B = ## retrieves the value at ``t[key]``. If `key` is not in `t`, ## default empty value for the type `B` is returned ## and no exception is raised. One can check with ``hasKey`` whether the key @@ -139,14 +141,14 @@ proc `[]`*[A, B](t: TTable[A, B], key: A): B = var index = rawGet(t, key) if index >= 0: result = t.data[index].val -proc mget*[A, B](t: var TTable[A, B], key: A): var B = +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) if index >= 0: result = t.data[index].val - else: raise newException(EInvalidKey, "key not found: " & $key) + else: raise newException(KeyError, "key not found: " & $key) -iterator allValues*[A, B](t: TTable[A, B]; key: A): B = +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: @@ -154,16 +156,16 @@ iterator allValues*[A, B](t: TTable[A, B]; key: A): B = yield t.data[h].val h = nextTry(h, high(t.data)) -proc hasKey*[A, B](t: TTable[A, B], key: A): bool = +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 -proc rawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B], +proc rawInsert[A, B](t: var Table[A, B], data: var KeyValuePairSeq[A, B], key: A, val: B) = rawInsertImpl() -proc enlarge[A, B](t: var TTable[A, B]) = - var n: TKeyValuePairSeq[A, B] +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) @@ -194,22 +196,22 @@ when false: inc(t.counter) result = false -proc `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) = +proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. putImpl() -proc add*[A, B](t: var TTable[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() -proc del*[A, B](t: var TTable[A, B], key: A) = +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 dec(t.counter) -proc initTable*[A, B](initialSize=64): TTable[A, B] = +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 @@ -220,7 +222,7 @@ proc initTable*[A, B](initialSize=64): TTable[A, B] = newSeq(result.data, initialSize) proc toTable*[A, B](pairs: openArray[tuple[key: A, - val: B]]): TTable[A, B] = + val: B]]): Table[A, B] = ## creates a new hash table that contains the given `pairs`. result = initTable[A, B](nextPowerOfTwo(pairs.len+10)) for key, val in items(pairs): result[key] = val @@ -237,7 +239,7 @@ template dollarImpl(): stmt {.dirty.} = result.add($val) result.add("}") -proc `$`*[A, B](t: TTable[A, B]): string = +proc `$`*[A, B](t: Table[A, B]): string = ## The `$` operator for hash tables. dollarImpl() @@ -251,93 +253,93 @@ template equalsImpl() = if t[key] != val: return false return true -proc `==`*[A, B](s, t: TTable[A, B]): bool = +proc `==`*[A, B](s, t: Table[A, B]): bool = equalsImpl() -proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): TTable[C, B] = +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] result = initTable[C, B]() for item in collection: result[index(item)] = item -proc len*[A, B](t: PTable[A, B]): int = +proc len*[A, B](t: TableRef[A, B]): int = ## returns the number of keys in `t`. result = t.counter -iterator pairs*[A, B](t: PTable[A, B]): tuple[key: A, val: B] = +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) -iterator mpairs*[A, B](t: PTable[A, B]): tuple[key: A, val: var B] = +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) -iterator keys*[A, B](t: PTable[A, B]): A = +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 -iterator values*[A, B](t: PTable[A, B]): B = +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 -iterator mvalues*[A, B](t: PTable[A, B]): var B = +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 -proc `[]`*[A, B](t: PTable[A, B], key: A): B = +proc `[]`*[A, B](t: TableRef[A, B], key: A): B = ## retrieves the value at ``t[key]``. If `key` is not in `t`, ## default empty value for the type `B` is returned ## and no exception is raised. One can check with ``hasKey`` whether the key ## exists. result = t[][key] -proc mget*[A, B](t: PTable[A, B], key: A): var B = +proc mget*[A, B](t: TableRef[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. t[].mget(key) -proc hasKey*[A, B](t: PTable[A, B], key: A): bool = +proc hasKey*[A, B](t: TableRef[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) -proc `[]=`*[A, B](t: PTable[A, B], key: A, val: B) = +proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. t[][key] = val -proc add*[A, B](t: PTable[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: PTable[A, B], key: A) = +proc del*[A, B](t: TableRef[A, B], key: A) = ## deletes `key` from hash table `t`. t[].del(key) -proc newTable*[A, B](initialSize=64): PTable[A, B] = +proc newTable*[A, B](initialSize=64): TableRef[A, B] = new(result) result[] = initTable[A, B](initialSize) -proc newTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): PTable[A, B] = +proc newTable*[A, B](pairs: openArray[tuple[key: A, val: B]]): TableRef[A, B] = ## creates a new hash table that contains the given `pairs`. new(result) result[] = toTable[A, B](pairs) -proc `$`*[A, B](t: PTable[A, B]): string = +proc `$`*[A, B](t: TableRef[A, B]): string = ## The `$` operator for hash tables. dollarImpl() -proc `==`*[A, B](s, t: PTable[A, B]): bool = +proc `==`*[A, B](s, t: TableRef[A, B]): bool = if isNil(s): result = isNil(t) elif isNil(t): result = false else: result = equalsImpl() -proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): PTable[C, B] = +proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] = ## Index the collection with the proc provided. # TODO: As soon as supported, change collection: A to collection: A[B] result = newTable[C, B]() @@ -347,16 +349,18 @@ proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): PTable[C, B] = # ------------------------------ ordered table ------------------------------ type - TOrderedKeyValuePair[A, B] = tuple[ - slot: TSlotEnum, next: int, key: A, val: B] - TOrderedKeyValuePairSeq[A, B] = seq[TOrderedKeyValuePair[A, B]] - TOrderedTable* {. - final, myShallow.}[A, B] = object ## table that remembers insertion order - data: TOrderedKeyValuePairSeq[A, B] + OrderedKeyValuePair[A, B] = tuple[ + slot: SlotEnum, next: int, key: A, val: B] + OrderedKeyValuePairSeq[A, B] = seq[OrderedKeyValuePair[A, B]] + OrderedTable* {. + myShallow.}[A, B] = object ## table that remembers insertion order + data: OrderedKeyValuePairSeq[A, B] counter, first, last: int - POrderedTable*[A, B] = ref TOrderedTable[A, B] + OrderedTableRef*[A, B] = ref OrderedTable[A, B] + +{.deprecated: [TOrderedTable: OrderedTable, POrderedTable: OrderedTableRef].} -proc len*[A, B](t: TOrderedTable[A, B]): int {.inline.} = +proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} = ## returns the number of keys in `t`. result = t.counter @@ -367,38 +371,38 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} = if t.data[h].slot == seFilled: yieldStmt h = nxt -iterator pairs*[A, B](t: TOrderedTable[A, B]): tuple[key: A, val: B] = +iterator pairs*[A, B](t: OrderedTable[A, B]): tuple[key: A, val: B] = ## iterates over any (key, value) pair in the table `t` in insertion ## order. forAllOrderedPairs: yield (t.data[h].key, t.data[h].val) -iterator mpairs*[A, B](t: var TOrderedTable[A, B]): tuple[key: A, val: var B] = +iterator mpairs*[A, B](t: var OrderedTable[A, B]): tuple[key: A, val: var B] = ## iterates over any (key, value) pair in the table `t` in insertion ## order. The values can be modified. forAllOrderedPairs: yield (t.data[h].key, t.data[h].val) -iterator keys*[A, B](t: TOrderedTable[A, B]): A = +iterator keys*[A, B](t: OrderedTable[A, B]): A = ## iterates over any key in the table `t` in insertion order. forAllOrderedPairs: yield t.data[h].key -iterator values*[A, B](t: TOrderedTable[A, B]): B = +iterator values*[A, B](t: OrderedTable[A, B]): B = ## iterates over any value in the table `t` in insertion order. forAllOrderedPairs: yield t.data[h].val -iterator mvalues*[A, B](t: var TOrderedTable[A, B]): var B = +iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B = ## iterates over any value in the table `t` in insertion order. The values ## can be modified. forAllOrderedPairs: yield t.data[h].val -proc rawGet[A, B](t: TOrderedTable[A, B], key: A): int = +proc rawGet[A, B](t: OrderedTable[A, B], key: A): int = rawGetImpl() -proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B = +proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B = ## retrieves the value at ``t[key]``. If `key` is not in `t`, ## default empty value for the type `B` is returned ## and no exception is raised. One can check with ``hasKey`` whether the key @@ -406,19 +410,19 @@ proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B = var index = rawGet(t, key) if index >= 0: result = t.data[index].val -proc mget*[A, B](t: var TOrderedTable[A, B], key: A): var B = +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) if index >= 0: result = t.data[index].val - else: raise newException(EInvalidKey, "key not found: " & $key) + else: raise newException(KeyError, "key not found: " & $key) -proc hasKey*[A, B](t: TOrderedTable[A, B], key: A): bool = +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 -proc rawInsert[A, B](t: var TOrderedTable[A, B], - data: var TOrderedKeyValuePairSeq[A, B], +proc rawInsert[A, B](t: var OrderedTable[A, B], + data: var OrderedKeyValuePairSeq[A, B], key: A, val: B) = rawInsertImpl() data[h].next = -1 @@ -426,8 +430,8 @@ proc rawInsert[A, B](t: var TOrderedTable[A, B], if t.last >= 0: data[t.last].next = h t.last = h -proc enlarge[A, B](t: var TOrderedTable[A, B]) = - var n: TOrderedKeyValuePairSeq[A, B] +proc enlarge[A, B](t: var OrderedTable[A, B]) = + var n: OrderedKeyValuePairSeq[A, B] newSeq(n, len(t.data) * growthFactor) var h = t.first t.first = -1 @@ -439,15 +443,15 @@ proc enlarge[A, B](t: var TOrderedTable[A, B]) = h = nxt swap(t.data, n) -proc `[]=`*[A, B](t: var TOrderedTable[A, B], key: A, val: B) = +proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. putImpl() -proc add*[A, B](t: var TOrderedTable[A, B], key: A, val: B) = +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 initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] = +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 @@ -460,16 +464,16 @@ proc initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] = newSeq(result.data, initialSize) proc toOrderedTable*[A, B](pairs: openArray[tuple[key: A, - val: B]]): TOrderedTable[A, B] = + val: B]]): OrderedTable[A, B] = ## creates a new ordered hash table that contains the given `pairs`. result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10)) for key, val in items(pairs): result[key] = val -proc `$`*[A, B](t: TOrderedTable[A, B]): string = +proc `$`*[A, B](t: OrderedTable[A, B]): string = ## The `$` operator for ordered hash tables. dollarImpl() -proc sort*[A, B](t: var TOrderedTable[A, B], +proc sort*[A, B](t: var OrderedTable[A, B], cmp: proc (x,y: tuple[key: A, val: B]): int) = ## sorts `t` according to `cmp`. This modifies the internal list ## that kept the insertion order, so insertion order is lost after this @@ -515,7 +519,7 @@ proc sort*[A, B](t: var TOrderedTable[A, B], t.first = list t.last = tail -proc len*[A, B](t: POrderedTable[A, B]): int {.inline.} = +proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} = ## returns the number of keys in `t`. result = t.counter @@ -526,59 +530,59 @@ template forAllOrderedPairs(yieldStmt: stmt) {.dirty, immediate.} = if t.data[h].slot == seFilled: yieldStmt h = nxt -iterator pairs*[A, B](t: POrderedTable[A, B]): tuple[key: A, val: B] = +iterator pairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: B] = ## iterates over any (key, value) pair in the table `t` in insertion ## order. forAllOrderedPairs: yield (t.data[h].key, t.data[h].val) -iterator mpairs*[A, B](t: POrderedTable[A, B]): tuple[key: A, val: var B] = +iterator mpairs*[A, B](t: OrderedTableRef[A, B]): tuple[key: A, val: var B] = ## iterates over any (key, value) pair in the table `t` in insertion ## order. The values can be modified. forAllOrderedPairs: yield (t.data[h].key, t.data[h].val) -iterator keys*[A, B](t: POrderedTable[A, B]): A = +iterator keys*[A, B](t: OrderedTableRef[A, B]): A = ## iterates over any key in the table `t` in insertion order. forAllOrderedPairs: yield t.data[h].key -iterator values*[A, B](t: POrderedTable[A, B]): B = +iterator values*[A, B](t: OrderedTableRef[A, B]): B = ## iterates over any value in the table `t` in insertion order. forAllOrderedPairs: yield t.data[h].val -iterator mvalues*[A, B](t: POrderedTable[A, B]): var B = +iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B = ## iterates over any value in the table `t` in insertion order. The values ## can be modified. forAllOrderedPairs: yield t.data[h].val -proc `[]`*[A, B](t: POrderedTable[A, B], key: A): B = +proc `[]`*[A, B](t: OrderedTableRef[A, B], key: A): B = ## retrieves the value at ``t[key]``. If `key` is not in `t`, ## default empty value for the type `B` is returned ## and no exception is raised. One can check with ``hasKey`` whether the key ## exists. result = t[][key] -proc mget*[A, B](t: POrderedTable[A, B], key: A): var B = +proc mget*[A, B](t: OrderedTableRef[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. result = t[].mget(key) -proc hasKey*[A, B](t: POrderedTable[A, B], key: A): bool = +proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) -proc `[]=`*[A, B](t: POrderedTable[A, B], key: A, val: B) = +proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) = ## puts a (key, value)-pair into `t`. t[][key] = val -proc add*[A, B](t: POrderedTable[A, B], key: A, val: B) = +proc add*[A, B](t: OrderedTableRef[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 newOrderedTable*[A, B](initialSize=64): POrderedTable[A, B] = +proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[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 @@ -588,16 +592,16 @@ proc newOrderedTable*[A, B](initialSize=64): POrderedTable[A, B] = result[] = initOrderedTable[A, B]() proc newOrderedTable*[A, B](pairs: openArray[tuple[key: A, - val: B]]): POrderedTable[A, B] = + val: B]]): OrderedTableRef[A, B] = ## creates a new ordered hash table that contains the given `pairs`. result = newOrderedTable[A, B](nextPowerOfTwo(pairs.len+10)) for key, val in items(pairs): result[key] = val -proc `$`*[A, B](t: POrderedTable[A, B]): string = +proc `$`*[A, B](t: OrderedTableRef[A, B]): string = ## The `$` operator for ordered hash tables. dollarImpl() -proc sort*[A, B](t: POrderedTable[A, B], +proc sort*[A, B](t: OrderedTableRef[A, B], cmp: proc (x,y: tuple[key: A, val: B]): int) = ## sorts `t` according to `cmp`. This modifies the internal list ## that kept the insertion order, so insertion order is lost after this @@ -608,87 +612,89 @@ proc sort*[A, B](t: POrderedTable[A, B], # ------------------------------ count tables ------------------------------- type - TCountTable* {.final, myShallow.}[ + CountTable* {.myShallow.}[ A] = object ## table that counts the number of each key data: seq[tuple[key: A, val: int]] counter: int - PCountTable*[A] = ref TCountTable[A] + CountTableRef*[A] = ref CountTable[A] + +{.deprecated: [TCountTable: CountTable, PCountTable: CountTableRef].} -proc len*[A](t: TCountTable[A]): int = +proc len*[A](t: CountTable[A]): int = ## returns the number of keys in `t`. result = t.counter -iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] = +iterator pairs*[A](t: CountTable[A]): tuple[key: A, val: int] = ## iterates over any (key, value) pair in the table `t`. for h in 0..high(t.data): if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val) -iterator mpairs*[A](t: var TCountTable[A]): tuple[key: A, val: var int] = +iterator mpairs*[A](t: var CountTable[A]): tuple[key: A, val: var int] = ## 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].val != 0: yield (t.data[h].key, t.data[h].val) -iterator keys*[A](t: TCountTable[A]): A = +iterator keys*[A](t: CountTable[A]): A = ## iterates over any key in the table `t`. for h in 0..high(t.data): if t.data[h].val != 0: yield t.data[h].key -iterator values*[A](t: TCountTable[A]): int = +iterator values*[A](t: CountTable[A]): int = ## iterates over any value in the table `t`. for h in 0..high(t.data): if t.data[h].val != 0: yield t.data[h].val -iterator mvalues*[A](t: TCountTable[A]): var int = +iterator mvalues*[A](t: CountTable[A]): var int = ## iterates over any value in the table `t`. The values can be modified. for h in 0..high(t.data): if t.data[h].val != 0: yield t.data[h].val -proc rawGet[A](t: TCountTable[A], key: A): int = +proc rawGet[A](t: CountTable[A], key: A): int = var h: THash = hash(key) and high(t.data) # start with real hash value while t.data[h].val != 0: if t.data[h].key == key: return h h = nextTry(h, high(t.data)) result = -1 -proc `[]`*[A](t: TCountTable[A], key: A): int = +proc `[]`*[A](t: CountTable[A], key: A): int = ## retrieves the value at ``t[key]``. If `key` is not in `t`, ## 0 is returned. One can check with ``hasKey`` whether the key ## exists. var index = rawGet(t, key) if index >= 0: result = t.data[index].val -proc mget*[A](t: var TCountTable[A], key: A): var int = +proc mget*[A](t: var CountTable[A], key: A): var int = ## 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) if index >= 0: result = t.data[index].val - else: raise newException(EInvalidKey, "key not found: " & $key) + else: raise newException(KeyError, "key not found: " & $key) -proc hasKey*[A](t: TCountTable[A], key: A): bool = +proc hasKey*[A](t: CountTable[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 -proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]], +proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]], key: A, val: int) = var h: THash = hash(key) and high(data) while data[h].val != 0: h = nextTry(h, high(data)) data[h].key = key data[h].val = val -proc enlarge[A](t: var TCountTable[A]) = +proc enlarge[A](t: var CountTable[A]) = var n: seq[tuple[key: A, val: int]] newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(t.data)): if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val) swap(t.data, n) -proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) = +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() -proc initCountTable*[A](initialSize=64): TCountTable[A] = +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 @@ -698,16 +704,16 @@ proc initCountTable*[A](initialSize=64): TCountTable[A] = result.counter = 0 newSeq(result.data, initialSize) -proc toCountTable*[A](keys: openArray[A]): TCountTable[A] = +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)) for key in items(keys): result[key] = 1 -proc `$`*[A](t: TCountTable[A]): string = +proc `$`*[A](t: CountTable[A]): string = ## The `$` operator for count tables. dollarImpl() -proc inc*[A](t: var TCountTable[A], key: A, val = 1) = +proc inc*[A](t: var CountTable[A], key: A, val = 1) = ## increments `t[key]` by `val`. var index = rawGet(t, key) if index >= 0: @@ -717,7 +723,7 @@ proc inc*[A](t: var TCountTable[A], key: A, val = 1) = rawInsert(t, t.data, key, val) inc(t.counter) -proc smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] = +proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] = ## returns the largest (key,val)-pair. Efficiency: O(n) assert t.len > 0 var minIdx = 0 @@ -726,7 +732,7 @@ proc smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] = result.key = t.data[minIdx].key result.val = t.data[minIdx].val -proc largest*[A](t: TCountTable[A]): tuple[key: A, val: int] = +proc largest*[A](t: CountTable[A]): tuple[key: A, val: int] = ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n) assert t.len > 0 var maxIdx = 0 @@ -735,7 +741,7 @@ proc largest*[A](t: TCountTable[A]): tuple[key: A, val: int] = result.key = t.data[maxIdx].key result.val = t.data[maxIdx].val -proc sort*[A](t: var TCountTable[A]) = +proc sort*[A](t: var CountTable[A]) = ## sorts the count table so that the entry with the highest counter comes ## first. This is destructive! You must not modify `t` afterwards! ## You can use the iterators `pairs`, `keys`, and `values` to iterate over @@ -756,57 +762,57 @@ proc sort*[A](t: var TCountTable[A]) = if j < h: break if h == 1: break -proc len*[A](t: PCountTable[A]): int = +proc len*[A](t: CountTableRef[A]): int = ## returns the number of keys in `t`. result = t.counter -iterator pairs*[A](t: PCountTable[A]): tuple[key: A, val: int] = +iterator pairs*[A](t: CountTableRef[A]): tuple[key: A, val: int] = ## iterates over any (key, value) pair in the table `t`. for h in 0..high(t.data): if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val) -iterator mpairs*[A](t: PCountTable[A]): tuple[key: A, val: var int] = +iterator mpairs*[A](t: CountTableRef[A]): tuple[key: A, val: var int] = ## 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].val != 0: yield (t.data[h].key, t.data[h].val) -iterator keys*[A](t: PCountTable[A]): A = +iterator keys*[A](t: CountTableRef[A]): A = ## iterates over any key in the table `t`. for h in 0..high(t.data): if t.data[h].val != 0: yield t.data[h].key -iterator values*[A](t: PCountTable[A]): int = +iterator values*[A](t: CountTableRef[A]): int = ## iterates over any value in the table `t`. for h in 0..high(t.data): if t.data[h].val != 0: yield t.data[h].val -iterator mvalues*[A](t: PCountTable[A]): var int = +iterator mvalues*[A](t: CountTableRef[A]): var int = ## iterates over any value in the table `t`. The values can be modified. for h in 0..high(t.data): if t.data[h].val != 0: yield t.data[h].val -proc `[]`*[A](t: PCountTable[A], key: A): int = +proc `[]`*[A](t: CountTableRef[A], key: A): int = ## retrieves the value at ``t[key]``. If `key` is not in `t`, ## 0 is returned. One can check with ``hasKey`` whether the key ## exists. result = t[][key] -proc mget*[A](t: PCountTable[A], key: A): var int = +proc mget*[A](t: CountTableRef[A], key: A): var int = ## retrieves the value at ``t[key]``. The value can be modified. ## If `key` is not in `t`, the ``EInvalidKey`` exception is raised. result = t[].mget(key) -proc hasKey*[A](t: PCountTable[A], key: A): bool = +proc hasKey*[A](t: CountTableRef[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = t[].hasKey(key) -proc `[]=`*[A](t: PCountTable[A], key: A, val: int) = +proc `[]=`*[A](t: CountTableRef[A], key: A, val: int) = ## puts a (key, value)-pair into `t`. `val` has to be positive. assert val > 0 t[][key] = val -proc newCountTable*[A](initialSize=64): PCountTable[A] = +proc newCountTable*[A](initialSize=64): CountTableRef[A] = ## creates a new count table that is empty. ## ## `initialSize` needs to be a power of two. If you need to accept runtime @@ -815,28 +821,28 @@ proc newCountTable*[A](initialSize=64): PCountTable[A] = new(result) result[] = initCountTable[A](initialSize) -proc newCountTable*[A](keys: openArray[A]): PCountTable[A] = +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)) for key in items(keys): result[key] = 1 -proc `$`*[A](t: PCountTable[A]): string = +proc `$`*[A](t: CountTableRef[A]): string = ## The `$` operator for count tables. dollarImpl() -proc inc*[A](t: PCountTable[A], key: A, val = 1) = +proc inc*[A](t: CountTableRef[A], key: A, val = 1) = ## increments `t[key]` by `val`. t[].inc(key, val) -proc smallest*[A](t: PCountTable[A]): tuple[key: A, val: int] = +proc smallest*[A](t: CountTableRef[A]): tuple[key: A, val: int] = ## returns the largest (key,val)-pair. Efficiency: O(n) t[].smallest -proc largest*[A](t: PCountTable[A]): tuple[key: A, val: int] = +proc largest*[A](t: CountTableRef[A]): tuple[key: A, val: int] = ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n) t[].largest -proc sort*[A](t: PCountTable[A]) = +proc sort*[A](t: CountTableRef[A]) = ## sorts the count table so that the entry with the highest counter comes ## first. This is destructive! You must not modify `t` afterwards! ## You can use the iterators `pairs`, `keys`, and `values` to iterate over diff --git a/lib/pure/colors.nim b/lib/pure/colors.nim index 9f824e5de..7942255cb 100644 --- a/lib/pure/colors.nim +++ b/lib/pure/colors.nim @@ -1,5 +1,5 @@ # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,18 +12,20 @@ import strutils type - TColor* = distinct int ## a color stored as RGB + Color* = distinct int ## a color stored as RGB -proc `==` *(a, b: TColor): bool {.borrow.} +{.deprecated: [TColor: Color].} + +proc `==` *(a, b: Color): bool {.borrow.} ## compares two colors. -template extract(a: TColor, r, g, b: expr) {.immediate.}= +template extract(a: Color, r, g, b: expr) {.immediate.}= var r = a.int shr 16 and 0xff var g = a.int shr 8 and 0xff var b = a.int and 0xff template rawRGB(r, g, b: int): expr = - TColor(r shl 16 or g shl 8 or b) + Color(r shl 16 or g shl 8 or b) template colorOp(op: expr) {.immediate.} = extract(a, ar, ag, ab) @@ -38,23 +40,23 @@ proc satMinus(a, b: int): int {.inline.} = result = a -% b if result < 0: result = 0 -proc `+`*(a, b: TColor): TColor = +proc `+`*(a, b: Color): Color = ## adds two colors: This uses saturated artithmetic, so that each color ## component cannot overflow (255 is used as a maximum). colorOp(satPlus) -proc `-`*(a, b: TColor): TColor = +proc `-`*(a, b: Color): Color = ## substracts two colors: This uses saturated artithmetic, so that each color ## component cannot overflow (255 is used as a maximum). colorOp(satMinus) -proc extractRGB*(a: TColor): tuple[r, g, b: range[0..255]] = +proc extractRGB*(a: Color): tuple[r, g, b: range[0..255]] = ## extracts the red/green/blue components of the color `a`. result.r = a.int shr 16 and 0xff result.g = a.int shr 8 and 0xff result.b = a.int and 0xff -proc intensity*(a: TColor, f: float): TColor = +proc intensity*(a: Color, f: float): Color = ## returns `a` with intensity `f`. `f` should be a float from 0.0 (completely ## dark) to 1.0 (full color intensity). var r = toInt(toFloat(a.int shr 16 and 0xff) * f) @@ -65,7 +67,7 @@ proc intensity*(a: TColor, f: float): TColor = if b >% 255: b = 255 result = rawRGB(r, g, b) -template mix*(a, b: TColor, fn: expr): expr = +template mix*(a, b: Color, fn: expr): expr = ## uses `fn` to mix the colors `a` and `b`. `fn` is invoked for each component ## R, G, and B. This is a template because `fn` should be inlined and the ## compiler cannot inline proc pointers yet. If `fn`'s result is not in the @@ -84,146 +86,146 @@ template mix*(a, b: TColor, fn: expr): expr = const - colAliceBlue* = TColor(0xF0F8FF) - colAntiqueWhite* = TColor(0xFAEBD7) - colAqua* = TColor(0x00FFFF) - colAquamarine* = TColor(0x7FFFD4) - colAzure* = TColor(0xF0FFFF) - colBeige* = TColor(0xF5F5DC) - colBisque* = TColor(0xFFE4C4) - colBlack* = TColor(0x000000) - colBlanchedAlmond* = TColor(0xFFEBCD) - colBlue* = TColor(0x0000FF) - colBlueViolet* = TColor(0x8A2BE2) - colBrown* = TColor(0xA52A2A) - colBurlyWood* = TColor(0xDEB887) - colCadetBlue* = TColor(0x5F9EA0) - colChartreuse* = TColor(0x7FFF00) - colChocolate* = TColor(0xD2691E) - colCoral* = TColor(0xFF7F50) - colCornflowerBlue* = TColor(0x6495ED) - colCornsilk* = TColor(0xFFF8DC) - colCrimson* = TColor(0xDC143C) - colCyan* = TColor(0x00FFFF) - colDarkBlue* = TColor(0x00008B) - colDarkCyan* = TColor(0x008B8B) - colDarkGoldenRod* = TColor(0xB8860B) - colDarkGray* = TColor(0xA9A9A9) - colDarkGreen* = TColor(0x006400) - colDarkKhaki* = TColor(0xBDB76B) - colDarkMagenta* = TColor(0x8B008B) - colDarkOliveGreen* = TColor(0x556B2F) - colDarkorange* = TColor(0xFF8C00) - colDarkOrchid* = TColor(0x9932CC) - colDarkRed* = TColor(0x8B0000) - colDarkSalmon* = TColor(0xE9967A) - colDarkSeaGreen* = TColor(0x8FBC8F) - colDarkSlateBlue* = TColor(0x483D8B) - colDarkSlateGray* = TColor(0x2F4F4F) - colDarkTurquoise* = TColor(0x00CED1) - colDarkViolet* = TColor(0x9400D3) - colDeepPink* = TColor(0xFF1493) - colDeepSkyBlue* = TColor(0x00BFFF) - colDimGray* = TColor(0x696969) - colDodgerBlue* = TColor(0x1E90FF) - colFireBrick* = TColor(0xB22222) - colFloralWhite* = TColor(0xFFFAF0) - colForestGreen* = TColor(0x228B22) - colFuchsia* = TColor(0xFF00FF) - colGainsboro* = TColor(0xDCDCDC) - colGhostWhite* = TColor(0xF8F8FF) - colGold* = TColor(0xFFD700) - colGoldenRod* = TColor(0xDAA520) - colGray* = TColor(0x808080) - colGreen* = TColor(0x008000) - colGreenYellow* = TColor(0xADFF2F) - colHoneyDew* = TColor(0xF0FFF0) - colHotPink* = TColor(0xFF69B4) - colIndianRed* = TColor(0xCD5C5C) - colIndigo* = TColor(0x4B0082) - colIvory* = TColor(0xFFFFF0) - colKhaki* = TColor(0xF0E68C) - colLavender* = TColor(0xE6E6FA) - colLavenderBlush* = TColor(0xFFF0F5) - colLawnGreen* = TColor(0x7CFC00) - colLemonChiffon* = TColor(0xFFFACD) - colLightBlue* = TColor(0xADD8E6) - colLightCoral* = TColor(0xF08080) - colLightCyan* = TColor(0xE0FFFF) - colLightGoldenRodYellow* = TColor(0xFAFAD2) - colLightGrey* = TColor(0xD3D3D3) - colLightGreen* = TColor(0x90EE90) - colLightPink* = TColor(0xFFB6C1) - colLightSalmon* = TColor(0xFFA07A) - colLightSeaGreen* = TColor(0x20B2AA) - colLightSkyBlue* = TColor(0x87CEFA) - colLightSlateGray* = TColor(0x778899) - colLightSteelBlue* = TColor(0xB0C4DE) - colLightYellow* = TColor(0xFFFFE0) - colLime* = TColor(0x00FF00) - colLimeGreen* = TColor(0x32CD32) - colLinen* = TColor(0xFAF0E6) - colMagenta* = TColor(0xFF00FF) - colMaroon* = TColor(0x800000) - colMediumAquaMarine* = TColor(0x66CDAA) - colMediumBlue* = TColor(0x0000CD) - colMediumOrchid* = TColor(0xBA55D3) - colMediumPurple* = TColor(0x9370D8) - colMediumSeaGreen* = TColor(0x3CB371) - colMediumSlateBlue* = TColor(0x7B68EE) - colMediumSpringGreen* = TColor(0x00FA9A) - colMediumTurquoise* = TColor(0x48D1CC) - colMediumVioletRed* = TColor(0xC71585) - colMidnightBlue* = TColor(0x191970) - colMintCream* = TColor(0xF5FFFA) - colMistyRose* = TColor(0xFFE4E1) - colMoccasin* = TColor(0xFFE4B5) - colNavajoWhite* = TColor(0xFFDEAD) - colNavy* = TColor(0x000080) - colOldLace* = TColor(0xFDF5E6) - colOlive* = TColor(0x808000) - colOliveDrab* = TColor(0x6B8E23) - colOrange* = TColor(0xFFA500) - colOrangeRed* = TColor(0xFF4500) - colOrchid* = TColor(0xDA70D6) - colPaleGoldenRod* = TColor(0xEEE8AA) - colPaleGreen* = TColor(0x98FB98) - colPaleTurquoise* = TColor(0xAFEEEE) - colPaleVioletRed* = TColor(0xD87093) - colPapayaWhip* = TColor(0xFFEFD5) - colPeachPuff* = TColor(0xFFDAB9) - colPeru* = TColor(0xCD853F) - colPink* = TColor(0xFFC0CB) - colPlum* = TColor(0xDDA0DD) - colPowderBlue* = TColor(0xB0E0E6) - colPurple* = TColor(0x800080) - colRed* = TColor(0xFF0000) - colRosyBrown* = TColor(0xBC8F8F) - colRoyalBlue* = TColor(0x4169E1) - colSaddleBrown* = TColor(0x8B4513) - colSalmon* = TColor(0xFA8072) - colSandyBrown* = TColor(0xF4A460) - colSeaGreen* = TColor(0x2E8B57) - colSeaShell* = TColor(0xFFF5EE) - colSienna* = TColor(0xA0522D) - colSilver* = TColor(0xC0C0C0) - colSkyBlue* = TColor(0x87CEEB) - colSlateBlue* = TColor(0x6A5ACD) - colSlateGray* = TColor(0x708090) - colSnow* = TColor(0xFFFAFA) - colSpringGreen* = TColor(0x00FF7F) - colSteelBlue* = TColor(0x4682B4) - colTan* = TColor(0xD2B48C) - colTeal* = TColor(0x008080) - colThistle* = TColor(0xD8BFD8) - colTomato* = TColor(0xFF6347) - colTurquoise* = TColor(0x40E0D0) - colViolet* = TColor(0xEE82EE) - colWheat* = TColor(0xF5DEB3) - colWhite* = TColor(0xFFFFFF) - colWhiteSmoke* = TColor(0xF5F5F5) - colYellow* = TColor(0xFFFF00) - colYellowGreen* = TColor(0x9ACD32) + colAliceBlue* = Color(0xF0F8FF) + colAntiqueWhite* = Color(0xFAEBD7) + colAqua* = Color(0x00FFFF) + colAquamarine* = Color(0x7FFFD4) + colAzure* = Color(0xF0FFFF) + colBeige* = Color(0xF5F5DC) + colBisque* = Color(0xFFE4C4) + colBlack* = Color(0x000000) + colBlanchedAlmond* = Color(0xFFEBCD) + colBlue* = Color(0x0000FF) + colBlueViolet* = Color(0x8A2BE2) + colBrown* = Color(0xA52A2A) + colBurlyWood* = Color(0xDEB887) + colCadetBlue* = Color(0x5F9EA0) + colChartreuse* = Color(0x7FFF00) + colChocolate* = Color(0xD2691E) + colCoral* = Color(0xFF7F50) + colCornflowerBlue* = Color(0x6495ED) + colCornsilk* = Color(0xFFF8DC) + colCrimson* = Color(0xDC143C) + colCyan* = Color(0x00FFFF) + colDarkBlue* = Color(0x00008B) + colDarkCyan* = Color(0x008B8B) + colDarkGoldenRod* = Color(0xB8860B) + colDarkGray* = Color(0xA9A9A9) + colDarkGreen* = Color(0x006400) + colDarkKhaki* = Color(0xBDB76B) + colDarkMagenta* = Color(0x8B008B) + colDarkOliveGreen* = Color(0x556B2F) + colDarkorange* = Color(0xFF8C00) + colDarkOrchid* = Color(0x9932CC) + colDarkRed* = Color(0x8B0000) + colDarkSalmon* = Color(0xE9967A) + colDarkSeaGreen* = Color(0x8FBC8F) + colDarkSlateBlue* = Color(0x483D8B) + colDarkSlateGray* = Color(0x2F4F4F) + colDarkTurquoise* = Color(0x00CED1) + colDarkViolet* = Color(0x9400D3) + colDeepPink* = Color(0xFF1493) + colDeepSkyBlue* = Color(0x00BFFF) + colDimGray* = Color(0x696969) + colDodgerBlue* = Color(0x1E90FF) + colFireBrick* = Color(0xB22222) + colFloralWhite* = Color(0xFFFAF0) + colForestGreen* = Color(0x228B22) + colFuchsia* = Color(0xFF00FF) + colGainsboro* = Color(0xDCDCDC) + colGhostWhite* = Color(0xF8F8FF) + colGold* = Color(0xFFD700) + colGoldenRod* = Color(0xDAA520) + colGray* = Color(0x808080) + colGreen* = Color(0x008000) + colGreenYellow* = Color(0xADFF2F) + colHoneyDew* = Color(0xF0FFF0) + colHotPink* = Color(0xFF69B4) + colIndianRed* = Color(0xCD5C5C) + colIndigo* = Color(0x4B0082) + colIvory* = Color(0xFFFFF0) + colKhaki* = Color(0xF0E68C) + colLavender* = Color(0xE6E6FA) + colLavenderBlush* = Color(0xFFF0F5) + colLawnGreen* = Color(0x7CFC00) + colLemonChiffon* = Color(0xFFFACD) + colLightBlue* = Color(0xADD8E6) + colLightCoral* = Color(0xF08080) + colLightCyan* = Color(0xE0FFFF) + colLightGoldenRodYellow* = Color(0xFAFAD2) + colLightGrey* = Color(0xD3D3D3) + colLightGreen* = Color(0x90EE90) + colLightPink* = Color(0xFFB6C1) + colLightSalmon* = Color(0xFFA07A) + colLightSeaGreen* = Color(0x20B2AA) + colLightSkyBlue* = Color(0x87CEFA) + colLightSlateGray* = Color(0x778899) + colLightSteelBlue* = Color(0xB0C4DE) + colLightYellow* = Color(0xFFFFE0) + colLime* = Color(0x00FF00) + colLimeGreen* = Color(0x32CD32) + colLinen* = Color(0xFAF0E6) + colMagenta* = Color(0xFF00FF) + colMaroon* = Color(0x800000) + colMediumAquaMarine* = Color(0x66CDAA) + colMediumBlue* = Color(0x0000CD) + colMediumOrchid* = Color(0xBA55D3) + colMediumPurple* = Color(0x9370D8) + colMediumSeaGreen* = Color(0x3CB371) + colMediumSlateBlue* = Color(0x7B68EE) + colMediumSpringGreen* = Color(0x00FA9A) + colMediumTurquoise* = Color(0x48D1CC) + colMediumVioletRed* = Color(0xC71585) + colMidnightBlue* = Color(0x191970) + colMintCream* = Color(0xF5FFFA) + colMistyRose* = Color(0xFFE4E1) + colMoccasin* = Color(0xFFE4B5) + colNavajoWhite* = Color(0xFFDEAD) + colNavy* = Color(0x000080) + colOldLace* = Color(0xFDF5E6) + colOlive* = Color(0x808000) + colOliveDrab* = Color(0x6B8E23) + colOrange* = Color(0xFFA500) + colOrangeRed* = Color(0xFF4500) + colOrchid* = Color(0xDA70D6) + colPaleGoldenRod* = Color(0xEEE8AA) + colPaleGreen* = Color(0x98FB98) + colPaleTurquoise* = Color(0xAFEEEE) + colPaleVioletRed* = Color(0xD87093) + colPapayaWhip* = Color(0xFFEFD5) + colPeachPuff* = Color(0xFFDAB9) + colPeru* = Color(0xCD853F) + colPink* = Color(0xFFC0CB) + colPlum* = Color(0xDDA0DD) + colPowderBlue* = Color(0xB0E0E6) + colPurple* = Color(0x800080) + colRed* = Color(0xFF0000) + colRosyBrown* = Color(0xBC8F8F) + colRoyalBlue* = Color(0x4169E1) + colSaddleBrown* = Color(0x8B4513) + colSalmon* = Color(0xFA8072) + colSandyBrown* = Color(0xF4A460) + colSeaGreen* = Color(0x2E8B57) + colSeaShell* = Color(0xFFF5EE) + colSienna* = Color(0xA0522D) + colSilver* = Color(0xC0C0C0) + colSkyBlue* = Color(0x87CEEB) + colSlateBlue* = Color(0x6A5ACD) + colSlateGray* = Color(0x708090) + colSnow* = Color(0xFFFAFA) + colSpringGreen* = Color(0x00FF7F) + colSteelBlue* = Color(0x4682B4) + colTan* = Color(0xD2B48C) + colTeal* = Color(0x008080) + colThistle* = Color(0xD8BFD8) + colTomato* = Color(0xFF6347) + colTurquoise* = Color(0x40E0D0) + colViolet* = Color(0xEE82EE) + colWheat* = Color(0xF5DEB3) + colWhite* = Color(0xFFFFFF) + colWhiteSmoke* = Color(0xF5F5F5) + colYellow* = Color(0xFFFF00) + colYellowGreen* = Color(0x9ACD32) colorNames = [ ("aliceblue", colAliceBlue), @@ -367,11 +369,11 @@ const ("yellow", colYellow), ("yellowgreen", colYellowGreen)] -proc `$`*(c: TColor): string = +proc `$`*(c: Color): string = ## converts a color into its textual representation. Example: ``#00FF00``. result = '#' & toHex(int(c), 6) -proc binaryStrSearch(x: openarray[tuple[name: string, col: TColor]], +proc binaryStrSearch(x: openArray[tuple[name: string, col: Color]], y: string): int = var a = 0 var b = len(x) - 1 @@ -383,14 +385,14 @@ proc binaryStrSearch(x: openarray[tuple[name: string, col: TColor]], else: return mid result = - 1 -proc parseColor*(name: string): TColor = +proc parseColor*(name: string): Color = ## parses `name` to a color value. If no valid color could be ## parsed ``EInvalidValue`` is raised. if name[0] == '#': - result = TColor(parseHexInt(name)) + result = Color(parseHexInt(name)) else: var idx = binaryStrSearch(colorNames, name) - if idx < 0: raise newException(EInvalidValue, "unkown color: " & name) + if idx < 0: raise newException(ValueError, "unkown color: " & name) result = colorNames[idx][1] proc isColor*(name: string): bool = @@ -403,7 +405,7 @@ proc isColor*(name: string): bool = else: result = binaryStrSearch(colorNames, name) >= 0 -proc rgb*(r, g, b: range[0..255]): TColor = +proc rgb*(r, g, b: range[0..255]): Color = ## constructs a color from RGB values. result = rawRGB(r, g, b) diff --git a/lib/pure/complex.nim b/lib/pure/complex.nim index 1392b73aa..a8709e098 100644 --- a/lib/pure/complex.nim +++ b/lib/pure/complex.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this @@ -25,53 +25,55 @@ const type - TComplex* = tuple[re, im: float] + Complex* = tuple[re, im: float] ## a complex number, consisting of a real and an imaginary part -proc `==` *(x, y: TComplex): bool = +{.deprecated: [TComplex: Complex].} + +proc `==` *(x, y: Complex): bool = ## Compare two complex numbers `x` and `y` for equality. result = x.re == y.re and x.im == y.im -proc `=~` *(x, y: TComplex): bool = +proc `=~` *(x, y: Complex): bool = ## Compare two complex numbers `x` and `y` approximately. result = abs(x.re-y.re)<EPS and abs(x.im-y.im)<EPS -proc `+` *(x, y: TComplex): TComplex = +proc `+` *(x, y: Complex): Complex = ## Add two complex numbers. result.re = x.re + y.re result.im = x.im + y.im -proc `+` *(x: TComplex, y: float): TComplex = +proc `+` *(x: Complex, y: float): Complex = ## Add complex `x` to float `y`. result.re = x.re + y result.im = x.im -proc `+` *(x: float, y: TComplex): TComplex = +proc `+` *(x: float, y: Complex): Complex = ## Add float `x` to complex `y`. result.re = x + y.re result.im = y.im -proc `-` *(z: TComplex): TComplex = +proc `-` *(z: Complex): Complex = ## Unary minus for complex numbers. result.re = -z.re result.im = -z.im -proc `-` *(x, y: TComplex): TComplex = +proc `-` *(x, y: Complex): Complex = ## Subtract two complex numbers. result.re = x.re - y.re result.im = x.im - y.im -proc `-` *(x: TComplex, y: float): TComplex = +proc `-` *(x: Complex, y: float): Complex = ## Subtracts float `y` from complex `x`. result = x + (-y) -proc `-` *(x: float, y: TComplex): TComplex = +proc `-` *(x: float, y: Complex): Complex = ## Subtracts complex `y` from float `x`. result = x + (-y) -proc `/` *(x, y: TComplex): TComplex = +proc `/` *(x, y: Complex): Complex = ## Divide `x` by `y`. var r, den: float @@ -86,73 +88,73 @@ proc `/` *(x, y: TComplex): TComplex = result.re = (x.re + r * x.im) / den result.im = (x.im - r * x.re) / den -proc `/` *(x : TComplex, y: float ): TComplex = +proc `/` *(x : Complex, y: float ): Complex = ## Divide complex `x` by float `y`. result.re = x.re/y result.im = x.im/y -proc `/` *(x : float, y: TComplex ): TComplex = +proc `/` *(x : float, y: Complex ): Complex = ## Divide float `x` by complex `y`. - var num : TComplex = (x, 0.0) + var num : Complex = (x, 0.0) result = num/y -proc `*` *(x, y: TComplex): TComplex = +proc `*` *(x, y: Complex): Complex = ## Multiply `x` with `y`. result.re = x.re * y.re - x.im * y.im result.im = x.im * y.re + x.re * y.im -proc `*` *(x: float, y: TComplex): TComplex = +proc `*` *(x: float, y: Complex): Complex = ## Multiply float `x` with complex `y`. result.re = x * y.re result.im = x * y.im -proc `*` *(x: TComplex, y: float): TComplex = +proc `*` *(x: Complex, y: float): Complex = ## Multiply complex `x` with float `y`. result.re = x.re * y result.im = x.im * y -proc `+=` *(x: var TComplex, y: TComplex) = +proc `+=` *(x: var Complex, y: Complex) = ## Add `y` to `x`. x.re += y.re x.im += y.im -proc `+=` *(x: var TComplex, y: float) = +proc `+=` *(x: var Complex, y: float) = ## Add `y` to the complex number `x`. x.re += y -proc `-=` *(x: var TComplex, y: TComplex) = +proc `-=` *(x: var Complex, y: Complex) = ## Subtract `y` from `x`. x.re -= y.re x.im -= y.im -proc `-=` *(x: var TComplex, y: float) = +proc `-=` *(x: var Complex, y: float) = ## Subtract `y` from the complex number `x`. x.re -= y -proc `*=` *(x: var TComplex, y: TComplex) = +proc `*=` *(x: var Complex, y: Complex) = ## Multiply `y` to `x`. let im = x.im * y.re + x.re * y.im x.re = x.re * y.re - x.im * y.im x.im = im -proc `*=` *(x: var TComplex, y: float) = +proc `*=` *(x: var Complex, y: float) = ## Multiply `y` to the complex number `x`. x.re *= y x.im *= y -proc `/=` *(x: var TComplex, y: TComplex) = +proc `/=` *(x: var Complex, y: Complex) = ## Divide `x` by `y` in place. x = x / y -proc `/=` *(x : var TComplex, y: float) = +proc `/=` *(x : var Complex, y: float) = ## Divide complex `x` by float `y` in place. x.re /= y x.im /= y -proc abs*(z: TComplex): float = +proc abs*(z: Complex): float = ## Return the distance from (0,0) to `z`. # optimized by checking special cases (sqrt is expensive) @@ -172,7 +174,7 @@ proc abs*(z: TComplex): float = result = y * sqrt(1.0 + temp * temp) -proc sqrt*(z: TComplex): TComplex = +proc sqrt*(z: Complex): Complex = ## Square root for a complex number `z`. var x, y, w, r: float @@ -196,7 +198,7 @@ proc sqrt*(z: TComplex): TComplex = result.re = z.im / (result.im + result.im) -proc exp*(z: TComplex): TComplex = +proc exp*(z: Complex): Complex = ## e raised to the power `z`. var rho = exp(z.re) var theta = z.im @@ -204,21 +206,21 @@ proc exp*(z: TComplex): TComplex = result.im = rho*sin(theta) -proc ln*(z: TComplex): TComplex = +proc ln*(z: Complex): Complex = ## Returns the natural log of `z`. result.re = ln(abs(z)) result.im = arctan2(z.im,z.re) -proc log10*(z: TComplex): TComplex = +proc log10*(z: Complex): Complex = ## Returns the log base 10 of `z`. result = ln(z)/ln(10.0) -proc log2*(z: TComplex): TComplex = +proc log2*(z: Complex): Complex = ## Returns the log base 2 of `z`. result = ln(z)/ln(2.0) -proc pow*(x, y: TComplex): TComplex = +proc pow*(x, y: Complex): Complex = ## `x` raised to the power `y`. if x.re == 0.0 and x.im == 0.0: if y.re == 0.0 and y.im == 0.0: @@ -240,53 +242,53 @@ proc pow*(x, y: TComplex): TComplex = result.im = s*sin(r) -proc sin*(z: TComplex): TComplex = +proc sin*(z: Complex): Complex = ## Returns the sine of `z`. result.re = sin(z.re)*cosh(z.im) result.im = cos(z.re)*sinh(z.im) -proc arcsin*(z: TComplex): TComplex = +proc arcsin*(z: Complex): Complex = ## Returns the inverse sine of `z`. - var i: TComplex = (0.0,1.0) + var i: Complex = (0.0,1.0) result = -i*ln(i*z + sqrt(1.0-z*z)) -proc cos*(z: TComplex): TComplex = +proc cos*(z: Complex): Complex = ## Returns the cosine of `z`. result.re = cos(z.re)*cosh(z.im) result.im = -sin(z.re)*sinh(z.im) -proc arccos*(z: TComplex): TComplex = +proc arccos*(z: Complex): Complex = ## Returns the inverse cosine of `z`. - var i: TComplex = (0.0,1.0) + var i: Complex = (0.0,1.0) result = -i*ln(z + sqrt(z*z-1.0)) -proc tan*(z: TComplex): TComplex = +proc tan*(z: Complex): Complex = ## Returns the tangent of `z`. result = sin(z)/cos(z) -proc cot*(z: TComplex): TComplex = +proc cot*(z: Complex): Complex = ## Returns the cotangent of `z`. result = cos(z)/sin(z) -proc sec*(z: TComplex): TComplex = +proc sec*(z: Complex): Complex = ## Returns the secant of `z`. result = 1.0/cos(z) -proc csc*(z: TComplex): TComplex = +proc csc*(z: Complex): Complex = ## Returns the cosecant of `z`. result = 1.0/sin(z) -proc sinh*(z: TComplex): TComplex = +proc sinh*(z: Complex): Complex = ## Returns the hyperbolic sine of `z`. result = 0.5*(exp(z)-exp(-z)) -proc cosh*(z: TComplex): TComplex = +proc cosh*(z: Complex): Complex = ## Returns the hyperbolic cosine of `z`. result = 0.5*(exp(z)+exp(-z)) -proc `$`*(z: TComplex): string = +proc `$`*(z: Complex): string = ## Returns `z`'s string representation as ``"(re, im)"``. result = "(" & $z.re & ", " & $z.im & ")" diff --git a/lib/pure/concurrency/cpuinfo.nim b/lib/pure/concurrency/cpuinfo.nim index dfa819f64..e55786c3e 100644 --- a/lib/pure/concurrency/cpuinfo.nim +++ b/lib/pure/concurrency/cpuinfo.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/pure/concurrency/cpuload.nim b/lib/pure/concurrency/cpuload.nim index 3cf6a7392..74a639be1 100644 --- a/lib/pure/concurrency/cpuload.nim +++ b/lib/pure/concurrency/cpuload.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim index e0a2ac678..7b0593b3e 100644 --- a/lib/pure/concurrency/threadpool.nim +++ b/lib/pure/concurrency/threadpool.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Implements Nimrod's 'spawn'. +## Implements Nim's 'spawn'. when not compileOption("threads"): {.error: "Threadpool requires --threads:on option.".} @@ -94,7 +94,7 @@ type idx: int FlowVarBase* = ref FlowVarBaseObj ## untyped base class for 'FlowVar[T]' - FlowVarBaseObj = object of TObject + FlowVarBaseObj = object of RootObj ready, usesCondVar: bool cv: CondVar #\ # for 'awaitAny' support @@ -164,7 +164,7 @@ proc cleanFlowVars(w: ptr Worker) = let q = addr(w.q) acquire(q.lock) for i in 0 .. <q.len: - GC_unref(cast[PObject](q.data[i])) + GC_unref(cast[RootRef](q.data[i])) q.len = 0 release(q.lock) signal(q.empty) @@ -189,7 +189,7 @@ proc nimFlowVarSignal(fv: FlowVarBase) {.compilerProc.} = proc awaitAndThen*[T](fv: FlowVar[T]; action: proc (x: T) {.closure.}) = ## blocks until the ``fv`` is available and then passes its value - ## to ``action``. Note that due to Nimrod's parameter passing semantics this + ## to ``action``. Note that due to Nim's parameter passing semantics this ## means that ``T`` doesn't need to be copied and so ``awaitAndThen`` can ## sometimes be more efficient than ``^``. await(fv) diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index 49bf92980..6247efed2 100644 --- a/lib/pure/cookies.nim +++ b/lib/pure/cookies.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ import strtabs, times -proc parseCookies*(s: string): PStringTable = +proc parseCookies*(s: string): StringTableRef = ## parses cookies into a string table. result = newStringTable(modeCaseInsensitive) var i = 0 @@ -42,20 +42,19 @@ proc setCookie*(key, value: string, domain = "", path = "", if secure: result.add("; secure") if httpOnly: result.add("; HttpOnly") -proc setCookie*(key, value: string, expires: TTimeInfo, +proc setCookie*(key, value: string, expires: TimeInfo, domain = "", path = "", noName = false, secure = false, httpOnly = false): string = ## Creates a command in the format of ## ``Set-Cookie: key=value; Domain=...; ...`` ## - ## **Note:** UTC is assumed as the timezone for ``expires``. - + ## **Note:** UTC is assumed as the timezone for ``expires``. return setCookie(key, value, domain, path, format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'UTC'"), noname, secure, httpOnly) - + when isMainModule: - var tim = TTime(int(getTime()) + 76 * (60 * 60 * 24)) + var tim = Time(int(getTime()) + 76 * (60 * 60 * 24)) echo(setCookie("test", "value", tim.getGMTime())) diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index 54a553173..c6794be67 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,31 +12,33 @@ ## Windows ``LoadLibrary``. type - TLibHandle* = pointer ## a handle to a dynamically loaded library + LibHandle* = pointer ## a handle to a dynamically loaded library -proc loadLib*(path: string, global_symbols=false): TLibHandle +{.deprecated: [TLibHandle: LibHandle].} + +proc loadLib*(path: string, global_symbols=false): LibHandle ## loads a library from `path`. Returns nil if the library could not ## be loaded. -proc loadLib*(): TLibHandle +proc loadLib*(): LibHandle ## gets the handle from the current executable. Returns nil if the ## library could not be loaded. -proc unloadLib*(lib: TLibHandle) +proc unloadLib*(lib: LibHandle) ## unloads the library `lib` proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} = ## raises an `EInvalidLibrary` exception. - var e: ref EInvalidLibrary + var e: ref LibraryError new(e) e.msg = "could not find symbol: " & $name raise e -proc symAddr*(lib: TLibHandle, name: cstring): pointer +proc symAddr*(lib: LibHandle, name: cstring): pointer ## retrieves the address of a procedure/variable from `lib`. Returns nil ## if the symbol could not be found. -proc checkedSymAddr*(lib: TLibHandle, name: cstring): pointer = +proc checkedSymAddr*(lib: LibHandle, name: cstring): pointer = ## retrieves the address of a procedure/variable from `lib`. Raises ## `EInvalidLibrary` if the symbol could not be found. result = symAddr(lib, name) @@ -55,19 +57,19 @@ when defined(posix): RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int RTLD_GLOBAL {.importc: "RTLD_GLOBAL", header: "<dlfcn.h>".}: int - proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".} - proc dlopen(path: CString, mode: int): TLibHandle {. + proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".} + proc dlopen(path: cstring, mode: int): LibHandle {. importc, header: "<dlfcn.h>".} - proc dlsym(lib: TLibHandle, name: cstring): pointer {. + proc dlsym(lib: LibHandle, name: cstring): pointer {. importc, header: "<dlfcn.h>".} - proc loadLib(path: string, global_symbols=false): TLibHandle = + proc loadLib(path: string, global_symbols=false): LibHandle = var flags = RTLD_NOW if global_symbols: flags = flags or RTLD_GLOBAL return dlopen(path, flags) - proc loadLib(): TLibHandle = return dlopen(nil, RTLD_NOW) - proc unloadLib(lib: TLibHandle) = dlclose(lib) - proc symAddr(lib: TLibHandle, name: cstring): pointer = + proc loadLib(): LibHandle = return dlopen(nil, RTLD_NOW) + proc unloadLib(lib: LibHandle) = dlclose(lib) + proc symAddr(lib: LibHandle, name: cstring): pointer = return dlsym(lib, name) elif defined(windows) or defined(dos): @@ -85,13 +87,13 @@ elif defined(windows) or defined(dos): proc getProcAddress(lib: THINSTANCE, name: cstring): pointer {. importc: "GetProcAddress", header: "<windows.h>", stdcall.} - proc loadLib(path: string, global_symbols=false): TLibHandle = - result = cast[TLibHandle](winLoadLibrary(path)) - proc loadLib(): TLibHandle = - result = cast[TLibHandle](winLoadLibrary(nil)) - proc unloadLib(lib: TLibHandle) = FreeLibrary(cast[THINSTANCE](lib)) + proc loadLib(path: string, global_symbols=false): LibHandle = + result = cast[LibHandle](winLoadLibrary(path)) + proc loadLib(): LibHandle = + result = cast[LibHandle](winLoadLibrary(nil)) + proc unloadLib(lib: LibHandle) = FreeLibrary(cast[THINSTANCE](lib)) - proc symAddr(lib: TLibHandle, name: cstring): pointer = + proc symAddr(lib: LibHandle, name: cstring): pointer = result = getProcAddress(cast[THINSTANCE](lib), name) else: diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 633ea6020..958a4133b 100644 --- a/lib/pure/encodings.nim +++ b/lib/pure/encodings.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -14,18 +14,20 @@ import os, parseutils, strutils when not defined(windows): type - TConverter = object - PConverter* = ptr TConverter ## can convert between two character sets + ConverterObj = object + EncodingConverter* = ptr ConverterObj ## can convert between two character sets else: type - TCodePage = distinct int32 - PConverter* = object - dest, src: TCodePage + CodePage = distinct int32 + EncodingConverter* = object + dest, src: CodePage type - EInvalidEncoding* = object of EInvalidValue ## exception that is raised - ## for encoding errors + EncodingError* = object of ValueError ## exception that is raised + ## for encoding errors + +{.deprecated: [EInvalidEncoding: EncodingError, PConverter: EncodingConverter].} when defined(windows): proc eqEncodingNames(a, b: string): bool = @@ -34,7 +36,7 @@ when defined(windows): while i < a.len and j < b.len: if a[i] in {'-', '_'}: inc i if b[j] in {'-', '_'}: inc j - if a[i].tolower != b[j].tolower: return false + if a[i].toLower != b[j].toLower: return false inc i inc j result = i == a.len and j == b.len @@ -214,26 +216,26 @@ when defined(windows): defaultChar: array[0..1, char] leadByte: array[0..12-1, char] - proc getCPInfo(codePage: TCodePage, lpCPInfo: var TCpInfo): int32 {. + proc getCPInfo(codePage: CodePage, lpCPInfo: var TCpInfo): int32 {. stdcall, importc: "GetCPInfo", dynlib: "kernel32".} - proc nameToCodePage(name: string): TCodePage = + proc nameToCodePage(name: string): CodePage = var nameAsInt: int if parseInt(name, nameAsInt) == 0: nameAsInt = -1 for no, na in items(winEncodings): - if no == nameAsInt or eqEncodingNames(na, name): return TCodePage(no) - result = TCodePage(-1) + if no == nameAsInt or eqEncodingNames(na, name): return CodePage(no) + result = CodePage(-1) - proc codePageToName(c: TCodePage): string = + proc codePageToName(c: CodePage): string = for no, na in items(winEncodings): if no == int(c): return if na.len != 0: na else: $no result = "" - proc getACP(): TCodePage {.stdcall, importc: "GetACP", dynlib: "kernel32".} + proc getACP(): CodePage {.stdcall, importc: "GetACP", dynlib: "kernel32".} proc multiByteToWideChar( - codePage: TCodePage, + codePage: CodePage, dwFlags: int32, lpMultiByteStr: cstring, cbMultiByte: cint, @@ -242,7 +244,7 @@ when defined(windows): stdcall, importc: "MultiByteToWideChar", dynlib: "kernel32".} proc wideCharToMultiByte( - codePage: TCodePage, + codePage: CodePage, dwFlags: int32, lpWideCharStr: cstring, cchWideChar: cint, @@ -260,7 +262,7 @@ else: else: const iconvDll = "(libc.so.6|libiconv.so)" - when defined(macosx) and defined(powerpc32): + when defined(macosx) and defined(powerpc): const prefix = "lib" else: const prefix = "" @@ -279,50 +281,50 @@ else: var errno {.importc, header: "<errno.h>".}: cint - proc iconvOpen(tocode, fromcode: cstring): PConverter {. + proc iconvOpen(tocode, fromcode: cstring): EncodingConverter {. importc: prefix & "iconv_open", cdecl, dynlib: iconvDll.} - proc iconvClose(c: PConverter) {. + proc iconvClose(c: EncodingConverter) {. importc: prefix & "iconv_close", cdecl, dynlib: iconvDll.} - proc iconv(c: PConverter, inbuf: var cstring, inbytesLeft: var int, + proc iconv(c: EncodingConverter, inbuf: var cstring, inbytesLeft: var int, outbuf: var cstring, outbytesLeft: var int): int {. importc: prefix & "iconv", cdecl, dynlib: iconvDll.} - proc iconv(c: PConverter, inbuf: pointer, inbytesLeft: pointer, + proc iconv(c: EncodingConverter, inbuf: pointer, inbytesLeft: pointer, outbuf: var cstring, outbytesLeft: var int): int {. importc: prefix & "iconv", cdecl, dynlib: iconvDll.} proc getCurrentEncoding*(): string = ## retrieves the current encoding. On Unix, always "UTF-8" is returned. when defined(windows): - result = codePageToName(GetACP()) + result = codePageToName(getACP()) else: result = "UTF-8" -proc open*(destEncoding = "UTF-8", srcEncoding = "CP1252"): PConverter = +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. when not defined(windows): result = iconvOpen(destEncoding, srcEncoding) if result == nil: - raise newException(EInvalidEncoding, + raise newException(EncodingError, "cannot create encoding converter from " & srcEncoding & " to " & destEncoding) else: result.dest = nameToCodePage(destEncoding) result.src = nameToCodePage(srcEncoding) if int(result.dest) == -1: - raise newException(EInvalidEncoding, + raise newException(EncodingError, "cannot find encoding " & destEncoding) if int(result.src) == -1: - raise newException(EInvalidEncoding, + raise newException(EncodingError, "cannot find encoding " & srcEncoding) -proc close*(c: PConverter) = +proc close*(c: EncodingConverter) = ## frees the resources the converter `c` holds. when not defined(windows): iconvClose(c) when defined(windows): - proc convert*(c: PConverter, s: string): string = + proc convert*(c: EncodingConverter, s: string): string = ## converts `s` to `destEncoding` that was given to the converter `c`. It ## assumed that `s` is in `srcEncoding`. @@ -352,7 +354,7 @@ when defined(windows): cbMultiByte = cint(s.len), lpWideCharStr = cstring(result), cchWideChar = cint(cap)) - if m == 0: osError(osLastError()) + if m == 0: raiseOSError(osLastError()) setLen(result, m*2) elif m <= cap: setLen(result, m*2) @@ -389,7 +391,7 @@ when defined(windows): cchWideChar = cint(result.len div 2), lpMultiByteStr = cstring(res), cbMultiByte = cap.cint) - if m == 0: osError(osLastError()) + if m == 0: raiseOSError(osLastError()) setLen(res, m) result = res elif m <= cap: @@ -399,7 +401,7 @@ when defined(windows): assert(false) # cannot happen else: - proc convert*(c: PConverter, s: string): string = + proc convert*(c: EncodingConverter, s: string): string = result = newString(s.len) var inLen = len(s) var outLen = len(result) @@ -412,7 +414,7 @@ else: var lerr = errno if lerr == EILSEQ or lerr == EINVAL: # unknown char, skip - Dst[0] = Src[0] + dst[0] = src[0] src = cast[cstring](cast[int](src) + 1) dst = cast[cstring](cast[int](dst) + 1) dec(inLen) @@ -424,19 +426,19 @@ else: dst = cast[cstring](cast[int](cstring(result)) + offset) outLen = len(result) - offset else: - osError(lerr.TOSErrorCode) + raiseOSError(lerr.OSErrorCode) # iconv has a buffer that needs flushing, specially if the last char is # not '\0' - discard iconv(c, nil, nil, dst, outlen) + discard iconv(c, nil, nil, dst, outLen) if iconvres == cint(-1) and errno == E2BIG: var offset = cast[int](dst) - cast[int](cstring(result)) setLen(result, len(result)+inLen*2+5) # 5 is minimally one utf-8 char dst = cast[cstring](cast[int](cstring(result)) + offset) outLen = len(result) - offset - discard iconv(c, nil, nil, dst, outlen) + discard iconv(c, nil, nil, dst, outLen) # trim output buffer - setLen(result, len(result) - outlen) + setLen(result, len(result) - outLen) proc convert*(s: string, destEncoding = "UTF-8", srcEncoding = "CP1252"): string = diff --git a/lib/pure/endians.nim b/lib/pure/endians.nim index 73017464d..6e33d4624 100644 --- a/lib/pure/endians.nim +++ b/lib/pure/endians.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/pure/events.nim b/lib/pure/events.nim index 5830d9109..47dc6ba3f 100644 --- a/lib/pure/events.nim +++ b/lib/pure/events.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2011 Alex Mitchell # # See the file "copying.txt", included in this @@ -14,10 +14,10 @@ ## 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. ## -## .. code-block:: Nimrod +## .. code-block:: Nim ## var ee = initEventEmitter() -## var genericargs: TEventArgs -## proc handleevent(e: TEventArgs) = +## var genericargs: EventArgs +## proc handleevent(e: EventArgs) = ## echo("Handled!") ## ## # Python way @@ -27,53 +27,56 @@ ## # C/Java way ## # Declare a type ## type -## TSomeObject = object of TObject -## SomeEvent: TEventHandler -## var myobj: TSomeObject +## SomeObject = object of RootObj +## SomeEvent: EventHandler +## var myobj: SomeObject ## myobj.SomeEvent = initEventHandler("SomeEvent") ## myobj.SomeEvent.addHandler(handleevent) ## ee.emit(myobj.SomeEvent, genericargs) type - TEventArgs* = object of TObject ## Base object for event arguments that are passed to callback functions. - TEventHandler* = tuple[name: string, handlers: seq[proc(e:TEventArgs) {.closure.}]] ## An eventhandler for an event. + EventArgs* = object of RootObj ## Base object for event arguments that are passed to callback functions. + EventHandler* = tuple[name: string, handlers: seq[proc(e: EventArgs) {.closure.}]] ## An eventhandler for an event. type - TEventEmitter* = object {.pure, final.} ## An object that fires events and holds event handlers for an object. - s: seq[TEventHandler] - EInvalidEvent* = object of EInvalidValue + EventEmitter* = object ## An object that fires events and holds event handlers for an object. + s: seq[EventHandler] + EventError* = object of ValueError + +{.deprecated: [TEventArgs: EventArgs, TEventHandler: EventHandler, + TEventEmitter: EventEmitter, EInvalidEvent: EventError].} -proc initEventHandler*(name: string): TEventHandler = +proc initEventHandler*(name: string): EventHandler = ## Initializes an EventHandler with the specified name and returns it. result.handlers = @[] result.name = name -proc addHandler*(handler: var TEventHandler, func: proc(e: TEventArgs) {.closure.}) = +proc addHandler*(handler: var EventHandler, func: proc(e: EventArgs) {.closure.}) = ## Adds the callback to the specified event handler. handler.handlers.add(func) -proc removeHandler*(handler: var TEventHandler, func: proc(e: TEventArgs) {.closure.}) = +proc removeHandler*(handler: var EventHandler, func: proc(e: EventArgs) {.closure.}) = ## Removes the callback from the specified event handler. for i in countup(0, len(handler.handlers) -1): if func == handler.handlers[i]: handler.handlers.del(i) break -proc containsHandler*(handler: var TEventHandler, func: proc(e: TEventArgs) {.closure.}): bool = +proc containsHandler*(handler: var EventHandler, func: proc(e: EventArgs) {.closure.}): bool = ## Checks if a callback is registered to this event handler. return handler.handlers.contains(func) -proc clearHandlers*(handler: var TEventHandler) = +proc clearHandlers*(handler: var EventHandler) = ## Clears all of the callbacks from the event handler. setLen(handler.handlers, 0) -proc getEventHandler(emitter: var TEventEmitter, event: string): int = +proc getEventHandler(emitter: var EventEmitter, event: string): int = for k in 0..high(emitter.s): if emitter.s[k].name == event: return k return -1 -proc on*(emitter: var TEventEmitter, event: string, func: proc(e: TEventArgs) {.closure.}) = +proc on*(emitter: var EventEmitter, event: string, func: proc(e: EventArgs) {.closure.}) = ## Assigns a event handler with the specified callback. If the event ## doesn't exist, it will be created. var i = getEventHandler(emitter, event) @@ -84,17 +87,17 @@ proc on*(emitter: var TEventEmitter, event: string, func: proc(e: TEventArgs) {. else: addHandler(emitter.s[i], func) -proc emit*(emitter: var TEventEmitter, eventhandler: var TEventHandler, - args: TEventArgs) = +proc emit*(emitter: var EventEmitter, eventhandler: var EventHandler, + args: EventArgs) = ## Fires an event handler with specified event arguments. for func in items(eventhandler.handlers): func(args) -proc emit*(emitter: var TEventEmitter, event: string, args: TEventArgs) = +proc emit*(emitter: var EventEmitter, event: string, args: EventArgs) = ## Fires an event handler with specified event arguments. var i = getEventHandler(emitter, event) if i >= 0: emit(emitter, emitter.s[i], args) -proc initEventEmitter*(): TEventEmitter = +proc initEventEmitter*(): EventEmitter = ## Creates and returns a new EventEmitter. result.s = @[] diff --git a/lib/pure/fsmonitor.nim b/lib/pure/fsmonitor.nim index b35466771..bf4aef61c 100644 --- a/lib/pure/fsmonitor.nim +++ b/lib/pure/fsmonitor.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Dominik Picheta # # See the file "copying.txt", included in this @@ -25,13 +25,13 @@ else: import inotify, os, asyncio, tables type - PFSMonitor* = ref TFSMonitor - TFSMonitor = object of TObject + FSMonitor* = ref FSMonitorObj + FSMonitorObj = object of RootObj fd: cint - handleEvent: proc (m: PFSMonitor, ev: TMonitorEvent) {.closure.} + handleEvent: proc (m: FSMonitor, ev: MonitorEvent) {.closure.} targets: TTable[cint, string] - TMonitorEventType* = enum ## Monitor event type + MonitorEventType* = enum ## Monitor event type MonitorAccess, ## File was accessed. MonitorAttrib, ## Metadata changed. MonitorCloseWrite, ## Writtable file was closed. @@ -45,8 +45,8 @@ type MonitorOpen, ## File was opened. MonitorAll ## Filter for all event types. - TMonitorEvent* = object - case kind*: TMonitorEventType ## Type of the event. + MonitorEvent* = object + case kind*: MonitorEventType ## Type of the event. of MonitorMoveSelf, MonitorMoved: oldPath*: string ## Old absolute location newPath*: string ## New absolute location @@ -58,6 +58,9 @@ type ## watched. wd*: cint ## Watch descriptor. +{.deprecated: [PFSMonitor: FSMonitor, TFSMonitor: FSMonitorObj, + TMonitorEventType: MonitorEventType, TMonitorEvent: MonitorEvent].} + const MaxEvents = 100 @@ -67,7 +70,7 @@ proc newMonitor*(): PFSMonitor = result.targets = initTable[cint, string]() result.fd = inotifyInit() if result.fd < 0: - OSError(OSLastError()) + raiseOSError(osLastError()) proc add*(monitor: PFSMonitor, target: string, filters = {MonitorAll}): cint {.discardable.} = @@ -93,7 +96,7 @@ proc add*(monitor: PFSMonitor, target: string, result = inotifyAddWatch(monitor.fd, target, INFilter.uint32) if result < 0: - OSError(OSLastError()) + raiseOSError(osLastError()) monitor.targets.add(result, target) proc del*(monitor: PFSMonitor, wd: cint) = @@ -101,7 +104,7 @@ proc del*(monitor: PFSMonitor, wd: cint) = ## ## If ``wd`` is not a part of ``monitor`` an EOS error is raised. if inotifyRmWatch(monitor.fd, wd) < 0: - OSError(OSLastError()) + raiseOSError(osLastError()) proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] = result = @[] @@ -110,8 +113,7 @@ proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] = let le = read(fd, addr(buffer[0]), size) - var movedFrom: TTable[cint, tuple[wd: cint, old: string]] = - initTable[cint, tuple[wd: cint, old: string]]() + var movedFrom = initTable[cint, tuple[wd: cint, old: string]]() var i = 0 while i < le: @@ -197,18 +199,19 @@ proc register*(d: PDispatcher, monitor: PFSMonitor, d.register(deleg) when isMainModule: - var disp = newDispatcher() - var monitor = newMonitor() - echo monitor.add("/home/dom/inotifytests/") - disp.register(monitor, - proc (m: PFSMonitor, ev: TMonitorEvent) = - echo("Got event: ", ev.kind) - if ev.kind == MonitorMoved: - echo("From ", ev.oldPath, " to ", ev.newPath) - echo("Name is ", ev.name) - else: - echo("Name ", ev.name, " fullname ", ev.fullName)) - - while true: - if not disp.poll(): break - + proc main = + var disp = newDispatcher() + var monitor = newMonitor() + echo monitor.add("/home/dom/inotifytests/") + disp.register(monitor, + proc (m: PFSMonitor, ev: TMonitorEvent) = + echo("Got event: ", ev.kind) + if ev.kind == MonitorMoved: + echo("From ", ev.oldPath, " to ", ev.newPath) + echo("Name is ", ev.name) + else: + echo("Name ", ev.name, " fullname ", ev.fullName)) + + while true: + if not disp.poll(): break + main() diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim index e8d3f762e..37b25871d 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Dominik Picheta +# Nim's Runtime Library +# (c) Copyright 2014 Dominik Picheta # See the file "copying.txt", included in this # distribution, for details about the copyright. # @@ -18,8 +18,8 @@ from asyncdispatch import PFuture ## by `RFC 959 <http://tools.ietf.org/html/rfc959>`_. ## ## This module provides both a synchronous and asynchronous implementation. -## The asynchronous implementation requires you to use the ``AsyncFTPClient`` -## function. You are then required to register the ``PAsyncFTPClient`` with a +## The asynchronous implementation requires you to use the ``asyncFTPClient`` +## function. You are then required to register the ``AsyncFTPClient`` with a ## asyncio dispatcher using the ``register`` function. Take a look at the ## asyncio module documentation for more information. ## @@ -28,65 +28,64 @@ from asyncdispatch import PFuture ## ## Here is some example usage of this module: ## -## .. code-block:: Nimrod -## var ftp = FTPClient("example.org", user = "user", pass = "pass") +## .. code-block:: Nim +## var ftp = ftpClient("example.org", user = "user", pass = "pass") ## ftp.connect() ## ftp.retrFile("file.ext", "file.ext") ## ## **Warning:** The API of this module is unstable, and therefore is subject ## to change. - type - PFtpBase*[SockType] = ref TFtpBase[SockType] - TFtpBase*[SockType] = object + FtpBase*[SockType] = ref FtpBaseObj[SockType] + FtpBaseObj*[SockType] = object csock*: SockType dsock*: SockType - when SockType is asyncio.PAsyncSocket: - handleEvent*: proc (ftp: PAsyncFTPClient, ev: TFTPEvent){.closure,gcsafe.} - disp: PDispatcher - asyncDSockID: PDelegate + when SockType is asyncio.AsyncSocket: + handleEvent*: proc (ftp: AsyncFTPClient, ev: FTPEvent){.closure,gcsafe.} + disp: Dispatcher + asyncDSockID: Delegate user*, pass*: string address*: string - when SockType is asyncnet.PAsyncSocket: - port*: rawsockets.TPort + when SockType is asyncnet.AsyncSocket: + port*: rawsockets.Port else: - port*: TPort + port*: Port jobInProgress*: bool - job*: PFTPJob[SockType] + job*: FTPJob[SockType] dsockConnected*: bool FTPJobType* = enum JRetrText, JRetr, JStore - PFtpJob[T] = ref TFtpJob[T] - TFTPJob[T] = object - prc: proc (ftp: PFTPBase[T], async: bool): bool {.nimcall, gcsafe.} + FtpJob[T] = ref FtpJobObj[T] + FTPJobObj[T] = object + prc: proc (ftp: FTPBase[T], async: bool): bool {.nimcall, gcsafe.} case typ*: FTPJobType of JRetrText: lines: string of JRetr, JStore: - file: TFile + file: File filename: string - total: biggestInt # In bytes. - progress: biggestInt # In bytes. - oneSecond: biggestInt # Bytes transferred in one second. + total: BiggestInt # In bytes. + progress: BiggestInt # In bytes. + oneSecond: BiggestInt # Bytes transferred in one second. lastProgressReport: float # Time toStore: string # Data left to upload (Only used with async) else: nil - TFtpClient* = TFtpBase[TSocket] - PFtpClient* = ref TFTPClient + FtpClientObj* = FtpBaseObj[Socket] + FtpClient* = ref FtpClientObj - PAsyncFTPClient* = ref TAsyncFTPClient ## Async alternative to TFTPClient. - TAsyncFTPClient* = TFtpBase[asyncio.PAsyncSocket] + AsyncFtpClient* = ref AsyncFtpClientObj ## Async alternative to TFTPClient. + AsyncFtpClientObj* = FtpBaseObj[asyncio.AsyncSocket] FTPEventType* = enum EvTransferProgress, EvLines, EvRetr, EvStore - TFTPEvent* = object ## Event + FTPEvent* = object ## Event filename*: string case typ*: FTPEventType of EvLines: @@ -94,17 +93,23 @@ type of EvRetr, EvStore: ## Retr/Store operation finished. nil of EvTransferProgress: - bytesTotal*: biggestInt ## Bytes total. - bytesFinished*: biggestInt ## Bytes transferred. - speed*: biggestInt ## Speed in bytes/s + bytesTotal*: BiggestInt ## Bytes total. + bytesFinished*: BiggestInt ## Bytes transferred. + speed*: BiggestInt ## Speed in bytes/s currentJob*: FTPJobType ## The current job being performed. - EInvalidReply* = object of ESynch - EFTP* = object of ESynch + ReplyError* = object of IOError + FTPError* = object of IOError + +{.deprecated: [ + TFTPClient: FTPClientObj, TFTPJob: FTPJob, PAsyncFTPClient: AsyncFTPClient, + TAsyncFTPClient: AsyncFTPClientObj, TFTPEvent: FTPEvent, + EInvalidReply: ReplyError, EFTP: FTPError +].} proc ftpClient*(address: string, port = TPort(21), - user, pass = ""): PFTPClient = - ## Create a ``PFTPClient`` object. + user, pass = ""): FtpClient = + ## Create a ``FtpClient`` object. new(result) result.user = user result.pass = pass @@ -113,13 +118,7 @@ proc ftpClient*(address: string, port = TPort(21), result.dsockConnected = false result.csock = socket() - if result.csock == InvalidSocket: osError(osLastError()) - -proc getDSock[T](ftp: PFTPBase[T]): TSocket = - return ftp.dsock - -proc getCSock[T](ftp: PFTPBase[T]): TSocket = - return ftp.csock + if result.csock == invalidSocket: raiseOSError(osLastError()) template blockingOperation(sock: TSocket, body: stmt) {.immediate.} = body @@ -129,16 +128,19 @@ template blockingOperation(sock: asyncio.PAsyncSocket, body: stmt) {.immediate.} body sock.setBlocking(false) -proc expectReply[T](ftp: PFtpBase[T]): TaintedString = +proc expectReply[T](ftp: FtpBase[T]): TaintedString = result = TaintedString"" - blockingOperation(ftp.getCSock()): - ftp.getCSock().readLine(result) + blockingOperation(ftp.csock): + when T is Socket: + ftp.csock.readLine(result) + else: + discard ftp.csock.readLine(result) -proc send*[T](ftp: PFtpBase[T], m: string): TaintedString = +proc send*[T](ftp: FtpBase[T], m: string): TaintedString = ## Send a message to the server, and wait for a primary reply. ## ``\c\L`` is added for you. - blockingOperation(ftp.getCSock()): - ftp.getCSock().send(m & "\c\L") + blockingOperation(ftp.csock): + ftp.csock.send(m & "\c\L") return ftp.expectReply() proc assertReply(received: TaintedString, expected: string) = @@ -154,8 +156,8 @@ proc assertReply(received: TaintedString, expected: varargs[string]) = "Expected reply '$1' got: $2" % [expected.join("' or '"), received.string]) -proc createJob[T](ftp: PFtpBase[T], - prc: proc (ftp: PFtpBase[T], async: bool): bool {. +proc createJob[T](ftp: FtpBase[T], + prc: proc (ftp: FtpBase[T], async: bool): bool {. nimcall,gcsafe.}, cmd: FTPJobType) = if ftp.jobInProgress: @@ -170,7 +172,7 @@ proc createJob[T](ftp: PFtpBase[T], of JRetr, JStore: ftp.job.toStore = "" -proc deleteJob[T](ftp: PFtpBase[T]) = +proc deleteJob[T](ftp: FtpBase[T]) = assert ftp.jobInProgress ftp.jobInProgress = false case ftp.job.typ @@ -215,13 +217,13 @@ proc handleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) = # 226 from csock. assert(not ftp.job.prc(ftp, true)) -proc pasv[T](ftp: PFtpBase[T]) = +proc pasv[T](ftp: FtpBase[T]) = ## Negotiate a data connection. when T is TSocket: ftp.dsock = socket() - if ftp.dsock == InvalidSocket: osError(osLastError()) + if ftp.dsock == invalidSocket: raiseOSError(osLastError()) elif T is PAsyncSocket: - ftp.dsock = AsyncSocket() + ftp.dsock = asyncSocket() ftp.dsock.handleRead = proc (s: PAsyncSocket) = handleRead(s, ftp) @@ -244,14 +246,14 @@ proc pasv[T](ftp: PFtpBase[T]) = var properPort = port[0].parseInt()*256+port[1].parseInt() ftp.dsock.connect(ip.join("."), TPort(properPort.toU16)) when T is PAsyncSocket: - ftp.dsockConnected = False + ftp.dsockConnected = false else: - ftp.dsockConnected = True + ftp.dsockConnected = true proc normalizePathSep(path: string): string = return replace(path, '\\', '/') -proc connect*[T](ftp: PFtpBase[T]) = +proc connect*[T](ftp: FtpBase[T]) = ## Connect to the FTP server specified by ``ftp``. when T is PAsyncSocket: blockingOperation(ftp.csock): @@ -270,21 +272,21 @@ proc connect*[T](ftp: PFtpBase[T]) = if ftp.pass != "": assertReply ftp.send("PASS " & ftp.pass), "230" -proc pwd*(ftp: PFTPClient): string = +proc pwd*[T](ftp: FtpBase[T]): string = ## Returns the current working directory. var wd = ftp.send("PWD") assertReply wd, "257" return wd.string.captureBetween('"') # " -proc cd*(ftp: PFTPClient, dir: string) = +proc cd*[T](ftp: FtpBase[T], dir: string) = ## Changes the current directory on the remote FTP server to ``dir``. assertReply ftp.send("CWD " & dir.normalizePathSep), "250" -proc cdup*(ftp: PFTPClient) = +proc cdup*[T](ftp: FtpBase[T]) = ## Changes the current directory to the parent of the current directory. assertReply ftp.send("CDUP"), "200" -proc getLines[T](ftp: PFtpBase[T], async: bool = false): bool = +proc getLines[T](ftp: FtpBase[T], async: bool = false): bool = ## Downloads text data in ASCII mode ## Returns true if the download is complete. ## It doesn't if `async` is true, because it doesn't check for 226 then. @@ -307,14 +309,14 @@ proc getLines[T](ftp: PFtpBase[T], async: bool = false): bool = {.fatal: "Incorrect socket instantiation".} if not async: - var readSocks: seq[TSocket] = @[ftp.getCSock()] + var readSocks: seq[TSocket] = @[ftp.csock] # This is only needed here. Asyncio gets this socket... - blockingOperation(ftp.getCSock()): - if readSocks.select(1) != 0 and ftp.getCSock() in readSocks: + blockingOperation(ftp.csock): + if readSocks.select(1) != 0 and ftp.csock in readSocks: assertReply ftp.expectReply(), "226" return true -proc listDirs*[T](ftp: PFtpBase[T], dir: string = "", +proc listDirs*[T](ftp: FtpBase[T], dir: string = "", async = false): seq[string] = ## Returns a list of filenames in the given directory. If ``dir`` is "", ## the current directory is used. If ``async`` is true, this @@ -332,7 +334,7 @@ proc listDirs*[T](ftp: PFtpBase[T], dir: string = "", ftp.deleteJob() else: return @[] -proc fileExists*(ftp: PFTPClient, file: string): bool {.deprecated.} = +proc fileExists*(ftp: FtpClient, file: string): bool {.deprecated.} = ## **Deprecated since version 0.9.0:** Please use ``existsFile``. ## ## Determines whether ``file`` exists. @@ -343,7 +345,7 @@ proc fileExists*(ftp: PFTPClient, file: string): bool {.deprecated.} = for f in items(files): if f.normalizePathSep == file.normalizePathSep: return true -proc existsFile*(ftp: PFTPClient, file: string): bool = +proc existsFile*(ftp: FtpClient, file: string): bool = ## Determines whether ``file`` exists. ## ## Warning: This function may block. Especially on directories with many @@ -352,7 +354,7 @@ proc existsFile*(ftp: PFTPClient, file: string): bool = for f in items(files): if f.normalizePathSep == file.normalizePathSep: return true -proc createDir*(ftp: PFTPClient, dir: string, recursive: bool = false) = +proc createDir*[T](ftp: FtpBase[T], dir: string, recursive: bool = false) = ## Creates a directory ``dir``. If ``recursive`` is true, the topmost ## subdirectory of ``dir`` will be created first, following the secondmost... ## etc. this allows you to give a full path as the ``dir`` without worrying @@ -362,14 +364,14 @@ proc createDir*(ftp: PFTPClient, dir: string, recursive: bool = false) = else: var reply = TaintedString"" var previousDirs = "" - for p in split(dir, {os.dirSep, os.altSep}): + for p in split(dir, {os.DirSep, os.AltSep}): if p != "": previousDirs.add(p) reply = ftp.send("MKD " & previousDirs) previousDirs.add('/') assertReply reply, "257" -proc chmod*(ftp: PFTPClient, path: string, +proc chmod*[T](ftp: FtpBase[T], path: string, permissions: set[TFilePermission]) = ## Changes permission of ``path`` to ``permissions``. var userOctal = 0 @@ -391,7 +393,7 @@ proc chmod*(ftp: PFTPClient, path: string, assertReply ftp.send("SITE CHMOD " & perm & " " & path.normalizePathSep), "200" -proc list*[T](ftp: PFtpBase[T], dir: string = "", async = false): string = +proc list*[T](ftp: FtpBase[T], dir: string = "", async = false): string = ## Lists all files in ``dir``. If ``dir`` is ``""``, uses the current ## working directory. If ``async`` is true, this function will return ## immediately and it will be your job to call asyncio's @@ -408,7 +410,7 @@ proc list*[T](ftp: PFtpBase[T], dir: string = "", async = false): string = else: return "" -proc retrText*[T](ftp: PFtpBase[T], file: string, async = false): string = +proc retrText*[T](ftp: FtpBase[T], file: string, async = false): string = ## Retrieves ``file``. File must be ASCII text. ## If ``async`` is true, this function will return immediately and ## it will be your job to call asyncio's ``poll`` to progress this operation. @@ -423,7 +425,7 @@ proc retrText*[T](ftp: PFtpBase[T], file: string, async = false): string = else: return "" -proc getFile[T](ftp: PFtpBase[T], async = false): bool = +proc getFile[T](ftp: FtpBase[T], async = false): bool = if ftp.dsockConnected: var r = "".TaintedString var bytesRead = 0 @@ -435,7 +437,7 @@ proc getFile[T](ftp: PFtpBase[T], async = false): bool = bytesRead = ftp.dsock.recvAsync(r, BufferSize) returned = bytesRead != -1 else: - bytesRead = getDSock(ftp).recv(r, BufferSize) + bytesRead = ftp.dsock.recv(r, BufferSize) returned = true let r2 = r.string if r2 != "": @@ -443,16 +445,16 @@ proc getFile[T](ftp: PFtpBase[T], async = false): bool = ftp.job.oneSecond.inc(r2.len) ftp.job.file.write(r2) elif returned and r2 == "": - ftp.dsockConnected = False + ftp.dsockConnected = false if not async: - var readSocks: seq[TSocket] = @[ftp.getCSock()] - blockingOperation(ftp.getCSock()): - if readSocks.select(1) != 0 and ftp.getCSock() in readSocks: + var readSocks: seq[TSocket] = @[ftp.csock] + blockingOperation(ftp.csock): + if readSocks.select(1) != 0 and ftp.csock in readSocks: assertReply ftp.expectReply(), "226" return true -proc retrFile*[T](ftp: PFtpBase[T], file, dest: string, async = false) = +proc retrFile*[T](ftp: FtpBase[T], file, dest: string, async = false) = ## Downloads ``file`` and saves it to ``dest``. Usage of this function ## asynchronously is recommended to view the progress of the download. ## The ``EvRetr`` event is passed to the specified ``handleEvent`` function @@ -465,7 +467,7 @@ proc retrFile*[T](ftp: PFtpBase[T], file, dest: string, async = false) = assertReply reply, ["125", "150"] if {'(', ')'} notin reply.string: raise newException(EInvalidReply, "Reply has no file size.") - var fileSize: biggestInt + var fileSize: BiggestInt if reply.string.captureBetween('(', ')').parseBiggestInt(fileSize) == 0: raise newException(EInvalidReply, "Reply has no file size.") @@ -477,7 +479,7 @@ proc retrFile*[T](ftp: PFtpBase[T], file, dest: string, async = false) = while not ftp.job.prc(ftp, false): discard ftp.deleteJob() -proc doUpload[T](ftp: PFtpBase[T], async = false): bool = +proc doUpload[T](ftp: FtpBase[T], async = false): bool = if ftp.dsockConnected: if ftp.job.toStore.len() > 0: assert(async) @@ -503,7 +505,7 @@ proc doUpload[T](ftp: PFtpBase[T], async = false): bool = return false if not async: - getDSock(ftp).send(s) + ftp.dsock.send(s) else: let bytesSent = ftp.dsock.sendAsync(s) if bytesSent == 0: @@ -515,7 +517,7 @@ proc doUpload[T](ftp: PFtpBase[T], async = false): bool = ftp.job.progress.inc(len) ftp.job.oneSecond.inc(len) -proc store*[T](ftp: PFtpBase[T], file, dest: string, async = false) = +proc store*[T](ftp: FtpBase[T], file, dest: string, async = false) = ## Uploads ``file`` to ``dest`` on the remote FTP server. Usage of this ## function asynchronously is recommended to view the progress of ## the download. @@ -535,7 +537,7 @@ proc store*[T](ftp: PFtpBase[T], file, dest: string, async = false) = while not ftp.job.prc(ftp, false): discard ftp.deleteJob() -proc close*[T](ftp: PFTPBase[T]) = +proc close*[T](ftp: FtpBase[T]) = ## Terminates the connection to the server. assertReply ftp.send("QUIT"), "221" if ftp.jobInProgress: ftp.deleteJob() @@ -571,7 +573,7 @@ proc asyncFTPClient*(address: string, port = TPort(21), ## Create a ``PAsyncFTPClient`` object. ## ## Use this if you want to use asyncio's dispatcher. - var dres: PAsyncFTPClient + var dres: AsyncFtpClient new(dres) dres.user = user dres.pass = pass @@ -579,9 +581,9 @@ proc asyncFTPClient*(address: string, port = TPort(21), dres.port = port dres.dsockConnected = false dres.handleEvent = handleEvent - dres.csock = AsyncSocket() + dres.csock = asyncSocket() dres.csock.handleRead = - proc (s: PAsyncSocket) = + proc (s: AsyncSocket) = csockHandleRead(s, dres) result = dres @@ -594,7 +596,7 @@ when isMainModule: proc main = var d = newDispatcher() let hev = - proc (ftp: PAsyncFTPClient, event: TFTPEvent) = + proc (ftp: AsyncFTPClient, event: FTPEvent) = case event.typ of EvStore: echo("Upload finished!") diff --git a/lib/pure/future.nim b/lib/pure/future.nim index b7df05207..7d791e16c 100644 --- a/lib/pure/future.nim +++ b/lib/pure/future.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # # See the file "copying.txt", included in this @@ -53,7 +53,7 @@ proc createProcType(p, b: PNimrodNode): PNimrodNode {.compileTime.} = macro `=>`*(p, b: expr): expr {.immediate.} = ## Syntax sugar for anonymous procedures. ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## proc passTwoAndTwo(f: (int, int) -> int): int = ## f(2, 2) @@ -104,7 +104,7 @@ macro `=>`*(p, b: expr): expr {.immediate.} = macro `->`*(p, b: expr): expr {.immediate.} = ## Syntax sugar for procedure types. ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## proc pass2(f: (float, float) -> float): float = ## f(2, 2) diff --git a/lib/pure/gentabs.nim b/lib/pure/gentabs.nim index 617473c14..a6128efc9 100644 --- a/lib/pure/gentabs.nim +++ b/lib/pure/gentabs.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -9,9 +9,11 @@ ## The ``gentabs`` module implements an efficient hash table that is a ## key-value mapping. The keys are required to be strings, but the values -## may be any Nimrod or user defined type. This module supports matching +## may be any Nim or user defined type. This module supports matching ## of keys in case-sensitive, case-insensitive and style-insensitive modes. +{.deprecated.} + import os, hashes, strutils @@ -23,7 +25,7 @@ type TGenKeyValuePair[T] = tuple[key: string, val: T] TGenKeyValuePairSeq[T] = seq[TGenKeyValuePair[T]] - TGenTable*[T] = object of TObject + TGenTable*[T] = object of RootObj counter: int data: TGenKeyValuePairSeq[T] mode: TGenTableMode @@ -72,16 +74,16 @@ proc newGenTable*[T](mode: TGenTableMode): PGenTable[T] = proc nextTry(h, maxHash: THash): THash {.inline.} = result = ((5 * h) + 1) and maxHash -proc RawGet[T](tbl: PGenTable[T], key: string): int = +proc rawGet[T](tbl: PGenTable[T], key: string): int = var h: THash h = myhash(tbl, key) and high(tbl.data) # start with real hash value while not isNil(tbl.data[h].key): - if mycmp(tbl, tbl.data[h].key, key): + if myCmp(tbl, tbl.data[h].key, key): return h h = nextTry(h, high(tbl.data)) result = - 1 -proc RawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T], +proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T], key: string, val: T) = var h: THash h = myhash(tbl, key) and high(data) @@ -90,12 +92,12 @@ proc RawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T], data[h].key = key data[h].val = val -proc Enlarge[T](tbl: PGenTable[T]) = +proc enlarge[T](tbl: PGenTable[T]) = var n: TGenKeyValuePairSeq[T] newSeq(n, len(tbl.data) * growthFactor) for i in countup(0, high(tbl.data)): if not isNil(tbl.data[i].key): - RawInsert[T](tbl, n, tbl.data[i].key, tbl.data[i].val) + rawInsert[T](tbl, n, tbl.data[i].key, tbl.data[i].val) swap(tbl.data, n) proc hasKey*[T](tbl: PGenTable[T], key: string): bool = @@ -106,17 +108,17 @@ proc `[]`*[T](tbl: PGenTable[T], key: string): T = ## retrieves the value at ``tbl[key]``. If `key` is not in `tbl`, ## default(T) is returned and no exception is raised. One can check ## with ``hasKey`` whether the key exists. - var index = RawGet(tbl, key) + var index = rawGet(tbl, key) if index >= 0: result = tbl.data[index].val proc `[]=`*[T](tbl: PGenTable[T], key: string, val: T) = ## puts a (key, value)-pair into `tbl`. - var index = RawGet(tbl, key) + var index = rawGet(tbl, key) if index >= 0: tbl.data[index].val = val else: - if mustRehash(len(tbl.data), tbl.counter): Enlarge(tbl) - RawInsert(tbl, tbl.data, key, val) + if mustRehash(len(tbl.data), tbl.counter): enlarge(tbl) + rawInsert(tbl, tbl.data, key, val) inc(tbl.counter) diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim index 740355e55..30daaf2dc 100644 --- a/lib/pure/hashes.nim +++ b/lib/pure/hashes.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -8,13 +8,13 @@ # ## This module implements efficient computations of hash values for diverse -## Nimrod types. All the procs are based on these two building blocks: the `!& +## Nim types. All the procs are based on these two building blocks: the `!& ## proc <#!&>`_ used to start or mix a hash value, and the `!$ proc <#!$>`_ ## used to *finish* the hash value. If you want to implement hash procs for ## your custom types you will end up writing the following kind of skeleton of ## code: ## -## .. code-block:: nimrod +## .. code-block:: Nim ## proc hash(x: Something): THash = ## ## Computes a THash from `x`. ## var h: THash = 0 @@ -29,7 +29,7 @@ ## like for example objects made up of ``strings``, you can simply hash ## together the hash value of the individual fields: ## -## .. code-block:: nimrod +## .. code-block:: Nim ## proc hash(x: Something): THash = ## ## Computes a THash from `x`. ## var h: THash = 0 diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index b9d6aec7b..a1440b6f4 100644 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -18,13 +18,13 @@ ## ## Example: ## -## .. code-block:: nimrod -## var nim = "Nimrod" -## echo h1(a(href="http://nimrod-lang.org", nim)) +## .. code-block:: Nim +## var nim = "Nim" +## echo h1(a(href="http://nim-lang.org", nim)) ## ## Writes the string:: ## -## <h1><a href="http://nimrod-lang.org">Nimrod</a></h1> +## <h1><a href="http://nim-lang.org">Nim</a></h1> ## import @@ -53,8 +53,7 @@ proc delete[T](s: var seq[T], attr: T): bool = setLen(s, L-1) result = true -proc xmlCheckedTag*(e: PNimrodNode, tag: string, - optAttr = "", reqAttr = "", +proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "", isLeaf = false): PNimrodNode {.compileTime.} = ## use this procedure to define a new XML tag @@ -484,7 +483,7 @@ macro `var`*(e: expr): expr {.immediate.} = result = xmlCheckedTag(e, "var", commonAttr) when isMainModule: - var nim = "Nimrod" - echo h1(a(href="http://nimrod-code.org", nim)) + var nim = "Nim" + echo h1(a(href="http://nim-lang.org", nim)) echo form(action="test", `accept-charset` = "Content-Type") diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim index c38eb7063..e2cbb4949 100644 --- a/lib/pure/htmlparser.nim +++ b/lib/pure/htmlparser.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,7 +13,7 @@ ## It can be used to parse a wild HTML document and output it as valid XHTML ## document (well, if you are lucky): ## -## .. code-block:: nimrod +## .. code-block:: Nim ## ## echo loadHtml("mydirty.html") ## @@ -29,7 +29,7 @@ ## and write back the modified version. In this case we look for hyperlinks ## ending with the extension ``.rst`` and convert them to ``.html``. ## -## .. code-block:: nimrod +## .. code-block:: Nim ## ## import htmlparser ## import xmltree # To use '$' for PXmlNode @@ -422,7 +422,7 @@ proc toHtmlTag(s: string): THtmlTag = of "wbr": tagWbr else: tagUnknown -proc htmlTag*(n: PXmlNode): THtmlTag = +proc htmlTag*(n: XmlNode): THtmlTag = ## gets `n`'s tag as a ``THtmlTag``. if n.clientData == 0: n.clientData = toHtmlTag(n.tag).ord @@ -438,24 +438,24 @@ proc entityToUtf8*(entity: string): string = ## converts an HTML entity name like ``Ü`` to its UTF-8 equivalent. ## "" is returned if the entity name is unknown. The HTML parser ## already converts entities to UTF-8. - for name, val in items(entities): - if name == entity: return toUTF8(TRune(val)) + for name, val in items(Entities): + if name == entity: return toUTF8(Rune(val)) result = "" -proc addNode(father, son: PXmlNode) = +proc addNode(father, son: XmlNode) = if son != nil: add(father, son) -proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode +proc parse(x: var XmlParser, errors: var seq[string]): XmlNode -proc expected(x: var TXmlParser, n: PXmlNode): string = +proc expected(x: var XmlParser, n: XmlNode): string = result = errorMsg(x, "</" & n.tag & "> expected") template elemName(x: expr): expr = rawData(x) -proc untilElementEnd(x: var TXmlParser, result: PXmlNode, +proc untilElementEnd(x: var XmlParser, result: XmlNode, errors: var seq[string]) = # we parsed e.g. ``<br>`` and don't really expect a ``</br>``: - if result.htmlTag in singleTags: + if result.htmlTag in SingleTags: if x.kind != xmlElementEnd or cmpIgnoreCase(x.elemName, result.tag) != 0: return while true: @@ -496,7 +496,7 @@ proc untilElementEnd(x: var TXmlParser, result: PXmlNode, else: result.addNode(parse(x, errors)) -proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode = +proc parse(x: var XmlParser, errors: var seq[string]): XmlNode = case x.kind of xmlComment: result = newComment(x.rawData) @@ -549,11 +549,11 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode = next(x) of xmlEof: discard -proc parseHtml*(s: PStream, filename: string, - errors: var seq[string]): PXmlNode = +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. - var x: TXmlParser + var x: XmlParser open(x, s, filename, {reportComments, reportWhitespace}) next(x) # skip the DOCTYPE: @@ -573,21 +573,21 @@ proc parseHtml*(s: PStream, filename: string, if result.len == 1: result = result[0] -proc parseHtml*(s: PStream): PXmlNode = +proc parseHtml*(s: Stream): XmlNode = ## parses the XTML from stream `s` and returns a ``PXmlNode``. All parsing ## errors are ignored. var errors: seq[string] = @[] result = parseHtml(s, "unknown_html_doc", errors) -proc loadHtml*(path: string, errors: var seq[string]): PXmlNode = +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 ## the `errors` sequence. var s = newFileStream(path, fmRead) - if s == nil: raise newException(EIO, "Unable to read file: " & path) + if s == nil: raise newException(IOError, "Unable to read file: " & path) result = parseHtml(s, path, errors) -proc loadHtml*(path: string): PXmlNode = +proc loadHtml*(path: string): XmlNode = ## Loads and parses HTML from file specified by ``path``, and returns ## a ``PXmlNode``. All parsing errors are ignored. var errors: seq[string] = @[] @@ -600,7 +600,7 @@ when isMainModule: var x = loadHtml(paramStr(1), errors) for e in items(errors): echo e - var f: TFile + var f: File if open(f, "test.txt", fmWrite): f.write($x) f.close() diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 4db6ac6ed..892ddac40 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Dominik Picheta, Andreas Rumpf # # See the file "copying.txt", included in this @@ -21,7 +21,7 @@ ## This example uses HTTP GET to retrieve ## ``http://google.com`` ## -## .. code-block:: nimrod +## .. code-block:: Nim ## echo(getContent("http://google.com")) ## ## Using HTTP POST @@ -31,7 +31,7 @@ ## uses ``multipart/form-data`` as the ``Content-Type`` to send the HTML to ## the server. ## -## .. code-block:: nimrod +## .. code-block:: Nim ## var headers: string = "Content-Type: multipart/form-data; boundary=xyz\c\L" ## var body: string = "--xyz\c\L" ## # soap 1.2 output @@ -48,13 +48,26 @@ ## ## echo(postContent("http://validator.w3.org/check", headers, body)) ## +## Asynchronous HTTP requests +## ========================== +## +## You simply have to create a new instance of the ``AsyncHttpClient`` object. +## You may then use ``await`` on the functions defined for that object. +## Keep in mind that the following code needs to be inside an asynchronous +## procedure. +## +## .. code-block::nim +## +## var client = newAsyncHttpClient() +## var resp = await client.request("http://google.com") +## ## SSL/TLS support ## =============== ## This requires the OpenSSL library, fortunately it's widely used and installed ## on many operating systems. httpclient will use SSL automatically if you give ## any of the functions a url with the ``https`` schema, for example: ## ``https://github.com/``, you also have to compile with ``ssl`` defined like so: -## ``nimrod c -d:ssl ...``. +## ``nim c -d:ssl ...``. ## ## Timeouts ## ======== @@ -78,36 +91,41 @@ import sockets, strutils, parseurl, parseutils, strtabs, base64, os import asyncnet, asyncdispatch import rawsockets +from net import nil type - TResponse* = tuple[ + Response* = tuple[ version: string, status: string, - headers: PStringTable, + headers: StringTableRef, body: string] - PProxy* = ref object + Proxy* = ref object url*: TUrl auth*: string - EInvalidProtocol* = object of ESynch ## exception that is raised when server + ProtocolError* = object of IOError ## exception that is raised when server ## does not conform to the implemented ## protocol - EHttpRequestErr* = object of ESynch ## Thrown in the ``getContent`` proc - ## and ``postContent`` proc, - ## when the server returns an error + HttpRequestError* = object of IOError ## Thrown in the ``getContent`` proc + ## and ``postContent`` proc, + ## when the server returns an error -const defUserAgent* = "Nimrod httpclient/0.1" +{.deprecated: [TResponse: Response, PProxy: Proxy, + EInvalidProtocol: ProtocolError, EHttpRequestErr: HttpRequestError +].} + +const defUserAgent* = "Nim httpclient/0.1" proc httpError(msg: string) = - var e: ref EInvalidProtocol + var e: ref ProtocolError new(e) e.msg = msg raise e proc fileError(msg: string) = - var e: ref EIO + var e: ref IOError new(e) e.msg = msg raise e @@ -160,16 +178,17 @@ proc parseBody(s: TSocket, headers: PStringTable, timeout: int): string = var contentLengthHeader = headers["Content-Length"] if contentLengthHeader != "": var length = contentLengthHeader.parseint() - result = newString(length) - var received = 0 - while true: - if received >= length: break - let r = s.recv(addr(result[received]), length-received, timeout) - if r == 0: break - received += r - if received != length: - httpError("Got invalid content length. Expected: " & $length & - " got: " & $received) + if length > 0: + result = newString(length) + var received = 0 + while true: + if received >= length: break + let r = s.recv(addr(result[received]), length-received, timeout) + if r == 0: break + received += r + if received != length: + httpError("Got invalid content length. Expected: " & $length & + " got: " & $received) else: # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO @@ -177,7 +196,7 @@ proc parseBody(s: TSocket, headers: PStringTable, timeout: int): string = # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5 if headers["Connection"] == "close": var buf = "" - while True: + while true: buf = newString(4000) let r = s.recv(addr(buf[0]), 4000, timeout) if r == 0: break @@ -190,7 +209,7 @@ proc parseResponse(s: TSocket, getBody: bool, timeout: int): TResponse = var fullyRead = false var line = "" result.headers = newStringTable(modeCaseInsensitive) - while True: + while true: line = "" linei = 0 s.readLine(line, timeout) @@ -232,7 +251,7 @@ proc parseResponse(s: TSocket, getBody: bool, timeout: int): TResponse = result.body = "" type - THttpMethod* = enum ## the requested HttpMethod + HttpMethod* = enum ## the requested HttpMethod httpHEAD, ## Asks for the response identical to the one that would ## correspond to a GET request, but without the response ## body. @@ -250,6 +269,8 @@ type httpCONNECT ## Converts the request connection to a transparent ## TCP/IP tunnel, usually used for proxies. +{.deprecated: [THttpMethod: HttpMethod].} + when not defined(ssl): type PSSLContext = ref object let defaultSSLContext: PSSLContext = nil @@ -288,7 +309,7 @@ proc request*(url: string, httpMethod = httpGET, extraHeaders = "", add(headers, "\c\L") var s = socket() - if s == InvalidSocket: osError(osLastError()) + if s == invalidSocket: raiseOSError(osLastError()) var port = sockets.TPort(80) if r.scheme == "https": when defined(ssl): @@ -315,7 +336,7 @@ proc redirection(status: string): bool = const redirectionNRs = ["301", "302", "303", "307"] for i in items(redirectionNRs): if status.startsWith(i): - return True + return true proc getNewLocation(lastUrl: string, headers: PStringTable): string = result = headers["Location"] @@ -431,16 +452,20 @@ proc generateHeaders(r: TURL, httpMethod: THttpMethod, add(result, "\c\L") type - PAsyncHttpClient* = ref object - socket: PAsyncSocket + AsyncHttpClient* = ref object + socket: AsyncSocket connected: bool currentURL: TURL ## Where we are currently connected. - headers: PStringTable + headers: StringTableRef maxRedirects: int userAgent: string + when defined(ssl): + sslContext: net.SslContext + +{.deprecated: [PAsyncHttpClient: AsyncHttpClient].} proc newAsyncHttpClient*(userAgent = defUserAgent, - maxRedirects = 5): PAsyncHttpClient = + maxRedirects = 5, sslContext = defaultSslContext): AsyncHttpClient = ## Creates a new PAsyncHttpClient instance. ## ## ``userAgent`` specifies the user agent that will be used when making @@ -448,18 +473,22 @@ proc newAsyncHttpClient*(userAgent = defUserAgent, ## ## ``maxRedirects`` specifies the maximum amount of redirects to follow, ## default is 5. + ## + ## ``sslContext`` specifies the SSL context to use for HTTPS requests. new result result.headers = newStringTable(modeCaseInsensitive) result.userAgent = defUserAgent result.maxRedirects = maxRedirects + when defined(ssl): + result.sslContext = net.SslContext(sslContext) -proc close*(client: PAsyncHttpClient) = +proc close*(client: AsyncHttpClient) = ## Closes any connections held by the HTTP client. if client.connected: client.socket.close() client.connected = false -proc recvFull(socket: PAsyncSocket, size: int): PFuture[string] {.async.} = +proc recvFull(socket: PAsyncSocket, size: int): Future[string] {.async.} = ## Ensures that all the data requested is read and returned. result = "" while true: @@ -468,7 +497,7 @@ proc recvFull(socket: PAsyncSocket, size: int): PFuture[string] {.async.} = if data == "": break # We've been disconnected. result.add data -proc parseChunks(client: PAsyncHttpClient): PFuture[string] {.async.} = +proc parseChunks(client: PAsyncHttpClient): Future[string] {.async.} = result = "" var ri = 0 while true: @@ -501,7 +530,7 @@ proc parseChunks(client: PAsyncHttpClient): PFuture[string] {.async.} = # them: http://tools.ietf.org/html/rfc2616#section-3.6.1 proc parseBody(client: PAsyncHttpClient, - headers: PStringTable): PFuture[string] {.async.} = + headers: PStringTable): Future[string] {.async.} = result = "" if headers["Transfer-Encoding"] == "chunked": result = await parseChunks(client) @@ -511,12 +540,13 @@ proc parseBody(client: PAsyncHttpClient, var contentLengthHeader = headers["Content-Length"] if contentLengthHeader != "": var length = contentLengthHeader.parseint() - result = await client.socket.recvFull(length) - if result == "": - httpError("Got disconnected while trying to read body.") - if result.len != length: - httpError("Received length doesn't match expected length. Wanted " & - $length & " got " & $result.len) + if length > 0: + result = await client.socket.recvFull(length) + if result == "": + httpError("Got disconnected while trying to read body.") + if result.len != length: + httpError("Received length doesn't match expected length. Wanted " & + $length & " got " & $result.len) else: # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.4 TODO @@ -524,19 +554,19 @@ proc parseBody(client: PAsyncHttpClient, # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5 if headers["Connection"] == "close": var buf = "" - while True: + while true: buf = await client.socket.recvFull(4000) if buf == "": break result.add(buf) proc parseResponse(client: PAsyncHttpClient, - getBody: bool): PFuture[TResponse] {.async.} = + getBody: bool): Future[TResponse] {.async.} = var parsedStatus = false var linei = 0 var fullyRead = false var line = "" result.headers = newStringTable(modeCaseInsensitive) - while True: + while true: linei = 0 line = await client.socket.recvLine() if line == "": break # We've been disconnected. @@ -582,20 +612,29 @@ proc newConnection(client: PAsyncHttpClient, url: TURL) {.async.} = client.currentURL.scheme != url.scheme: if client.connected: client.close() client.socket = newAsyncSocket() - if url.scheme == "https": - assert false, "TODO SSL" # TODO: I should be able to write 'net.TPort' here... let port = - if url.port == "": rawsockets.TPort(80) + if url.port == "": + if url.scheme.toLower() == "https": + rawsockets.TPort(443) + else: + rawsockets.TPort(80) else: rawsockets.TPort(url.port.parseInt) + if url.scheme.toLower() == "https": + when defined(ssl): + client.sslContext.wrapSocket(client.socket) + else: + raise newException(EHttpRequestErr, + "SSL support is not available. Cannot connect over SSL.") + await client.socket.connect(url.hostname, port) client.currentURL = url client.connected = true proc request*(client: PAsyncHttpClient, url: string, httpMethod = httpGET, - body = ""): PFuture[TResponse] {.async.} = + body = ""): Future[TResponse] {.async.} = ## Connects to the hostname specified by the URL and performs a request ## using the method specified. ## @@ -618,7 +657,7 @@ proc request*(client: PAsyncHttpClient, url: string, httpMethod = httpGET, result = await parseResponse(client, httpMethod != httpHEAD) -proc get*(client: PAsyncHttpClient, url: string): PFuture[TResponse] {.async.} = +proc get*(client: PAsyncHttpClient, url: string): Future[TResponse] {.async.} = ## Connects to the hostname specified by the URL and performs a GET request. ## ## This procedure will follow redirects up to a maximum number of redirects @@ -648,16 +687,16 @@ when isMainModule: resp = await client.request("http://picheta.me/aboutme.html") echo("Got response: ", resp.status) - resp = await client.request("http://nimrod-lang.org/") + resp = await client.request("http://nim-lang.org/") echo("Got response: ", resp.status) - resp = await client.request("http://nimrod-lang.org/download.html") + resp = await client.request("http://nim-lang.org/download.html") echo("Got response: ", resp.status) waitFor main() else: - #downloadFile("http://force7.de/nimrod/index.html", "nimrodindex.html") + #downloadFile("http://force7.de/nim/index.html", "nimindex.html") #downloadFile("http://www.httpwatch.com/", "ChunkTest.html") #downloadFile("http://validator.w3.org/check?uri=http%3A%2F%2Fgoogle.com", # "validator.html") diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim index 885742b64..dc6db4738 100644 --- a/lib/pure/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf, Dominik Picheta # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ ## ## Example: ## -## .. code-block:: nimrod +## .. code-block:: nim ## import strutils, sockets, httpserver ## ## var counter = 0 @@ -22,8 +22,6 @@ ## ## run(handleRequest, TPort(80)) ## -## **Warning:** The API of this module is unstable, and therefore is subject -## to change. import parseutils, strutils, os, osproc, strtabs, streams, sockets, asyncio @@ -90,14 +88,14 @@ proc serveFile*(client: TSocket, filename: string) = headers(client, filename) const bufSize = 8000 # != 8K might be good for memory manager var buf = alloc(bufsize) - while True: + while true: var bytesread = readBuffer(f, buf, bufsize) if bytesread > 0: var byteswritten = send(client, buf, bytesread) if bytesread != bytesWritten: dealloc(buf) close(f) - OSError(OSLastError()) + raiseOSError(osLastError()) if bytesread != bufSize: break dealloc(buf) close(f) @@ -145,7 +143,7 @@ when false: var buf = alloc(contentLength) if recv(client, buf, contentLength) != contentLength: dealloc(buf) - OSError() + raiseOSError() var inp = process.inputStream inp.writeData(buf, contentLength) dealloc(buf) @@ -228,9 +226,9 @@ proc open*(s: var TServer, port = TPort(80), reuseAddr = false) = ## creates a new server at port `port`. If ``port == 0`` a free port is ## acquired that can be accessed later by the ``port`` proc. s.socket = socket(AF_INET) - if s.socket == InvalidSocket: OSError(OSLastError()) + if s.socket == invalidSocket: raiseOSError(osLastError()) if reuseAddr: - s.socket.setSockOpt(OptReuseAddr, True) + s.socket.setSockOpt(OptReuseAddr, true) bindAddr(s.socket, port) listen(s.socket) @@ -238,7 +236,7 @@ proc open*(s: var TServer, port = TPort(80), reuseAddr = false) = s.port = getSockName(s.socket) else: s.port = port - s.client = InvalidSocket + s.client = invalidSocket s.reqMethod = "" s.body = "" s.path = "" @@ -346,7 +344,7 @@ proc next*(s: var TServer) = # XXX we ignore "HTTP/1.1" etc. for now here var query = 0 var last = i - while last < data.len and data[last] notin whitespace: + while last < data.len and data[last] notin Whitespace: if data[last] == '?' and query == 0: query = last inc(last) if query > 0: @@ -466,7 +464,7 @@ proc nextAsync(s: PAsyncHTTPServer) = # XXX we ignore "HTTP/1.1" etc. for now here var query = 0 var last = i - while last < data.len and data[last] notin whitespace: + while last < data.len and data[last] notin Whitespace: if data[last] == '?' and query == 0: query = last inc(last) if query > 0: @@ -483,7 +481,7 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo ## Creates an Asynchronous HTTP server at ``port``. var capturedRet: PAsyncHTTPServer new(capturedRet) - capturedRet.asyncSocket = AsyncSocket() + capturedRet.asyncSocket = asyncSocket() capturedRet.asyncSocket.handleAccept = proc (s: PAsyncSocket) = nextAsync(capturedRet) @@ -491,7 +489,7 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo capturedRet.query) if quit: capturedRet.asyncSocket.close() if reuseAddr: - capturedRet.asyncSocket.setSockOpt(OptReuseAddr, True) + capturedRet.asyncSocket.setSockOpt(OptReuseAddr, true) capturedRet.asyncSocket.bindAddr(port, address) capturedRet.asyncSocket.listen() @@ -500,7 +498,7 @@ proc asyncHTTPServer*(handleRequest: proc (server: PAsyncHTTPServer, client: TSo else: capturedRet.port = port - capturedRet.client = InvalidSocket + capturedRet.client = invalidSocket capturedRet.reqMethod = "" capturedRet.body = "" capturedRet.path = "" diff --git a/lib/pure/json.nim b/lib/pure/json.nim index a45900f29..8bd05ad55 100644 --- a/lib/pure/json.nim +++ b/lib/pure/json.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf, Dominik Picheta +# Nim's Runtime Library +# (c) Copyright 2014 Andreas Rumpf, Dominik Picheta # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -16,7 +16,7 @@ ## ## Usage example: ## -## .. code-block:: nimrod +## .. code-block:: nim ## let ## small_json = """{"test": 1.3, "key2": true}""" ## jobj = parseJson(small_json) @@ -26,7 +26,7 @@ ## ## Results in: ## -## .. code-block:: nimrod +## .. code-block:: nim ## ## 1.3000000000000000e+00 ## true @@ -35,7 +35,7 @@ import hashes, strutils, lexbase, streams, unicode type - TJsonEventKind* = enum ## enumeration of all events that may occur when parsing + JsonEventKind* = enum ## enumeration of all events that may occur when parsing jsonError, ## an error ocurred during parsing jsonEof, ## end of file reached jsonString, ## a string literal @@ -65,7 +65,7 @@ type tkColon, tkComma - TJsonError* = enum ## enumeration that lists all errors that can occur + JsonError* = enum ## enumeration that lists all errors that can occur errNone, ## no error errInvalidToken, ## invalid token errStringExpected, ## string expected @@ -78,20 +78,23 @@ type errEofExpected, ## EOF expected errExprExpected ## expr expected - TParserState = enum + ParserState = enum stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma, stateExpectObjectComma, stateExpectColon, stateExpectValue - TJsonParser* = object of TBaseLexer ## the parser object. + JsonParser* = object of BaseLexer ## the parser object. a: string tok: TTokKind - kind: TJsonEventKind - err: TJsonError - state: seq[TParserState] + kind: JsonEventKind + err: JsonError + state: seq[ParserState] filename: string + +{.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError, + TJsonParser: JsonParser].} const - errorMessages: array [TJsonError, string] = [ + errorMessages: array [JsonError, string] = [ "no error", "invalid token", "string expected", @@ -116,7 +119,7 @@ const "{", "}", "[", "]", ":", "," ] -proc open*(my: var TJsonParser, input: PStream, filename: string) = +proc open*(my: var JsonParser, input: Stream, filename: string) = ## initializes the parser with an input stream. `Filename` is only used ## for nice error messages. lexbase.open(my, input) @@ -125,49 +128,49 @@ proc open*(my: var TJsonParser, input: PStream, filename: string) = my.kind = jsonError my.a = "" -proc close*(my: var TJsonParser) {.inline.} = +proc close*(my: var JsonParser) {.inline.} = ## closes the parser `my` and its associated input stream. lexbase.close(my) -proc str*(my: TJsonParser): string {.inline.} = +proc str*(my: JsonParser): string {.inline.} = ## returns the character data for the events: ``jsonInt``, ``jsonFloat``, ## ``jsonString`` assert(my.kind in {jsonInt, jsonFloat, jsonString}) return my.a -proc getInt*(my: TJsonParser): BiggestInt {.inline.} = +proc getInt*(my: JsonParser): BiggestInt {.inline.} = ## returns the number for the event: ``jsonInt`` assert(my.kind == jsonInt) return parseBiggestInt(my.a) -proc getFloat*(my: TJsonParser): float {.inline.} = +proc getFloat*(my: JsonParser): float {.inline.} = ## returns the number for the event: ``jsonFloat`` assert(my.kind == jsonFloat) return parseFloat(my.a) -proc kind*(my: TJsonParser): TJsonEventKind {.inline.} = +proc kind*(my: JsonParser): JsonEventKind {.inline.} = ## returns the current event type for the JSON parser return my.kind -proc getColumn*(my: TJsonParser): int {.inline.} = +proc getColumn*(my: JsonParser): int {.inline.} = ## get the current column the parser has arrived at. result = getColNumber(my, my.bufpos) -proc getLine*(my: TJsonParser): int {.inline.} = +proc getLine*(my: JsonParser): int {.inline.} = ## get the current line the parser has arrived at. result = my.lineNumber -proc getFilename*(my: TJsonParser): string {.inline.} = +proc getFilename*(my: JsonParser): string {.inline.} = ## get the filename of the file that the parser processes. result = my.filename -proc errorMsg*(my: TJsonParser): string = +proc errorMsg*(my: JsonParser): string = ## returns a helpful error message for the event ``jsonError`` assert(my.kind == jsonError) result = "$1($2, $3) Error: $4" % [ my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]] -proc errorMsgExpected*(my: TJsonParser, e: string): string = +proc errorMsgExpected*(my: JsonParser, e: string): string = ## returns an error message "`e` expected" in the same format as the ## other error messages result = "$1($2, $3) Error: $4" % [ @@ -181,7 +184,7 @@ proc handleHexChar(c: char, x: var int): bool = of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10) else: result = false # error -proc parseString(my: var TJsonParser): TTokKind = +proc parseString(my: var JsonParser): TTokKind = result = tkString var pos = my.bufpos + 1 var buf = my.buf @@ -221,7 +224,7 @@ proc parseString(my: var TJsonParser): TTokKind = if handleHexChar(buf[pos], r): inc(pos) if handleHexChar(buf[pos], r): inc(pos) if handleHexChar(buf[pos], r): inc(pos) - add(my.a, toUTF8(TRune(r))) + add(my.a, toUTF8(Rune(r))) else: # don't bother with the error add(my.a, buf[pos]) @@ -239,7 +242,7 @@ proc parseString(my: var TJsonParser): TTokKind = inc(pos) my.bufpos = pos # store back -proc skip(my: var TJsonParser) = +proc skip(my: var JsonParser) = var pos = my.bufpos var buf = my.buf while true: @@ -297,7 +300,7 @@ proc skip(my: var TJsonParser) = break my.bufpos = pos -proc parseNumber(my: var TJsonParser) = +proc parseNumber(my: var JsonParser) = var pos = my.bufpos var buf = my.buf if buf[pos] == '-': @@ -328,7 +331,7 @@ proc parseNumber(my: var TJsonParser) = inc(pos) my.bufpos = pos -proc parseName(my: var TJsonParser) = +proc parseName(my: var JsonParser) = var pos = my.bufpos var buf = my.buf if buf[pos] in IdentStartChars: @@ -337,7 +340,7 @@ proc parseName(my: var TJsonParser) = inc(pos) my.bufpos = pos -proc getTok(my: var TJsonParser): TTokKind = +proc getTok(my: var JsonParser): TTokKind = setLen(my.a, 0) skip(my) # skip whitespace, comments case my.buf[my.bufpos] @@ -381,7 +384,7 @@ proc getTok(my: var TJsonParser): TTokKind = result = tkError my.tok = result -proc next*(my: var TJsonParser) = +proc next*(my: var JsonParser) = ## retrieves the first/next event. This controls the parser. var tk = getTok(my) var i = my.state.len-1 @@ -399,7 +402,7 @@ proc next*(my: var TJsonParser) = case tk of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: my.state[i] = stateEof # expect EOF next! - my.kind = TJsonEventKind(ord(tk)) + my.kind = JsonEventKind(ord(tk)) of tkBracketLe: my.state.add(stateArray) # we expect any my.kind = jsonArrayStart @@ -415,7 +418,7 @@ proc next*(my: var TJsonParser) = case tk of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: my.state.add(stateExpectColon) - my.kind = TJsonEventKind(ord(tk)) + my.kind = JsonEventKind(ord(tk)) of tkBracketLe: my.state.add(stateExpectColon) my.state.add(stateArray) @@ -434,7 +437,7 @@ proc next*(my: var TJsonParser) = case tk of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: my.state.add(stateExpectArrayComma) # expect value next! - my.kind = TJsonEventKind(ord(tk)) + my.kind = JsonEventKind(ord(tk)) of tkBracketLe: my.state.add(stateExpectArrayComma) my.state.add(stateArray) @@ -485,7 +488,7 @@ proc next*(my: var TJsonParser) = case tk of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: my.state[i] = stateExpectObjectComma - my.kind = TJsonEventKind(ord(tk)) + my.kind = JsonEventKind(ord(tk)) of tkBracketLe: my.state[i] = stateExpectObjectComma my.state.add(stateArray) @@ -502,7 +505,7 @@ proc next*(my: var TJsonParser) = # ------------- higher level interface --------------------------------------- type - TJsonNodeKind* = enum ## possible JSON node types + JsonNodeKind* = enum ## possible JSON node types JNull, JBool, JInt, @@ -511,9 +514,9 @@ type JObject, JArray - PJsonNode* = ref TJsonNode ## JSON node - TJsonNode* {.final, pure, acyclic.} = object - case kind*: TJsonNodeKind + JsonNode* = ref JsonNodeObj ## JSON node + JsonNodeObj* {.acyclic.} = object + case kind*: JsonNodeKind of JString: str*: string of JInt: @@ -525,101 +528,104 @@ type of JNull: nil of JObject: - fields*: seq[tuple[key: string, val: PJsonNode]] + fields*: seq[tuple[key: string, val: JsonNode]] of JArray: - elems*: seq[PJsonNode] + elems*: seq[JsonNode] + + JsonParsingError* = object of ValueError ## is raised for a JSON error - EJsonParsingError* = object of EInvalidValue ## is raised for a JSON error +{.deprecated: [EJsonParsingError: JsonParsingError, TJsonNode: JsonNodeObj, + PJsonNode: JsonNode, TJsonNodeKind: JsonNodeKind].} -proc raiseParseErr*(p: TJsonParser, msg: string) {.noinline, noreturn.} = +proc raiseParseErr*(p: JsonParser, msg: string) {.noinline, noreturn.} = ## raises an `EJsonParsingError` exception. - raise newException(EJsonParsingError, errorMsgExpected(p, msg)) + raise newException(JsonParsingError, errorMsgExpected(p, msg)) -proc newJString*(s: string): PJsonNode = +proc newJString*(s: string): JsonNode = ## Creates a new `JString PJsonNode`. new(result) result.kind = JString result.str = s -proc newJStringMove(s: string): PJsonNode = +proc newJStringMove(s: string): JsonNode = new(result) result.kind = JString shallowCopy(result.str, s) -proc newJInt*(n: BiggestInt): PJsonNode = +proc newJInt*(n: BiggestInt): JsonNode = ## Creates a new `JInt PJsonNode`. new(result) result.kind = JInt result.num = n -proc newJFloat*(n: float): PJsonNode = +proc newJFloat*(n: float): JsonNode = ## Creates a new `JFloat PJsonNode`. new(result) result.kind = JFloat result.fnum = n -proc newJBool*(b: bool): PJsonNode = +proc newJBool*(b: bool): JsonNode = ## Creates a new `JBool PJsonNode`. new(result) result.kind = JBool result.bval = b -proc newJNull*(): PJsonNode = +proc newJNull*(): JsonNode = ## Creates a new `JNull PJsonNode`. new(result) -proc newJObject*(): PJsonNode = +proc newJObject*(): JsonNode = ## Creates a new `JObject PJsonNode` new(result) result.kind = JObject result.fields = @[] -proc newJArray*(): PJsonNode = +proc newJArray*(): JsonNode = ## Creates a new `JArray PJsonNode` new(result) result.kind = JArray result.elems = @[] -proc `%`*(s: string): PJsonNode = +proc `%`*(s: string): JsonNode = ## Generic constructor for JSON data. Creates a new `JString PJsonNode`. new(result) result.kind = JString result.str = s -proc `%`*(n: BiggestInt): PJsonNode = +proc `%`*(n: BiggestInt): JsonNode = ## Generic constructor for JSON data. Creates a new `JInt PJsonNode`. new(result) result.kind = JInt result.num = n -proc `%`*(n: float): PJsonNode = +proc `%`*(n: float): JsonNode = ## Generic constructor for JSON data. Creates a new `JFloat PJsonNode`. new(result) result.kind = JFloat result.fnum = n -proc `%`*(b: bool): PJsonNode = +proc `%`*(b: bool): JsonNode = ## Generic constructor for JSON data. Creates a new `JBool PJsonNode`. new(result) result.kind = JBool result.bval = b -proc `%`*(keyVals: openArray[tuple[key: string, val: PJsonNode]]): PJsonNode = +proc `%`*(keyVals: openArray[tuple[key: string, val: JsonNode]]): JsonNode = ## Generic constructor for JSON data. Creates a new `JObject PJsonNode` new(result) result.kind = JObject newSeq(result.fields, keyVals.len) for i, p in pairs(keyVals): result.fields[i] = p -proc `%`*(elements: openArray[PJsonNode]): PJsonNode = +proc `%`*(elements: openArray[JsonNode]): JsonNode = ## Generic constructor for JSON data. Creates a new `JArray PJsonNode` new(result) result.kind = JArray newSeq(result.elems, elements.len) for i, p in pairs(elements): result.elems[i] = p -proc `==`* (a,b: PJsonNode): bool = +proc `==`* (a,b: JsonNode): bool = ## Check two nodes for equality if a.isNil: if b.isNil: return true @@ -643,7 +649,7 @@ proc `==`* (a,b: PJsonNode): bool = of JObject: a.fields == b.fields -proc hash* (n:PJsonNode): THash = +proc hash* (n:JsonNode): THash = ## Compute the hash for a JSON node case n.kind of JArray: @@ -661,7 +667,7 @@ proc hash* (n:PJsonNode): THash = of JNull: result = hash(0) -proc len*(n: PJsonNode): int = +proc len*(n: JsonNode): int = ## If `n` is a `JArray`, it returns the number of elements. ## If `n` is a `JObject`, it returns the number of pairs. ## Else it returns 0. @@ -670,7 +676,7 @@ proc len*(n: PJsonNode): int = of JObject: result = n.fields.len else: discard -proc `[]`*(node: PJsonNode, name: string): PJsonNode = +proc `[]`*(node: JsonNode, name: string): JsonNode = ## Gets a field from a `JObject`, which must not be nil. ## If the value at `name` does not exist, returns nil assert(not isNil(node)) @@ -680,35 +686,35 @@ proc `[]`*(node: PJsonNode, name: string): PJsonNode = return item return nil -proc `[]`*(node: PJsonNode, index: int): PJsonNode = +proc `[]`*(node: JsonNode, index: int): JsonNode = ## Gets the node at `index` in an Array. Result is undefined if `index` ## is out of bounds assert(not isNil(node)) assert(node.kind == JArray) return node.elems[index] -proc hasKey*(node: PJsonNode, key: string): bool = +proc hasKey*(node: JsonNode, key: string): bool = ## Checks if `key` exists in `node`. assert(node.kind == JObject) for k, item in items(node.fields): if k == key: return true -proc existsKey*(node: PJsonNode, key: string): bool {.deprecated.} = node.hasKey(key) +proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key) ## Deprecated for `hasKey` -proc add*(father, child: PJsonNode) = +proc add*(father, child: JsonNode) = ## Adds `child` to a JArray node `father`. assert father.kind == JArray father.elems.add(child) -proc add*(obj: PJsonNode, key: string, val: PJsonNode) = +proc add*(obj: JsonNode, key: string, val: JsonNode) = ## Adds ``(key, val)`` pair to the JObject node `obj`. For speed ## reasons no check for duplicate keys is performed! ## But ``[]=`` performs the check. assert obj.kind == JObject obj.fields.add((key, val)) -proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) = +proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) = ## Sets a field from a `JObject`. Performs a check for duplicate keys. assert(obj.kind == JObject) for i in 0..obj.fields.len-1: @@ -717,14 +723,14 @@ proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) = return obj.fields.add((key, val)) -proc `{}`*(node: PJsonNode, key: string): PJsonNode = +proc `{}`*(node: JsonNode, key: string): JsonNode = ## Transverses the node and gets the given value. If any of the ## names does not exist, returns nil result = node if isNil(node): return nil result = result[key] -proc `{}=`*(node: PJsonNode, names: varargs[string], value: PJsonNode) = +proc `{}=`*(node: JsonNode, names: varargs[string], value: JsonNode) = ## Transverses the node and tries to set the value at the given location ## to `value` If any of the names are missing, they are added var node = node @@ -734,16 +740,16 @@ proc `{}=`*(node: PJsonNode, names: varargs[string], value: PJsonNode) = node = node[names[i]] node[names[names.len-1]] = value -proc delete*(obj: PJsonNode, key: string) = +proc delete*(obj: JsonNode, key: string) = ## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs. assert(obj.kind == JObject) for i in 0..obj.fields.len-1: if obj.fields[i].key == key: obj.fields.delete(i) return - raise newException(EInvalidIndex, "key not in object") + raise newException(IndexError, "key not in object") -proc copy*(p: PJsonNode): PJsonNode = +proc copy*(p: JsonNode): JsonNode = ## Performs a deep copy of `a`. case p.kind of JString: @@ -794,7 +800,7 @@ proc escapeJson*(s: string): string = result.add(toHex(r, 4)) result.add("\"") -proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = true, +proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, lstArr = false, currIndent = 0) = case node.kind of JObject: @@ -849,34 +855,34 @@ proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = true, if lstArr: result.indent(currIndent) result.add("null") -proc pretty*(node: PJsonNode, indent = 2): string = +proc pretty*(node: JsonNode, indent = 2): string = ## Converts `node` to its JSON Representation, with indentation and ## on multiple lines. result = "" toPretty(result, node, indent) -proc `$`*(node: PJsonNode): string = +proc `$`*(node: JsonNode): string = ## Converts `node` to its JSON Representation on one line. result = "" toPretty(result, node, 1, false) -iterator items*(node: PJsonNode): PJsonNode = +iterator items*(node: JsonNode): JsonNode = ## Iterator for the items of `node`. `node` has to be a JArray. assert node.kind == JArray for i in items(node.elems): yield i -iterator pairs*(node: PJsonNode): tuple[key: string, val: PJsonNode] = +iterator pairs*(node: JsonNode): tuple[key: string, val: JsonNode] = ## Iterator for the child elements of `node`. `node` has to be a JObject. assert node.kind == JObject for key, val in items(node.fields): yield (key, val) -proc eat(p: var TJsonParser, tok: TTokKind) = +proc eat(p: var JsonParser, tok: TTokKind) = if p.tok == tok: discard getTok(p) else: raiseParseErr(p, tokToStr[tok]) -proc parseJson(p: var TJsonParser): PJsonNode = +proc parseJson(p: var JsonParser): JsonNode = ## Parses JSON from a JSON Parser `p`. case p.tok of tkString: @@ -925,24 +931,24 @@ proc parseJson(p: var TJsonParser): PJsonNode = raiseParseErr(p, "{") when not defined(js): - proc parseJson*(s: PStream, filename: string): PJsonNode = + proc parseJson*(s: Stream, filename: string): JsonNode = ## Parses from a stream `s` into a `PJsonNode`. `filename` is only needed ## for nice error messages. - var p: TJsonParser + var p: JsonParser p.open(s, filename) discard getTok(p) # read first token result = p.parseJson() p.close() - proc parseJson*(buffer: string): PJsonNode = + proc parseJson*(buffer: string): JsonNode = ## Parses JSON from `buffer`. result = parseJson(newStringStream(buffer), "input") - proc parseFile*(filename: string): PJsonNode = + proc parseFile*(filename: string): JsonNode = ## Parses `file` into a `PJsonNode`. var stream = newFileStream(filename, fmRead) if stream == nil: - raise newException(EIO, "cannot read from file: " & filename) + raise newException(IOError, "cannot read from file: " & filename) result = parseJson(stream, filename) else: from math import `mod` @@ -1056,8 +1062,8 @@ when isMainModule: echo(pretty(parsed2)) try: echo(parsed["key2"][12123]) - raise newException(EInvalidValue, "That line was expected to fail") - except EInvalidIndex: echo() + raise newException(ValueError, "That line was expected to fail") + except IndexError: echo() let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }""" # nil passthrough @@ -1069,12 +1075,12 @@ when isMainModule: try: let a = testJson["a"][9] assert(false, "EInvalidIndex not thrown") - except EInvalidIndex: + except IndexError: discard try: let a = testJson["a"][-1] assert(false, "EInvalidIndex not thrown") - except EInvalidIndex: + except IndexError: discard try: assert(testJson["a"][0].num == 1, "Index doesn't correspond to its value") diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim index eee95e2e6..a3a3d7b5c 100644 --- a/lib/pure/lexbase.nim +++ b/lib/pure/lexbase.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Compiler +# The Nim Compiler # (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this @@ -25,34 +25,36 @@ const # type - TBaseLexer* = object of TObject ## the base lexer. Inherit your lexer from - ## this object. + BaseLexer* = object of RootObj ## the base lexer. Inherit your lexer from + ## this object. bufpos*: int ## the current position within the buffer buf*: cstring ## the buffer itself bufLen*: int ## length of buffer in characters - input: PStream ## the input stream + input: Stream ## the input stream lineNumber*: int ## the current line number sentinel: int lineStart: int # index of last line start in buffer fileOpened: bool -proc open*(L: var TBaseLexer, input: PStream, bufLen: int = 8192) +{.deprecated: [TBaseLexer: BaseLexer].} + +proc open*(L: var BaseLexer, input: Stream, bufLen: int = 8192) ## inits the TBaseLexer with a stream to read from -proc close*(L: var TBaseLexer) +proc close*(L: var BaseLexer) ## closes the base lexer. This closes `L`'s associated stream too. -proc getCurrentLine*(L: TBaseLexer, marker: bool = true): string +proc getCurrentLine*(L: BaseLexer, marker: bool = true): string ## retrieves the current line. -proc getColNumber*(L: TBaseLexer, pos: int): int +proc getColNumber*(L: BaseLexer, pos: int): int ## retrieves the current column. -proc handleCR*(L: var TBaseLexer, pos: int): int +proc handleCR*(L: var BaseLexer, pos: int): int ## Call this if you scanned over '\c' in the buffer; it returns the the ## position to continue the scanning from. `pos` must be the position ## of the '\c'. -proc handleLF*(L: var TBaseLexer, pos: int): int +proc handleLF*(L: var BaseLexer, pos: int): int ## Call this if you scanned over '\L' in the buffer; it returns the the ## position to continue the scanning from. `pos` must be the position ## of the '\L'. @@ -62,11 +64,11 @@ proc handleLF*(L: var TBaseLexer, pos: int): int const chrSize = sizeof(char) -proc close(L: var TBaseLexer) = +proc close(L: var BaseLexer) = dealloc(L.buf) close(L.input) -proc fillBuffer(L: var TBaseLexer) = +proc fillBuffer(L: var BaseLexer) = var charsRead, toCopy, s: int # all are in characters, # not bytes (in case this @@ -111,7 +113,7 @@ proc fillBuffer(L: var TBaseLexer) = break s = L.bufLen - 1 -proc fillBaseLexer(L: var TBaseLexer, pos: int): int = +proc fillBaseLexer(L: var BaseLexer, pos: int): int = assert(pos <= L.sentinel) if pos < L.sentinel: result = pos + 1 # nothing to do @@ -121,24 +123,24 @@ proc fillBaseLexer(L: var TBaseLexer, pos: int): int = result = 0 L.lineStart = result -proc handleCR(L: var TBaseLexer, pos: int): int = +proc handleCR(L: var BaseLexer, pos: int): int = assert(L.buf[pos] == '\c') inc(L.lineNumber) result = fillBaseLexer(L, pos) if L.buf[result] == '\L': result = fillBaseLexer(L, result) -proc handleLF(L: var TBaseLexer, pos: int): int = +proc handleLF(L: var BaseLexer, pos: int): int = assert(L.buf[pos] == '\L') inc(L.lineNumber) result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result; -proc skipUtf8Bom(L: var TBaseLexer) = +proc skipUtf8Bom(L: var BaseLexer) = if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'): inc(L.bufpos, 3) inc(L.lineStart, 3) -proc open(L: var TBaseLexer, input: PStream, bufLen: int = 8192) = +proc open(L: var BaseLexer, input: Stream, bufLen: int = 8192) = assert(bufLen > 0) assert(input != nil) L.input = input @@ -151,10 +153,10 @@ proc open(L: var TBaseLexer, input: PStream, bufLen: int = 8192) = fillBuffer(L) skipUtf8Bom(L) -proc getColNumber(L: TBaseLexer, pos: int): int = +proc getColNumber(L: BaseLexer, pos: int): int = result = abs(pos - L.lineStart) -proc getCurrentLine(L: TBaseLexer, marker: bool = true): string = +proc getCurrentLine(L: BaseLexer, marker: bool = true): string = var i: int result = "" i = L.lineStart diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 284384b37..bd5e1bf42 100644 --- a/lib/pure/logging.nim +++ b/lib/pure/logging.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf, Dominik Picheta # # See the file "copying.txt", included in this @@ -26,7 +26,7 @@ ## The following example demonstrates logging to three different handlers ## simultaneously: ## -## .. code-block:: nimrod +## .. code-block:: nim ## ## var L = newConsoleLogger() ## var fL = newFileLogger("test.log", fmtStr = verboseFmtStr) @@ -42,7 +42,7 @@ import strutils, os, times type - TLevel* = enum ## logging level + Level* = enum ## logging level lvlAll, ## all levels active lvlDebug, ## debug level (and any above) active lvlInfo, ## info level (and any above) active @@ -52,7 +52,7 @@ type lvlNone ## no levels active const - LevelNames*: array [TLevel, string] = [ + LevelNames*: array [Level, string] = [ "DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE" ] @@ -60,26 +60,29 @@ const verboseFmtStr* = "$date $time " type - PLogger* = ref object of PObject ## abstract logger; the base type of all loggers - levelThreshold*: TLevel ## only messages of level >= levelThreshold - ## should be processed + Logger* = ref object of RootObj ## abstract logger; the base type of all loggers + levelThreshold*: Level ## only messages of level >= levelThreshold + ## should be processed fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc. - PConsoleLogger* = ref object of PLogger ## logger that writes the messages to the - ## console + ConsoleLogger* = ref object of Logger ## logger that writes the messages to the + ## console - PFileLogger* = ref object of PLogger ## logger that writes the messages to a file - f: TFile + FileLogger* = ref object of Logger ## logger that writes the messages to a file + f: File - PRollingFileLogger* = ref object of PFileLogger ## logger that writes the - ## messages to a file and - ## performs log rotation + RollingFileLogger* = ref object of FileLogger ## logger that writes the + ## messages to a file and + ## performs log rotation maxLines: int # maximum number of lines curLine : int baseName: string # initial filename - baseMode: TFileMode # initial file mode + baseMode: FileMode # initial file mode logFiles: int # how many log files already created, e.g. basename.1, basename.2... +{.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger, + PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].} + proc substituteLog(frmt: string): string = ## converts $date to the current date ## converts $time to the current time @@ -105,20 +108,20 @@ proc substituteLog(frmt: string): string = of "appdir": result.add(app.splitFile.dir) of "appname": result.add(app.splitFile.name) -method log*(logger: PLogger, level: TLevel, - frmt: string, args: varargs[string, `$`]) {.raises: [EBase], tags: [FTime, FWriteIO, FReadIO].} = +method log*(logger: Logger, level: Level, + frmt: string, args: varargs[string, `$`]) {.raises: [Exception], tags: [FTime, FWriteIO, FReadIO].} = ## Override this method in custom loggers. Default implementation does ## nothing. discard -method log*(logger: PConsoleLogger, level: TLevel, +method log*(logger: ConsoleLogger, level: Level, frmt: string, args: varargs[string, `$`]) = ## Logs to the console using ``logger`` only. if level >= logger.levelThreshold: writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr), frmt % args) -method log*(logger: PFileLogger, level: TLevel, +method log*(logger: FileLogger, level: Level, frmt: string, args: varargs[string, `$`]) = ## Logs to a file using ``logger`` only. if level >= logger.levelThreshold: @@ -130,16 +133,16 @@ proc defaultFilename*(): string = var (path, name, ext) = splitFile(getAppFilename()) result = changeFileExt(path / name, "log") -proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): PConsoleLogger = +proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): ConsoleLogger = ## Creates a new console logger. This logger logs to the console. new result result.fmtStr = fmtStr result.levelThreshold = levelThreshold proc newFileLogger*(filename = defaultFilename(), - mode: TFileMode = fmAppend, + mode: FileMode = fmAppend, levelThreshold = lvlAll, - fmtStr = defaultFmtStr): PFileLogger = + fmtStr = defaultFmtStr): FileLogger = ## Creates a new file logger. This logger logs to a file. new(result) result.levelThreshold = levelThreshold @@ -148,7 +151,7 @@ proc newFileLogger*(filename = defaultFilename(), # ------ -proc countLogLines(logger: PRollingFileLogger): int = +proc countLogLines(logger: RollingFileLogger): int = result = 0 for line in logger.f.lines(): result.inc() @@ -166,13 +169,13 @@ proc countFiles(filename: string): int = let num = parseInt(numS) if num > result: result = num - except EInvalidValue: discard + except ValueError: discard proc newRollingFileLogger*(filename = defaultFilename(), - mode: TFileMode = fmReadWrite, + mode: FileMode = fmReadWrite, levelThreshold = lvlAll, fmtStr = defaultFmtStr, - maxLines = 1000): PRollingFileLogger = + maxLines = 1000): RollingFileLogger = ## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines ## a new log file will be started and the old will be renamed. new(result) @@ -190,14 +193,14 @@ proc newRollingFileLogger*(filename = defaultFilename(), # We need to get a line count because we will be appending to the file. result.curLine = countLogLines(result) -proc rotate(logger: PRollingFileLogger) = +proc rotate(logger: RollingFileLogger) = let (dir, name, ext) = splitFile(logger.baseName) for i in countdown(logger.logFiles, 0): let srcSuff = if i != 0: ExtSep & $i else: "" moveFile(dir / (name & ext & srcSuff), dir / (name & ext & ExtSep & $(i+1))) -method log*(logger: PRollingFileLogger, level: TLevel, +method log*(logger: RollingFileLogger, level: Level, frmt: string, args: varargs[string, `$`]) = ## Logs to a file using rolling ``logger`` only. if level >= logger.levelThreshold: @@ -215,20 +218,20 @@ method log*(logger: PRollingFileLogger, level: TLevel, var level* = lvlAll ## global log filter - handlers*: seq[PLogger] = @[] ## handlers with their own log levels + handlers*: seq[Logger] = @[] ## handlers with their own log levels -proc logLoop(level: TLevel, frmt: string, args: varargs[string, `$`]) = +proc logLoop(level: Level, frmt: string, args: varargs[string, `$`]) = for logger in items(handlers): if level >= logger.levelThreshold: log(logger, level, frmt, args) -template log*(level: TLevel, frmt: string, args: varargs[string, `$`]) = +template log*(level: Level, frmt: string, args: varargs[string, `$`]) = ## Logs a message to all registered handlers at the given level. bind logLoop bind `%` - bind logging.Level + bind logging.level - if level >= logging.Level: + if level >= logging.level: logLoop(level, frmt, args) template debug*(frmt: string, args: varargs[string, `$`]) = diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 789f6ad76..fc63605a9 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -1,319 +1,319 @@ -# -# -# Nimrod's Runtime Library -# (c) Copyright 2013 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module contains procs for serialization and deseralization of -## arbitrary Nimrod data structures. The serialization format uses JSON. -## -## **Restriction**: For objects their type is **not** serialized. This means -## essentially that it does not work if the object has some other runtime -## type than its compiletime type: -## -## .. code-block:: nimrod -## -## type -## TA = object -## TB = object of TA -## f: int -## -## var -## a: ref TA -## b: ref TB -## -## new(b) -## a = b -## echo($$a[]) # produces "{}", not "{f: 0}" - -import streams, typeinfo, json, intsets, tables - -proc ptrToInt(x: pointer): int {.inline.} = - result = cast[int](x) # don't skip alignment - -proc storeAny(s: PStream, a: TAny, stored: var TIntSet) = - case a.kind - of akNone: assert false - of akBool: s.write($getBool(a)) - of akChar: s.write(escapeJson($getChar(a))) - of akArray, akSequence: - if a.kind == akSequence and isNil(a): s.write("null") - else: - s.write("[") - for i in 0 .. a.len-1: - if i > 0: s.write(", ") - storeAny(s, a[i], stored) - s.write("]") - of akObject, akTuple: - s.write("{") - var i = 0 - for key, val in fields(a): - if i > 0: s.write(", ") - s.write(escapeJson(key)) - s.write(": ") - storeAny(s, val, stored) - inc(i) - s.write("}") - of akSet: - s.write("[") - var i = 0 - for e in elements(a): - if i > 0: s.write(", ") - s.write($e) - inc(i) - s.write("]") - of akRange: storeAny(s, skipRange(a), stored) - of akEnum: s.write(getEnumField(a).escapeJson) - of akPtr, akRef: - var x = a.getPointer - if isNil(x): s.write("null") - elif stored.containsOrIncl(x.ptrToInt): - # already stored, so we simply write out the pointer as an int: - s.write($x.ptrToInt) - else: - # else as a [value, key] pair: - # (reversed order for convenient x[0] access!) - s.write("[") - s.write($x.ptrToInt) - s.write(", ") - storeAny(s, a[], stored) - s.write("]") - of akProc, akPointer, akCString: s.write($a.getPointer.ptrToInt) - of akString: - var x = getString(a) - if IsNil(x): s.write("null") - else: s.write(escapeJson(x)) - of akInt..akInt64, akUInt..akUInt64: s.write($getBiggestInt(a)) - of akFloat..akFloat128: s.write($getBiggestFloat(a)) - -proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) = - case a.kind - of akNone: assert false - of akBool: - case p.kind - of jsonFalse: setBiggestInt(a, 0) - of jsonTrue: setBiggestInt(a, 1) - else: raiseParseErr(p, "'true' or 'false' expected for a bool") - next(p) - of akChar: - if p.kind == jsonString: - var x = p.str - if x.len == 1: - setBiggestInt(a, ord(x[0])) - next(p) - return - raiseParseErr(p, "string of length 1 expected for a char") - of akEnum: - if p.kind == jsonString: - setBiggestInt(a, getEnumOrdinal(a, p.str)) - next(p) - return - raiseParseErr(p, "string expected for an enum") - of akArray: - if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for an array") - next(p) - var i = 0 - while p.kind != jsonArrayEnd and p.kind != jsonEof: - loadAny(p, a[i], t) - inc(i) - if p.kind == jsonArrayEnd: next(p) - else: raiseParseErr(p, "']' end of array expected") - of akSequence: - case p.kind - of jsonNull: - setPointer(a, nil) - next(p) - of jsonArrayStart: - next(p) - invokeNewSeq(a, 0) - var i = 0 - while p.kind != jsonArrayEnd and p.kind != jsonEof: - extendSeq(a) - loadAny(p, a[i], t) - inc(i) - if p.kind == jsonArrayEnd: next(p) - else: raiseParseErr(p, "") - else: - raiseParseErr(p, "'[' expected for a seq") - of akObject, akTuple: - if a.kind == akObject: setObjectRuntimeType(a) - if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object") - next(p) - while p.kind != jsonObjectEnd and p.kind != jsonEof: - if p.kind != jsonString: - raiseParseErr(p, "string expected for a field name") - var fieldName = p.str - next(p) - loadAny(p, a[fieldName], t) - if p.kind == jsonObjectEnd: next(p) - else: raiseParseErr(p, "'}' end of object expected") - of akSet: - if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for a set") - next(p) - while p.kind != jsonArrayEnd and p.kind != jsonEof: - if p.kind != jsonInt: raiseParseErr(p, "int expected for a set") - inclSetElement(a, p.getInt.int) - next(p) - if p.kind == jsonArrayEnd: next(p) - else: raiseParseErr(p, "']' end of array expected") - of akPtr, akRef: - case p.kind - of jsonNull: - setPointer(a, nil) - next(p) - of jsonInt: - setPointer(a, t[p.getInt]) - next(p) - of jsonArrayStart: - next(p) - if a.kind == akRef: invokeNew(a) - else: setPointer(a, alloc0(a.baseTypeSize)) - if p.kind == jsonInt: - t[p.getInt] = getPointer(a) - next(p) - else: raiseParseErr(p, "index for ref type expected") - loadAny(p, a[], t) - if p.kind == jsonArrayEnd: next(p) - else: raiseParseErr(p, "']' end of ref-address pair expected") - else: raiseParseErr(p, "int for pointer type expected") - of akProc, akPointer, akCString: - case p.kind - of jsonNull: - setPointer(a, nil) - next(p) - of jsonInt: - setPointer(a, cast[pointer](p.getInt.int)) - next(p) - else: raiseParseErr(p, "int for pointer type expected") - of akString: - case p.kind - of jsonNull: - setPointer(a, nil) - next(p) - of jsonString: - setString(a, p.str) - next(p) - else: raiseParseErr(p, "string expected") - of akInt..akInt64, akUInt..akUInt64: - if p.kind == jsonInt: - setBiggestInt(a, getInt(p)) - next(p) - return - raiseParseErr(p, "int expected") - of akFloat..akFloat128: - if p.kind == jsonFloat: - setBiggestFloat(a, getFloat(p)) - next(p) - return - raiseParseErr(p, "float expected") - of akRange: loadAny(p, a.skipRange, t) - -proc loadAny(s: PStream, a: TAny, t: var TTable[biggestInt, pointer]) = - var p: TJsonParser - open(p, s, "unknown file") - next(p) - loadAny(p, a, t) - close(p) - -proc load*[T](s: PStream, data: var T) = - ## loads `data` from the stream `s`. Raises `EIO` in case of an error. - var tab = initTable[biggestInt, pointer]() - loadAny(s, toAny(data), tab) - -proc store*[T](s: PStream, data: T) = - ## stores `data` into the stream `s`. Raises `EIO` in case of an error. - var stored = initIntSet() - var d: T - shallowCopy(d, data) - storeAny(s, toAny(d), stored) - -proc `$$`*[T](x: T): string = - ## returns a string representation of `x`. - var stored = initIntSet() - var d: T - shallowCopy(d, x) - var s = newStringStream() - storeAny(s, toAny(d), stored) - result = s.data - -proc to*[T](data: string): T = - ## reads data and transforms it to a ``T``. - var tab = initTable[biggestInt, pointer]() - loadAny(newStringStream(data), toAny(result), tab) - -when isMainModule: - template testit(x: expr) = echo($$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 test2: tuple[name: string, s: uint] = ("tuple test", 56u) - testit(test2) - - type - TE = enum - blah, blah2 - - TestObj = object - test, asd: int - case test2: TE - of blah: - help: string - else: - nil - - PNode = ref TNode - TNode = object - next, prev: PNode - data: string - - proc buildList(): PNode = - new(result) - new(result.next) - new(result.prev) - result.data = "middle" - result.next.data = "next" - result.prev.data = "prev" - result.next.next = result.prev - result.next.prev = result - result.prev.next = result - result.prev.prev = result.next - - var test3: TestObj - test3.test = 42 - test3.test2 = blah - testit(test3) - - var test4: ref tuple[a, b: string] - new(test4) - test4.a = "ref string test: A" - test4.b = "ref string test: B" - testit(test4) - - var test5 = @[(0,1),(2,3),(4,5)] - testit(test5) - - var test6: set[char] = {'A'..'Z', '_'} - testit(test6) - - var test7 = buildList() - echo($$test7) - testit(test7) - - type - TA {.inheritable.} = object - TB = object of TA - f: int - - var - a: ref TA - b: ref TB - new(b) - a = b - echo($$a[]) # produces "{}", not "{f: 0}" - +# +# +# Nim's Runtime Library +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module contains procs for serialization and deseralization of +## arbitrary Nim data structures. The serialization format uses JSON. +## +## **Restriction**: For objects their type is **not** serialized. This means +## essentially that it does not work if the object has some other runtime +## type than its compiletime type: +## +## .. code-block:: nim +## +## type +## TA = object +## TB = object of TA +## f: int +## +## var +## a: ref TA +## b: ref TB +## +## new(b) +## a = b +## echo($$a[]) # produces "{}", not "{f: 0}" + +import streams, typeinfo, json, intsets, tables + +proc ptrToInt(x: pointer): int {.inline.} = + result = cast[int](x) # don't skip alignment + +proc storeAny(s: Stream, a: TAny, stored: var IntSet) = + case a.kind + of akNone: assert false + of akBool: s.write($getBool(a)) + of akChar: s.write(escapeJson($getChar(a))) + of akArray, akSequence: + if a.kind == akSequence and isNil(a): s.write("null") + else: + s.write("[") + for i in 0 .. a.len-1: + if i > 0: s.write(", ") + storeAny(s, a[i], stored) + s.write("]") + of akObject, akTuple: + s.write("{") + var i = 0 + for key, val in fields(a): + if i > 0: s.write(", ") + s.write(escapeJson(key)) + s.write(": ") + storeAny(s, val, stored) + inc(i) + s.write("}") + of akSet: + s.write("[") + var i = 0 + for e in elements(a): + if i > 0: s.write(", ") + s.write($e) + inc(i) + s.write("]") + of akRange: storeAny(s, skipRange(a), stored) + of akEnum: s.write(getEnumField(a).escapeJson) + of akPtr, akRef: + var x = a.getPointer + if isNil(x): s.write("null") + elif stored.containsOrIncl(x.ptrToInt): + # already stored, so we simply write out the pointer as an int: + s.write($x.ptrToInt) + else: + # else as a [value, key] pair: + # (reversed order for convenient x[0] access!) + s.write("[") + s.write($x.ptrToInt) + s.write(", ") + storeAny(s, a[], stored) + s.write("]") + of akProc, akPointer, akCString: s.write($a.getPointer.ptrToInt) + of akString: + var x = getString(a) + if isNil(x): s.write("null") + else: s.write(escapeJson(x)) + of akInt..akInt64, akUInt..akUInt64: s.write($getBiggestInt(a)) + of akFloat..akFloat128: s.write($getBiggestFloat(a)) + +proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) = + case a.kind + of akNone: assert false + of akBool: + case p.kind + of jsonFalse: setBiggestInt(a, 0) + of jsonTrue: setBiggestInt(a, 1) + else: raiseParseErr(p, "'true' or 'false' expected for a bool") + next(p) + of akChar: + if p.kind == jsonString: + var x = p.str + if x.len == 1: + setBiggestInt(a, ord(x[0])) + next(p) + return + raiseParseErr(p, "string of length 1 expected for a char") + of akEnum: + if p.kind == jsonString: + setBiggestInt(a, getEnumOrdinal(a, p.str)) + next(p) + return + raiseParseErr(p, "string expected for an enum") + of akArray: + if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for an array") + next(p) + var i = 0 + while p.kind != jsonArrayEnd and p.kind != jsonEof: + loadAny(p, a[i], t) + inc(i) + if p.kind == jsonArrayEnd: next(p) + else: raiseParseErr(p, "']' end of array expected") + of akSequence: + case p.kind + of jsonNull: + setPointer(a, nil) + next(p) + of jsonArrayStart: + next(p) + invokeNewSeq(a, 0) + var i = 0 + while p.kind != jsonArrayEnd and p.kind != jsonEof: + extendSeq(a) + loadAny(p, a[i], t) + inc(i) + if p.kind == jsonArrayEnd: next(p) + else: raiseParseErr(p, "") + else: + raiseParseErr(p, "'[' expected for a seq") + of akObject, akTuple: + if a.kind == akObject: setObjectRuntimeType(a) + if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object") + next(p) + while p.kind != jsonObjectEnd and p.kind != jsonEof: + if p.kind != jsonString: + raiseParseErr(p, "string expected for a field name") + var fieldName = p.str + next(p) + loadAny(p, a[fieldName], t) + if p.kind == jsonObjectEnd: next(p) + else: raiseParseErr(p, "'}' end of object expected") + of akSet: + if p.kind != jsonArrayStart: raiseParseErr(p, "'[' expected for a set") + next(p) + while p.kind != jsonArrayEnd and p.kind != jsonEof: + if p.kind != jsonInt: raiseParseErr(p, "int expected for a set") + inclSetElement(a, p.getInt.int) + next(p) + if p.kind == jsonArrayEnd: next(p) + else: raiseParseErr(p, "']' end of array expected") + of akPtr, akRef: + case p.kind + of jsonNull: + setPointer(a, nil) + next(p) + of jsonInt: + setPointer(a, t[p.getInt]) + next(p) + of jsonArrayStart: + next(p) + if a.kind == akRef: invokeNew(a) + else: setPointer(a, alloc0(a.baseTypeSize)) + if p.kind == jsonInt: + t[p.getInt] = getPointer(a) + next(p) + else: raiseParseErr(p, "index for ref type expected") + loadAny(p, a[], t) + if p.kind == jsonArrayEnd: next(p) + else: raiseParseErr(p, "']' end of ref-address pair expected") + else: raiseParseErr(p, "int for pointer type expected") + of akProc, akPointer, akCString: + case p.kind + of jsonNull: + setPointer(a, nil) + next(p) + of jsonInt: + setPointer(a, cast[pointer](p.getInt.int)) + next(p) + else: raiseParseErr(p, "int for pointer type expected") + of akString: + case p.kind + of jsonNull: + setPointer(a, nil) + next(p) + of jsonString: + setString(a, p.str) + next(p) + else: raiseParseErr(p, "string expected") + of akInt..akInt64, akUInt..akUInt64: + if p.kind == jsonInt: + setBiggestInt(a, getInt(p)) + next(p) + return + raiseParseErr(p, "int expected") + of akFloat..akFloat128: + if p.kind == jsonFloat: + setBiggestFloat(a, getFloat(p)) + next(p) + return + raiseParseErr(p, "float expected") + of akRange: loadAny(p, a.skipRange, t) + +proc loadAny(s: Stream, a: TAny, t: var Table[BiggestInt, pointer]) = + var p: JsonParser + open(p, s, "unknown file") + next(p) + loadAny(p, a, t) + close(p) + +proc load*[T](s: Stream, data: var T) = + ## loads `data` from the stream `s`. Raises `EIO` in case of an error. + var tab = initTable[BiggestInt, pointer]() + loadAny(s, toAny(data), tab) + +proc store*[T](s: Stream, data: T) = + ## stores `data` into the stream `s`. Raises `EIO` in case of an error. + var stored = initIntSet() + var d: T + shallowCopy(d, data) + storeAny(s, toAny(d), stored) + +proc `$$`*[T](x: T): string = + ## returns a string representation of `x`. + var stored = initIntSet() + var d: T + shallowCopy(d, x) + var s = newStringStream() + storeAny(s, toAny(d), stored) + result = s.data + +proc to*[T](data: string): T = + ## reads data and transforms it to a ``T``. + var tab = initTable[BiggestInt, pointer]() + loadAny(newStringStream(data), toAny(result), tab) + +when isMainModule: + template testit(x: expr) = echo($$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 test2: tuple[name: string, s: uint] = ("tuple test", 56u) + testit(test2) + + type + TE = enum + blah, blah2 + + TestObj = object + test, asd: int + case test2: TE + of blah: + help: string + else: + nil + + PNode = ref TNode + TNode = object + next, prev: PNode + data: string + + proc buildList(): PNode = + new(result) + new(result.next) + new(result.prev) + result.data = "middle" + result.next.data = "next" + result.prev.data = "prev" + result.next.next = result.prev + result.next.prev = result + result.prev.next = result + result.prev.prev = result.next + + var test3: TestObj + test3.test = 42 + test3.test2 = blah + testit(test3) + + var test4: ref tuple[a, b: string] + new(test4) + test4.a = "ref string test: A" + test4.b = "ref string test: B" + testit(test4) + + var test5 = @[(0,1),(2,3),(4,5)] + testit(test5) + + var test6: set[char] = {'A'..'Z', '_'} + testit(test6) + + var test7 = buildList() + echo($$test7) + testit(test7) + + type + TA {.inheritable.} = object + TB = object of TA + f: int + + var + a: ref TA + b: ref TB + new(b) + a = b + echo($$a[]) # produces "{}", not "{f: 0}" + diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim index 2db7fa660..46fc9985c 100644 --- a/lib/pure/matchers.nim +++ b/lib/pure/matchers.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# Nim's Runtime Library +# (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -31,8 +31,8 @@ proc validEmailAddress*(s: string): bool {.noSideEffect, inc(i) if s[i] != '@': return false var j = len(s)-1 - if s[j] notin letters: return false - while j >= i and s[j] in letters: dec(j) + if s[j] notin Letters: return false + while j >= i and s[j] in Letters: dec(j) inc(i) # skip '@' while s[i] in {'0'..'9', 'a'..'z', '-', '.'}: inc(i) if s[i] != '\0': return false @@ -44,7 +44,7 @@ proc validEmailAddress*(s: string): bool {.noSideEffect, "aero", "jobs", "museum": return true return false -proc parseInt*(s: string, value: var int, validRange: TSlice[int]) {. +proc parseInt*(s: string, value: var int, validRange: Slice[int]) {. noSideEffect, rtl, extern: "nmatchParseInt".} = ## parses `s` into an integer in the range `validRange`. If successful, ## `value` is modified to contain the result. Otherwise no exception is @@ -53,7 +53,7 @@ proc parseInt*(s: string, value: var int, validRange: TSlice[int]) {. var x = value try: discard parseutils.parseInt(s, x, 0) - except EOverflow: + except OverflowError: discard if x in validRange: value = x diff --git a/lib/pure/math.nim b/lib/pure/math.nim index 8af09114b..32bae18c2 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# Nim's Runtime Library +# (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -9,7 +9,7 @@ ## Constructive mathematics is naturally typed. -- Simon Thompson ## -## Basic math routines for Nimrod. +## Basic math routines for Nim. ## This module is available for the `JavaScript target ## <backends.html#the-javascript-target>`_. @@ -30,19 +30,19 @@ const E* = 2.71828182845904523536028747 ## Euler's number MaxFloat64Precision* = 16 ## maximum number of meaningful digits - ## after the decimal point for Nimrod's + ## after the decimal point for Nim's ## ``float64`` type. MaxFloat32Precision* = 8 ## maximum number of meaningful digits - ## after the decimal point for Nimrod's + ## after the decimal point for Nim's ## ``float32`` type. MaxFloatPrecision* = MaxFloat64Precision ## maximum number of ## meaningful digits ## after the decimal point - ## for Nimrod's ``float`` type. + ## for Nim's ``float`` type. type - TFloatClass* = enum ## describes the class a floating point value belongs to. - ## This is the type that is returned by `classify`. + FloatClass* = enum ## describes the class a floating point value belongs to. + ## This is the type that is returned by `classify`. fcNormal, ## value is an ordinary nonzero floating point value fcSubnormal, ## value is a subnormal (a very small) floating point value fcZero, ## value is zero @@ -51,10 +51,10 @@ type fcInf, ## value is positive infinity fcNegInf ## value is negative infinity -proc classify*(x: float): TFloatClass = +proc classify*(x: float): FloatClass = ## classifies a floating point value. Returns `x`'s class as specified by - ## `TFloatClass`. - + ## `FloatClass`. + # JavaScript and most C compilers have no classify: if x == 0.0: if 1.0/x == Inf: @@ -278,21 +278,23 @@ else: proc `mod`*(x, y: float): float = result = if y == 0.0: x else: x - y * (x/y).floor -proc random*[T](x: TSlice[T]): T = +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)] type - TRunningStat* {.pure,final.} = object ## an accumulator for statistical data - n*: int ## number of pushed data - sum*, min*, max*, mean*: float ## self-explaining + RunningStat* = object ## an accumulator for statistical data + n*: int ## number of pushed data + sum*, min*, max*, mean*: float ## self-explaining oldM, oldS, newS: float -proc push*(s: var TRunningStat, x: float) = +{.deprecated: [TFloatClass: FloatClass, TRunningStat: RunningStat].} + +proc push*(s: var RunningStat, x: float) = ## pushes a value `x` for processing inc(s.n) # See Knuth TAOCP vol 2, 3rd edition, page 232 @@ -313,16 +315,16 @@ proc push*(s: var TRunningStat, x: float) = s.oldS = s.newS s.sum = s.sum + x -proc push*(s: var TRunningStat, x: int) = +proc push*(s: var RunningStat, x: int) = ## pushes a value `x` for processing. `x` is simply converted to ``float`` ## and the other push operation is called. push(s, toFloat(x)) -proc variance*(s: TRunningStat): float = +proc variance*(s: RunningStat): float = ## computes the current variance of `s` if s.n > 1: result = s.newS / (toFloat(s.n - 1)) -proc standardDeviation*(s: TRunningStat): float = +proc standardDeviation*(s: RunningStat): float = ## computes the current standard deviation of `s` result = sqrt(variance(s)) diff --git a/lib/pure/md5.nim b/lib/pure/md5.nim index 0328932fd..3b5453957 100644 --- a/lib/pure/md5.nim +++ b/lib/pure/md5.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this @@ -84,14 +84,14 @@ proc decode(dest: var openArray[int8], src: openArray[int32]) = dest[i+3] = toU8(src[j] shr 24'i32 and 0xff'i32) inc(i, 4) -proc transform(Buffer: pointer, State: var MD5State) = +proc transform(buffer: pointer, state: var MD5State) = var myBlock: MD5Block - encode(myBlock, cast[cstring](Buffer)) - var a = State[0] - var b = State[1] - var c = State[2] - var d = State[3] + encode(myBlock, cast[cstring](buffer)) + var a = state[0] + var b = state[1] + var c = state[2] + var d = state[3] FF(a, b, c, d, myBlock[0], 7'i8, 0xD76AA478'i32) FF(d, a, b, c, myBlock[1], 12'i8, 0xE8C7B756'i32) FF(c, d, a, b, myBlock[2], 17'i8, 0x242070DB'i32) @@ -156,52 +156,52 @@ proc transform(Buffer: pointer, State: var MD5State) = II(d, a, b, c, myBlock[11], 10'i8, 0xBD3AF235'i32) II(c, d, a, b, myBlock[2], 15'i8, 0x2AD7D2BB'i32) II(b, c, d, a, myBlock[9], 21'i8, 0xEB86D391'i32) - State[0] = State[0] +% a - State[1] = State[1] +% b - State[2] = State[2] +% c - State[3] = State[3] +% d + state[0] = state[0] +% a + state[1] = state[1] +% b + state[2] = state[2] +% c + state[3] = state[3] +% d proc md5Init*(c: var MD5Context) = ## initializes a MD5Context - c.State[0] = 0x67452301'i32 - c.State[1] = 0xEFCDAB89'i32 - c.State[2] = 0x98BADCFE'i32 - c.State[3] = 0x10325476'i32 - c.Count[0] = 0'i32 - c.Count[1] = 0'i32 - zeroMem(addr(c.Buffer), sizeof(MD5Buffer)) + c.state[0] = 0x67452301'i32 + c.state[1] = 0xEFCDAB89'i32 + c.state[2] = 0x98BADCFE'i32 + c.state[3] = 0x10325476'i32 + c.count[0] = 0'i32 + c.count[1] = 0'i32 + zeroMem(addr(c.buffer), sizeof(MD5buffer)) proc md5Update*(c: var MD5Context, input: cstring, len: int) = ## updates the MD5Context with the `input` data of length `len` var input = input var Index = (c.count[0] shr 3) and 0x3F - c.Count[0] = c.count[0] +% toU32(len shl 3) - if c.Count[0] < (len shl 3): c.Count[1] = c.count[1] +% 1'i32 - c.Count[1] = c.count[1] +% toU32(len shr 29) + c.count[0] = c.count[0] +% toU32(len shl 3) + if c.count[0] < (len shl 3): c.count[1] = c.count[1] +% 1'i32 + c.count[1] = c.count[1] +% toU32(len shr 29) var PartLen = 64 - Index if len >= PartLen: - copyMem(addr(c.Buffer[Index]), input, PartLen) - transform(addr(c.Buffer), c.State) + copyMem(addr(c.buffer[Index]), input, PartLen) + transform(addr(c.buffer), c.state) var i = PartLen while i + 63 < len: - transform(addr(input[i]), c.State) + transform(addr(input[i]), c.state) inc(i, 64) - copyMem(addr(c.Buffer[0]), addr(input[i]), len-i) + copyMem(addr(c.buffer[0]), addr(input[i]), len-i) else: - copyMem(addr(c.Buffer[Index]), addr(input[0]), len) + copyMem(addr(c.buffer[Index]), addr(input[0]), len) proc md5Final*(c: var MD5Context, digest: var MD5Digest) = ## finishes the MD5Context and stores the result in `digest` var Bits: MD5CBits PadLen: int - decode(Bits, c.Count) - var Index = (c.Count[0] shr 3) and 0x3F + decode(Bits, c.count) + var Index = (c.count[0] shr 3) and 0x3F if Index < 56: PadLen = 56 - Index else: PadLen = 120 - Index md5Update(c, padding, PadLen) md5Update(c, cast[cstring](addr(Bits)), 8) - decode(digest, c.State) + decode(digest, c.state) zeroMem(addr(c), sizeof(MD5Context)) proc toMD5*(s: string): MD5Digest = @@ -216,8 +216,8 @@ proc `$`*(D: MD5Digest): string = const digits = "0123456789abcdef" result = "" for i in 0..15: - add(result, Digits[(D[i] shr 4) and 0xF]) - add(result, Digits[D[i] and 0xF]) + add(result, digits[(D[i] shr 4) and 0xF]) + add(result, digits[D[i] and 0xF]) proc getMD5*(s: string): string = ## computes an MD5 value of `s` and returns its string representation diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index ffeb0beff..24dbfb6d3 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2014 Nimrod Contributors +# Nim's Runtime Library +# (c) Copyright 2014 Nim Contributors # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -22,7 +22,7 @@ else: import os type - TMemFile* = object {.pure.} ## represents a memory mapped file + MemFile* = object ## represents a memory mapped file mem*: pointer ## a pointer to the memory mapped file. The pointer ## can be used directly to change the contents of the ## file, if it was opened with write access. @@ -34,8 +34,9 @@ type else: handle: cint +{.deprecated: [TMemFile: MemFile].} -proc mapMem*(m: var TMemFile, mode: TFileMode = fmRead, +proc mapMem*(m: var MemFile, mode: FileMode = fmRead, mappedSize = -1, offset = 0): pointer = var readonly = mode == fmRead when defined(windows): @@ -47,7 +48,7 @@ proc mapMem*(m: var TMemFile, mode: TFileMode = fmRead, if mappedSize == -1: 0 else: mappedSize, nil) if result == nil: - osError(osLastError()) + raiseOSError(osLastError()) else: assert mappedSize > 0 result = mmap( @@ -57,30 +58,30 @@ proc mapMem*(m: var TMemFile, mode: TFileMode = fmRead, if readonly: (MAP_PRIVATE or MAP_POPULATE) else: (MAP_SHARED or MAP_POPULATE), m.handle, offset) if result == cast[pointer](MAP_FAILED): - osError(osLastError()) + raiseOSError(osLastError()) -proc unmapMem*(f: var TMemFile, p: pointer, size: int) = +proc unmapMem*(f: var MemFile, p: pointer, size: int) = ## unmaps the memory region ``(p, <p+size)`` of the mapped file `f`. ## All changes are written back to the file system, if `f` was opened ## with write access. ``size`` must be of exactly the size that was requested ## via ``mapMem``. when defined(windows): - if unmapViewOfFile(p) == 0: osError(osLastError()) + if unmapViewOfFile(p) == 0: raiseOSError(osLastError()) else: - if munmap(p, size) != 0: osError(osLastError()) + if munmap(p, size) != 0: raiseOSError(osLastError()) -proc open*(filename: string, mode: TFileMode = fmRead, - mappedSize = -1, offset = 0, newFileSize = -1): TMemFile = +proc open*(filename: string, mode: FileMode = fmRead, + mappedSize = -1, offset = 0, newFileSize = -1): MemFile = ## opens a memory mapped file. If this fails, ``EOS`` is raised. ## `newFileSize` can only be set if the file does not exist and is opened ## with write access (e.g., with fmReadWrite). `mappedSize` and `offset` ## can be used to map only a slice of the file. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var - ## mm, mm_full, mm_half: TMemFile + ## mm, mm_full, mm_half: MemFile ## ## mm = memfiles.open("/tmp/test.mmap", mode = fmWrite, newFileSize = 1024) # Create a new file ## mm.close() @@ -100,11 +101,11 @@ proc open*(filename: string, mode: TFileMode = fmRead, result.size = 0 when defined(windows): - template fail(errCode: TOSErrorCode, msg: expr) = + template fail(errCode: OSErrorCode, msg: expr) = rollback() if result.fHandle != 0: discard closeHandle(result.fHandle) if result.mapHandle != 0: discard closeHandle(result.mapHandle) - osError(errCode) + raiseOSError(errCode) # return false #raise newException(EIO, msg) @@ -169,10 +170,10 @@ proc open*(filename: string, mode: TFileMode = fmRead, else: result.size = fileSize.int else: - template fail(errCode: TOSErrorCode, msg: expr) = + template fail(errCode: OSErrorCode, msg: expr) = rollback() if result.handle != 0: discard close(result.handle) - osError(errCode) + raiseOSError(errCode) var flags = if readonly: O_RDONLY else: O_RDWR @@ -214,12 +215,12 @@ proc open*(filename: string, mode: TFileMode = fmRead, if result.mem == cast[pointer](MAP_FAILED): fail(osLastError(), "file mapping failed") -proc close*(f: var TMemFile) = +proc close*(f: var MemFile) = ## closes the memory mapped file `f`. All changes are written back to the ## file system, if `f` was opened with write access. var error = false - var lastErr: TOSErrorCode + var lastErr: OSErrorCode when defined(windows): if f.fHandle != INVALID_HANDLE_VALUE: @@ -242,5 +243,5 @@ proc close*(f: var TMemFile) = else: f.handle = 0 - if error: osError(lastErr) + if error: raiseOSError(lastErr) diff --git a/lib/pure/mersenne.nim b/lib/pure/mersenne.nim index 2b12cce73..a6a781cb8 100644 --- a/lib/pure/mersenne.nim +++ b/lib/pure/mersenne.nim @@ -1,24 +1,26 @@ import unsigned type - TMersenneTwister* = object + MersenneTwister* = object mt: array[0..623, uint32] index: int -proc newMersenneTwister*(seed: int): TMersenneTwister = +{.deprecated: [TMersenneTwister: MersenneTwister].} + +proc newMersenneTwister*(seed: int): MersenneTwister = result.index = 0 result.mt[0]= uint32(seed) for i in 1..623'u32: result.mt[i]= (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i) -proc generateNumbers(m: var TMersenneTwister) = +proc generateNumbers(m: var MersenneTwister) = for i in 0..623: var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32) m.mt[i] = m.mt[(i+397) mod 624] xor uint32(y shr 1'u32) if (y mod 2'u32) != 0: m.mt[i] = m.mt[i] xor 0x9908b0df'u32 -proc getNum*(m: var TMersenneTwister): int = +proc getNum*(m: var MersenneTwister): int = if m.index == 0: generateNumbers(m) var y = m.mt[m.index] @@ -29,11 +31,9 @@ proc getNum*(m: var TMersenneTwister): int = m.index = (m.index+1) mod 624 return int(y) - - # Test when isMainModule: var mt = newMersenneTwister(2525) for i in 0..99: - echo mt.getNum \ No newline at end of file + echo mt.getNum diff --git a/lib/pure/mimetypes.nim b/lib/pure/mimetypes.nim index 92baf0549..a52ba4ebe 100644 --- a/lib/pure/mimetypes.nim +++ b/lib/pure/mimetypes.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Dominik Picheta # # See the file "copying.txt", included in this @@ -10,8 +10,10 @@ ## This module implements a mimetypes database import strtabs type - TMimeDB* = object - mimes: PStringTable + MimeDB* = object + mimes: StringTableRef + +{.deprecated: [TMimeDB: MimeDB].} const mimes* = { "ez": "application/andrew-inset", @@ -489,20 +491,19 @@ const mimes* = { "vrml": "x-world/x-vrml", "wrl": "x-world/x-vrml"} -proc newMimetypes*(): TMimeDB = +proc newMimetypes*(): MimeDB = ## Creates a new Mimetypes database. The database will contain the most ## common mimetypes. - result.mimes = mimes.newStringTable() -proc getMimetype*(mimedb: TMimeDB, ext: string, default = "text/plain"): string = +proc getMimetype*(mimedb: MimeDB, ext: string, default = "text/plain"): string = ## Gets mimetype which corresponds to ``ext``. Returns ``default`` if ``ext`` ## could not be found. result = mimedb.mimes[ext] if result == "": return default -proc getExt*(mimedb: TMimeDB, mimetype: string, default = "txt"): string = +proc getExt*(mimedb: MimeDB, mimetype: string, default = "txt"): string = ## Gets extension which corresponds to ``mimetype``. Returns ``default`` if ## ``mimetype`` could not be found. Extensions are returned without the ## leading dot. @@ -511,11 +512,11 @@ proc getExt*(mimedb: TMimeDB, mimetype: string, default = "txt"): string = if m == mimetype: result = e -proc register*(mimedb: var TMimeDB, ext: string, mimetype: string) = +proc register*(mimedb: var MimeDB, ext: string, mimetype: string) = ## Adds ``mimetype`` to the ``mimedb``. mimedb.mimes[ext] = mimetype when isMainModule: var m = newMimetypes() echo m.getMimetype("mp4") - echo m.getExt("text/html") \ No newline at end of file + echo m.getExt("text/html") diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 696527467..60298ec88 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ {.deadCodeElim: on.} import rawsockets, os, strutils, unsigned, parseutils, times -export TPort, `$`, `==` +export Port, `$`, `==` const useWinVersion = defined(Windows) or defined(nimdoc) @@ -22,25 +22,29 @@ when defined(ssl): when defined(ssl): type - ESSL* = object of ESynch + SslError* = object of Exception - TSSLCVerifyMode* = enum + SslCVerifyMode* = enum CVerifyNone, CVerifyPeer - TSSLProtVersion* = enum + SslProtVersion* = enum protSSLv2, protSSLv3, protTLSv1, protSSLv23 - PSSLContext* = distinct PSSLCTX + SslContext* = distinct SslCtx - TSSLAcceptResult* = enum + SslAcceptResult* = enum AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess + {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode, + TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext, + TSSLAcceptResult: SSLAcceptResult].} + const BufferSize*: int = 4000 ## size of a buffered socket's buffer type - TSocketImpl* = object ## socket type - fd*: TSocketHandle + SocketImpl* = object ## socket type + fd*: SocketHandle case isBuffered*: bool # determines whether this socket is buffered. of true: buffer*: array[0..BufferSize, char] @@ -57,42 +61,46 @@ type sslPeekChar*: char of false: nil - PSocket* = ref TSocketImpl + Socket* = ref SocketImpl - TSOBool* = enum ## Boolean socket options. + SOBool* = enum ## Boolean socket options. OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive, OptOOBInline, OptReuseAddr - TReadLineResult* = enum ## result for readLineAsync + ReadLineResult* = enum ## result for readLineAsync ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone - ETimeout* = object of ESynch + TimeoutError* = object of Exception - TSocketFlags* {.pure.} = enum + SocketFlag* {.pure.} = enum Peek, SafeDisconn ## Ensures disconnection exceptions (ECONNRESET, EPIPE etc) are not thrown. -proc isDisconnectionError*(flags: set[TSocketFlags], - lastError: TOSErrorCode): bool = +{.deprecated: [TSocketFlags: SocketFlag, ETimeout: TimeoutError, + TReadLineResult: ReadLineResult, TSOBool: SOBool, PSocket: Socket, + TSocketImpl: SocketImpl].} + +proc isDisconnectionError*(flags: set[SocketFlag], + lastError: OSErrorCode): bool = ## Determines whether ``lastError`` is a disconnection error. Only does this ## if flags contains ``SafeDisconn``. when useWinVersion: - TSocketFlags.SafeDisconn in flags and + SocketFlag.SafeDisconn in flags and lastError.int32 in {WSAECONNRESET, WSAECONNABORTED, WSAENETRESET, WSAEDISCON, ERROR_NETNAME_DELETED} else: - TSocketFlags.SafeDisconn in flags and + SocketFlag.SafeDisconn in flags and lastError.int32 in {ECONNRESET, EPIPE, ENETRESET} -proc toOSFlags*(socketFlags: set[TSocketFlags]): cint = +proc toOSFlags*(socketFlags: set[SocketFlag]): cint = ## Converts the flags into the underlying OS representation. for f in socketFlags: case f - of TSocketFlags.Peek: + of SocketFlag.Peek: result = result or MSG_PEEK - of TSocketFlags.SafeDisconn: continue + of SocketFlag.SafeDisconn: continue -proc createSocket(fd: TSocketHandle, isBuff: bool): PSocket = +proc createSocket(fd: SocketHandle, isBuff: bool): Socket = assert fd != osInvalidSocket new(result) result.fd = fd @@ -100,14 +108,23 @@ proc createSocket(fd: TSocketHandle, isBuff: bool): PSocket = if isBuff: result.currPos = 0 -proc newSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, - protocol: TProtocol = IPPROTO_TCP, buffered = true): PSocket = +proc newSocket*(domain, typ, protocol: cint, buffered = true): Socket = + ## Creates a new socket. + ## + ## If an error occurs EOS will be raised. + let fd = newRawSocket(domain, typ, protocol) + if fd == osInvalidSocket: + raiseOSError(osLastError()) + result = createSocket(fd, buffered) + +proc newSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP, buffered = true): Socket = ## Creates a new socket. ## ## If an error occurs EOS will be raised. let fd = newRawSocket(domain, typ, protocol) if fd == osInvalidSocket: - osError(osLastError()) + raiseOSError(osLastError()) result = createSocket(fd, buffered) when defined(ssl): @@ -117,16 +134,17 @@ when defined(ssl): ErrLoadBioStrings() OpenSSL_add_all_algorithms() - proc SSLError(s = "") = + proc raiseSSLError*(s = "") = + ## Raises a new SSL error. if s != "": - raise newException(ESSL, s) + raise newException(SSLError, s) let err = ErrPeekLastError() if err == 0: - raise newException(ESSL, "No error reported.") + raise newException(SSLError, "No error reported.") if err == -1: - OSError(OSLastError()) + raiseOSError(osLastError()) var errStr = ErrErrorString(err, nil) - raise newException(ESSL, $errStr) + raise newException(SSLError, $errStr) # http://simplestcodings.blogspot.co.uk/2010/08/secure-server-client-using-openssl-in-c.html proc loadCertificates(ctx: PSSL_CTX, certFile, keyFile: string) = @@ -138,23 +156,23 @@ when defined(ssl): if certFile != "": var ret = SSLCTXUseCertificateChainFile(ctx, certFile) if ret != 1: - SSLError() + raiseSSLError() # TODO: Password? www.rtfm.com/openssl-examples/part1.pdf if keyFile != "": if SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) != 1: - SSLError() + raiseSSLError() if SSL_CTX_check_private_key(ctx) != 1: - SSLError("Verification of private key file failed.") + raiseSSLError("Verification of private key file failed.") - proc newContext*(protVersion = ProtSSLv23, verifyMode = CVerifyPeer, + proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, certFile = "", keyFile = ""): PSSLContext = ## Creates an SSL context. ## - ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 are - ## are available with the addition of ``ProtSSLv23`` which allows for + ## Protocol version specifies the protocol to use. SSLv2, SSLv3, TLSv1 + ## are available with the addition of ``protSSLv23`` which allows for ## compatibility with all of them. ## ## There are currently only two options for verify mode; @@ -174,21 +192,21 @@ when defined(ssl): when not defined(linux): newCTX = SSL_CTX_new(SSLv2_method()) else: - SSLError() + raiseSslError() of protSSLv3: newCTX = SSL_CTX_new(SSLv3_method()) of protTLSv1: newCTX = SSL_CTX_new(TLSv1_method()) if newCTX.SSLCTXSetCipherList("ALL") != 1: - SSLError() + raiseSSLError() case verifyMode of CVerifyPeer: newCTX.SSLCTXSetVerify(SSLVerifyPeer, nil) of CVerifyNone: newCTX.SSLCTXSetVerify(SSLVerifyNone, nil) if newCTX == nil: - SSLError() + raiseSSLError() discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY) newCTX.loadCertificates(certFile, keyFile) @@ -207,13 +225,13 @@ when defined(ssl): socket.sslNoHandshake = false socket.sslHasPeekChar = false if socket.sslHandle == nil: - SSLError() + raiseSSLError() if SSLSetFd(socket.sslHandle, socket.fd) != 1: - SSLError() + raiseSSLError() -proc socketError*(socket: PSocket, err: int = -1, async = false, - lastError = (-1).TOSErrorCode) = +proc socketError*(socket: Socket, err: int = -1, async = false, + lastError = (-1).OSErrorCode) = ## Raises an EOS error based on the error code returned by ``SSLGetError`` ## (for SSL sockets) and ``osLastError`` otherwise. ## @@ -227,20 +245,20 @@ proc socketError*(socket: PSocket, err: int = -1, async = false, var ret = SSLGetError(socket.sslHandle, err.cint) case ret of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: if async: return - else: SSLError("Not enough data on socket.") + else: raiseSSLError("Not enough data on socket.") of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ: if async: return - else: SSLError("Not enough data on socket.") + else: raiseSSLError("Not enough data on socket.") of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() - else: SSLError("Unknown Error") + raiseSSLError() + 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 @@ -248,47 +266,47 @@ proc socketError*(socket: PSocket, err: int = -1, async = false, when useWinVersion: if lastE.int32 == WSAEWOULDBLOCK: return - else: osError(lastE) + else: raiseOSError(lastE) else: if lastE.int32 == EAGAIN or lastE.int32 == EWOULDBLOCK: return - else: osError(lastE) - else: osError(lastE) + else: raiseOSError(lastE) + else: raiseOSError(lastE) -proc listen*(socket: PSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} = +proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} = ## Marks ``socket`` as accepting connections. ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. ## ## Raises an EOS error upon failure. - if listen(socket.fd, backlog) < 0'i32: osError(osLastError()) + if listen(socket.fd, backlog) < 0'i32: raiseOSError(osLastError()) -proc bindAddr*(socket: PSocket, port = TPort(0), address = "") {. - tags: [FReadIO].} = +proc bindAddr*(socket: Socket, port = Port(0), address = "") {. + tags: [ReadIOEffect].} = ## Binds ``address``:``port`` to the socket. ## ## If ``address`` is "" then ADDR_ANY will be bound. if address == "": - var name: TSockaddr_in + var name: Sockaddr_in when useWinVersion: name.sin_family = toInt(AF_INET).int16 else: name.sin_family = toInt(AF_INET) name.sin_port = htons(int16(port)) name.sin_addr.s_addr = htonl(INADDR_ANY) - if bindAddr(socket.fd, cast[ptr TSockAddr](addr(name)), - sizeof(name).TSocklen) < 0'i32: - osError(osLastError()) + if bindAddr(socket.fd, cast[ptr SockAddr](addr(name)), + sizeof(name).SockLen) < 0'i32: + raiseOSError(osLastError()) else: var aiList = getAddrInfo(address, port, AF_INET) - if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.TSocklen) < 0'i32: + if bindAddr(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: dealloc(aiList) - osError(osLastError()) + raiseOSError(osLastError()) dealloc(aiList) -proc acceptAddr*(server: PSocket, client: var PSocket, address: var string, - flags = {TSocketFlags.SafeDisconn}) {.tags: [FReadIO].} = +proc acceptAddr*(server: Socket, client: var Socket, address: var string, + flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} = ## 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. @@ -305,16 +323,16 @@ proc acceptAddr*(server: PSocket, client: var PSocket, address: var string, ## flag is specified then this error will not be raised and instead ## accept will be called again. assert(client != nil) - var sockAddress: Tsockaddr_in - var addrLen = sizeof(sockAddress).TSocklen - var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)), + var sockAddress: Sockaddr_in + var addrLen = sizeof(sockAddress).SockLen + var sock = accept(server.fd, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) if sock == osInvalidSocket: let err = osLastError() if flags.isDisconnectionError(err): acceptAddr(server, client, address, flags) - osError(err) + raiseOSError(err) else: client.fd = sock client.isBuffered = server.isBuffered @@ -363,17 +381,17 @@ when false: #defined(ssl): if err != SSL_ERROR_WANT_ACCEPT: case err of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: client.sslNoHandshake = true return AcceptNoHandshake of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() + raiseSSLError() else: - SSLError("Unknown error") + raiseSSLError("Unknown error") client.sslNoHandshake = false if client.isSSL and client.sslNoHandshake: @@ -383,8 +401,8 @@ when false: #defined(ssl): acceptAddrPlain(AcceptNoClient, AcceptSuccess): doHandshake() -proc accept*(server: PSocket, client: var PSocket, - flags = {TSocketFlags.SafeDisconn}) {.tags: [FReadIO].} = +proc accept*(server: Socket, client: var Socket, + flags = {SocketFlag.SafeDisconn}) {.tags: [ReadIOEffect].} = ## Equivalent to ``acceptAddr`` but doesn't return the address, only the ## socket. ## @@ -398,7 +416,7 @@ proc accept*(server: PSocket, client: var PSocket, var addrDummy = "" acceptAddr(server, client, addrDummy, flags) -proc close*(socket: PSocket) = +proc close*(socket: Socket) = ## Closes a socket. socket.fd.close() when defined(ssl): @@ -410,7 +428,7 @@ proc close*(socket: PSocket) = elif res != 1: socketError(socket) -proc toCInt(opt: TSOBool): cint = +proc toCInt(opt: SOBool): cint = case opt of OptAcceptConn: SO_ACCEPTCONN of OptBroadcast: SO_BROADCAST @@ -420,20 +438,20 @@ proc toCInt(opt: TSOBool): cint = of OptOOBInline: SO_OOBINLINE of OptReuseAddr: SO_REUSEADDR -proc getSockOpt*(socket: PSocket, opt: TSOBool, level = SOL_SOCKET): bool {. - tags: [FReadIO].} = +proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {. + tags: [ReadIOEffect].} = ## Retrieves option ``opt`` as a boolean value. - var res = getsockoptint(socket.fd, cint(level), toCInt(opt)) + var res = getSockOptInt(socket.fd, cint(level), toCInt(opt)) result = res != 0 -proc setSockOpt*(socket: PSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {. - tags: [FWriteIO].} = +proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {. + tags: [WriteIOEffect].} = ## Sets option ``opt`` to a boolean value specified by ``value``. var valuei = cint(if value: 1 else: 0) - setsockoptint(socket.fd, cint(level), toCInt(opt), valuei) + setSockOptInt(socket.fd, cint(level), toCInt(opt), valuei) -proc connect*(socket: PSocket, address: string, port = TPort(0), - af: TDomain = AF_INET) {.tags: [FReadIO].} = +proc connect*(socket: Socket, address: string, port = Port(0), + af: Domain = AF_INET) {.tags: [ReadIOEffect].} = ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a ## host name. If ``address`` is a host name, this function will try each IP ## of that host name. ``htons`` is already performed on ``port`` so you must @@ -443,17 +461,17 @@ proc connect*(socket: PSocket, address: string, port = TPort(0), var aiList = getAddrInfo(address, port, af) # try all possibilities: var success = false - var lastError: TOSErrorCode + var lastError: OSErrorCode var it = aiList while it != nil: - if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen) == 0'i32: + if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32: success = true break else: lastError = osLastError() it = it.ai_next dealloc(aiList) - if not success: osError(lastError) + if not success: raiseOSError(lastError) when defined(ssl): if socket.isSSL: @@ -477,19 +495,19 @@ when defined(ssl): var errret = SSLGetError(socket.sslHandle, ret) case errret of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE: return false of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSSLError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() + raiseSSLError() else: - SSLError("Unknown Error") + raiseSSLError("Unknown Error") socket.sslNoHandshake = false else: - SSLError("Socket is not an SSL socket.") + raiseSSLError("Socket is not an SSL socket.") proc gotHandshake*(socket: PSocket): bool = ## Determines whether a handshake has occurred between a client (``socket``) @@ -499,9 +517,9 @@ when defined(ssl): if socket.isSSL: return not socket.sslNoHandshake else: - SSLError("Socket is not an SSL socket.") + raiseSSLError("Socket is not an SSL socket.") -proc hasDataBuffered*(s: PSocket): bool = +proc hasDataBuffered*(s: Socket): bool = ## Determines whether a socket has data buffered. result = false if s.isBuffered: @@ -511,15 +529,15 @@ proc hasDataBuffered*(s: PSocket): bool = if s.isSSL and not result: result = s.sslHasPeekChar -proc select(readfd: PSocket, timeout = 500): int = +proc select(readfd: Socket, timeout = 500): int = ## Used for socket operation timeouts. if readfd.hasDataBuffered: return 1 - var fds = @[readFd.fd] + var fds = @[readfd.fd] result = select(fds, timeout) -proc readIntoBuf(socket: PSocket, flags: int32): int = +proc readIntoBuf(socket: Socket, flags: int32): int = result = 0 when defined(ssl): if socket.isSSL: @@ -543,7 +561,7 @@ template retRead(flags, readBytes: int) {.dirty.} = else: return res -proc recv*(socket: PSocket, data: pointer, size: int): int {.tags: [FReadIO].} = +proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect].} = ## Receives data from a socket. ## ## **Note**: This is a low-level function, you may be interested in the higher @@ -584,8 +602,8 @@ proc recv*(socket: PSocket, data: pointer, size: int): int {.tags: [FReadIO].} = else: result = recv(socket.fd, data, size.cint, 0'i32) -proc waitFor(socket: PSocket, waited: var float, timeout, size: int, - funcName: string): int {.tags: [FTime].} = +proc waitFor(socket: Socket, waited: var float, timeout, size: int, + funcName: string): int {.tags: [TimeEffect].} = ## determines the amount of characters that can be read. Result will never ## be larger than ``size``. For unbuffered sockets this will be ``1``. ## For buffered sockets it can be as big as ``BufferSize``. @@ -600,7 +618,7 @@ proc waitFor(socket: PSocket, waited: var float, timeout, size: int, result = min(result, size) else: if timeout - int(waited * 1000.0) < 1: - raise newException(ETimeout, "Call to '" & funcName & "' timed out.") + raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") when defined(ssl): if socket.isSSL: @@ -613,13 +631,13 @@ proc waitFor(socket: PSocket, waited: var float, timeout, size: int, var startTime = epochTime() let selRet = select(socket, timeout - int(waited * 1000.0)) - if selRet < 0: osError(osLastError()) + if selRet < 0: raiseOSError(osLastError()) if selRet != 1: - raise newException(ETimeout, "Call to '" & funcName & "' timed out.") + raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") waited += (epochTime() - startTime) -proc recv*(socket: PSocket, data: pointer, size: int, timeout: int): int {. - tags: [FReadIO, FTime].} = +proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {. + tags: [ReadIOEffect, TimeEffect].} = ## overload with a ``timeout`` parameter in miliseconds. var waited = 0.0 # number of seconds already waited @@ -636,8 +654,8 @@ proc recv*(socket: PSocket, data: pointer, size: int, timeout: int): int {. result = read -proc recv*(socket: PSocket, data: var string, size: int, timeout = -1, - flags = {TSocketFlags.SafeDisconn}): int = +proc recv*(socket: Socket, data: var string, size: int, timeout = -1, + flags = {SocketFlag.SafeDisconn}): int = ## Higher-level version of ``recv``. ## ## When 0 is returned the socket's connection has been closed. @@ -660,7 +678,7 @@ proc recv*(socket: PSocket, data: var string, size: int, timeout = -1, socket.socketError(result, lastError = lastError) data.setLen(result) -proc peekChar(socket: PSocket, c: var char): int {.tags: [FReadIO].} = +proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} = if socket.isBuffered: result = 1 if socket.bufLen == 0 or socket.currPos > socket.bufLen-1: @@ -680,9 +698,9 @@ proc peekChar(socket: PSocket, c: var char): int {.tags: [FReadIO].} = return result = recv(socket.fd, addr(c), 1, MSG_PEEK) -proc readLine*(socket: PSocket, line: var TaintedString, timeout = -1, - flags = {TSocketFlags.SafeDisconn}) {. - tags: [FReadIO, FTime].} = +proc readLine*(socket: Socket, line: var TaintedString, timeout = -1, + flags = {SocketFlag.SafeDisconn}) {. + tags: [ReadIOEffect, TimeEffect].} = ## Reads a line of data from ``socket``. ## ## If a full line is read ``\r\L`` is not @@ -729,9 +747,9 @@ proc readLine*(socket: PSocket, line: var TaintedString, timeout = -1, return add(line.string, c) -proc recvFrom*(socket: PSocket, data: var string, length: int, - address: var string, port: var TPort, flags = 0'i32): int {. - tags: [FReadIO].} = +proc recvFrom*(socket: Socket, data: var string, length: int, + address: var string, port: var Port, flags = 0'i32): int {. + tags: [ReadIOEffect].} = ## Receives data from ``socket``. This function should normally be used with ## connection-less sockets (UDP sockets). ## @@ -745,19 +763,19 @@ proc recvFrom*(socket: PSocket, data: var string, length: int, # TODO: Buffered sockets data.setLen(length) - var sockAddress: Tsockaddr_in - var addrLen = sizeof(sockAddress).TSocklen + var sockAddress: Sockaddr_in + var addrLen = sizeof(sockAddress).SockLen result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, - cast[ptr TSockAddr](addr(sockAddress)), addr(addrLen)) + cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) if result != -1: data.setLen(result) address = $inet_ntoa(sockAddress.sin_addr) - port = ntohs(sockAddress.sin_port).TPort + port = ntohs(sockAddress.sin_port).Port else: - osError(osLastError()) + raiseOSError(osLastError()) -proc skip*(socket: PSocket, size: int, timeout = -1) = +proc skip*(socket: Socket, size: int, timeout = -1) = ## Skips ``size`` amount of bytes. ## ## An optional timeout can be specified in miliseconds, if skipping the @@ -772,8 +790,8 @@ proc skip*(socket: PSocket, size: int, timeout = -1) = bytesSkipped += recv(socket, dummy, avail) dealloc(dummy) -proc send*(socket: PSocket, data: pointer, size: int): int {. - tags: [FWriteIO].} = +proc send*(socket: Socket, data: pointer, size: int): int {. + tags: [WriteIOEffect].} = ## Sends data to a socket. ## ## **Note**: This is a low-level version of ``send``. You likely should use @@ -789,8 +807,8 @@ proc send*(socket: PSocket, data: pointer, size: int): int {. const MSG_NOSIGNAL = 0 result = send(socket.fd, data, size, int32(MSG_NOSIGNAL)) -proc send*(socket: PSocket, data: string, - flags = {TSocketFlags.SafeDisconn}) {.tags: [FWriteIO].} = +proc send*(socket: Socket, data: string, + flags = {SocketFlag.SafeDisconn}) {.tags: [WriteIOEffect].} = ## sends data to a socket. let sent = send(socket, cstring(data), data.len) if sent < 0: @@ -799,16 +817,16 @@ proc send*(socket: PSocket, data: string, socketError(socket, lastError = lastError) if sent != data.len: - raise newException(EOS, "Could not send all data.") + raise newException(OSError, "Could not send all data.") -proc trySend*(socket: PSocket, data: string): bool {.tags: [FWriteIO].} = +proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} = ## Safe alternative to ``send``. Does not raise an EOS when an error occurs, ## and instead returns ``false`` on failure. result = send(socket, cstring(data), data.len) == data.len -proc sendTo*(socket: PSocket, address: string, port: TPort, data: pointer, - size: int, af: TDomain = AF_INET, flags = 0'i32): int {. - tags: [FWriteIO].} = +proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, + size: int, af: Domain = AF_INET, flags = 0'i32): int {. + tags: [WriteIOEffect].} = ## This proc sends ``data`` to the specified ``address``, ## which may be an IP address or a hostname, if a hostname is specified ## this function will try each IP of that hostname. @@ -825,7 +843,7 @@ proc sendTo*(socket: PSocket, address: string, port: TPort, data: pointer, var it = aiList while it != nil: result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr, - it.ai_addrlen.TSocklen) + it.ai_addrlen.SockLen) if result != -1'i32: success = true break @@ -833,8 +851,8 @@ proc sendTo*(socket: PSocket, address: string, port: TPort, data: pointer, dealloc(aiList) -proc sendTo*(socket: PSocket, address: string, port: TPort, - data: string): int {.tags: [FWriteIO].} = +proc sendTo*(socket: Socket, address: string, port: Port, + data: string): int {.tags: [WriteIOEffect].} = ## This proc sends ``data`` to the specified ``address``, ## which may be an IP address or a hostname, if a hostname is specified ## this function will try each IP of that hostname. @@ -842,8 +860,8 @@ proc sendTo*(socket: PSocket, address: string, port: TPort, ## This is the high-level version of the above ``sendTo`` function. result = socket.sendTo(address, port, cstring(data), data.len) -proc connectAsync(socket: PSocket, name: string, port = TPort(0), - af: TDomain = AF_INET) {.tags: [FReadIO].} = +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 @@ -855,10 +873,10 @@ proc connectAsync(socket: PSocket, name: string, port = TPort(0), var aiList = getAddrInfo(name, port, af) # try all possibilities: var success = false - var lastError: TOSErrorCode + var lastError: OSErrorCode var it = aiList while it != nil: - var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen) + var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) if ret == 0'i32: success = true break @@ -877,10 +895,10 @@ proc connectAsync(socket: PSocket, name: string, port = TPort(0), it = it.ai_next dealloc(aiList) - if not success: osError(lastError) + if not success: raiseOSError(lastError) -proc connect*(socket: PSocket, address: string, port = TPort(0), timeout: int, - af: TDomain = AF_INET) {.tags: [FReadIO, FWriteIO].} = +proc connect*(socket: Socket, address: string, port = Port(0), timeout: int, + af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} = ## Connects to server as specified by ``address`` on port specified by ``port``. ## ## The ``timeout`` paremeter specifies the time in miliseconds to allow for @@ -890,7 +908,7 @@ proc connect*(socket: PSocket, address: string, port = TPort(0), timeout: int, socket.connectAsync(address, port, af) var s = @[socket.fd] if selectWrite(s, timeout) != 1: - raise newException(ETimeout, "Call to 'connect' timed out.") + raise newException(TimeoutError, "Call to 'connect' timed out.") else: when defined(ssl): if socket.isSSL: @@ -898,10 +916,10 @@ proc connect*(socket: PSocket, address: string, port = TPort(0), timeout: int, doAssert socket.handshake() socket.fd.setBlocking(true) -proc isSSL*(socket: PSocket): bool = return socket.isSSL +proc isSSL*(socket: Socket): bool = return socket.isSSL ## Determines whether ``socket`` is a SSL socket. -proc getFD*(socket: PSocket): TSocketHandle = return socket.fd +proc getFD*(socket: Socket): SocketHandle = return socket.fd ## Returns the socket's file descriptor type @@ -1036,23 +1054,23 @@ proc parseIPv4Address(address_str: string): TIpAddress = currentByte = currentByte * 10 + cast[uint16](ord(address_str[i]) - ord('0')) if currentByte > 255'u16: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Value is out of range") seperatorValid = true elif address_str[i] == '.': # IPv4 address separator if not seperatorValid or byteCount >= 3: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. The address consists of too many groups") result.address_v4[byteCount] = cast[uint8](currentByte) currentByte = 0 byteCount.inc seperatorValid = false else: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Address contains an invalid character") if byteCount != 3 or not seperatorValid: - raise newException(EInvalidValue, "Invalid IP Address") + raise newException(ValueError, "Invalid IP Address") result.address_v4[byteCount] = cast[uint8](currentByte) proc parseIPv6Address(address_str: string): TIpAddress = @@ -1060,7 +1078,7 @@ proc parseIPv6Address(address_str: string): TIpAddress = ## Raises EInvalidValue on errors result.family = IpAddressFamily.IPv6 if address_str.len < 2: - raise newException(EInvalidValue, "Invalid IP Address") + raise newException(ValueError, "Invalid IP Address") var groupCount = 0 @@ -1075,17 +1093,17 @@ proc parseIPv6Address(address_str: string): TIpAddress = for i,c in address_str: if c == ':': if not seperatorValid: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Address contains an invalid seperator") if lastWasColon: if dualColonGroup != -1: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Address contains more than one \"::\" seperator") dualColonGroup = groupCount seperatorValid = false elif i != 0 and i != high(address_str): if groupCount >= 8: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. The address consists of too many groups") result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8) result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF) @@ -1094,17 +1112,17 @@ proc parseIPv6Address(address_str: string): TIpAddress = if dualColonGroup != -1: seperatorValid = false elif i == 0: # only valid if address starts with :: if address_str[1] != ':': - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Address may not start with \":\"") else: # i == high(address_str) - only valid if address ends with :: if address_str[high(address_str)-1] != ':': - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Address may not end with \":\"") lastWasColon = true currentGroupStart = i + 1 elif c == '.': # Switch to parse IPv4 mode if i < 3 or not seperatorValid or groupCount >= 7: - raise newException(EInvalidValue, "Invalid IP Address") + raise newException(ValueError, "Invalid IP Address") v4StartPos = currentGroupStart currentShort = 0 seperatorValid = false @@ -1117,19 +1135,19 @@ proc parseIPv6Address(address_str: string): TIpAddress = else: # Upper case hex currentShort = (currentShort shl 4) + cast[uint32](ord(c) - ord('A')) + 10 if currentShort > 65535'u32: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Value is out of range") lastWasColon = false seperatorValid = true else: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Address contains an invalid character") if v4StartPos == -1: # Don't parse v4. Copy the remaining v6 stuff if seperatorValid: # Copy remaining data if groupCount >= 8: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. The address consists of too many groups") result.address_v6[groupCount*2] = cast[uint8](currentShort shr 8) result.address_v6[groupCount*2+1] = cast[uint8](currentShort and 0xFF) @@ -1139,32 +1157,32 @@ proc parseIPv6Address(address_str: string): TIpAddress = if c in strutils.Digits: # Character is a number currentShort = currentShort * 10 + cast[uint32](ord(c) - ord('0')) if currentShort > 255'u32: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Value is out of range") seperatorValid = true elif c == '.': # IPv4 address separator if not seperatorValid or byteCount >= 3: - raise newException(EInvalidValue, "Invalid IP Address") + raise newException(ValueError, "Invalid IP Address") result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort) currentShort = 0 byteCount.inc() seperatorValid = false else: # Invalid character - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. Address contains an invalid character") if byteCount != 3 or not seperatorValid: - raise newException(EInvalidValue, "Invalid IP Address") + raise newException(ValueError, "Invalid IP Address") result.address_v6[groupCount*2 + byteCount] = cast[uint8](currentShort) groupCount += 2 # Shift and fill zeros in case of :: if groupCount > 8: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. The address consists of too many groups") elif groupCount < 8: # must fill if dualColonGroup == -1: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. The address consists of too few groups") var toFill = 8 - groupCount # The number of groups to fill var toShift = groupCount - dualColonGroup # Nr of known groups after :: @@ -1173,14 +1191,14 @@ proc parseIPv6Address(address_str: string): TIpAddress = for i in 0..2*toFill-1: # fill with 0s result.address_v6[dualColonGroup*2+i] = 0 elif dualColonGroup != -1: - raise newException(EInvalidValue, + raise newException(ValueError, "Invalid IP Address. The address consists of too many groups") proc parseIpAddress*(address_str: string): TIpAddress = ## Parses an IP address ## Raises EInvalidValue on error if address_str == nil: - raise newException(EInvalidValue, "IP Address string is nil") + raise newException(ValueError, "IP Address string is nil") if address_str.contains(':'): return parseIPv6Address(address_str) else: diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 6f94d0656..3598cdd3a 100644 --- a/lib/pure/nimprof.nim +++ b/lib/pure/nimprof.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Profiling support for Nimrod. This is an embedded profiler that requires +## Profiling support for Nim. This is an embedded profiler that requires ## ``--profiler:on``. You only need to import this module to get a profiling ## report at program exit. @@ -64,7 +64,7 @@ when withThreads: var profilingLock: TLock - InitLock profilingLock + initLock profilingLock proc hookAux(st: TStackTrace, costs: int) = # this is quite performance sensitive! @@ -132,9 +132,9 @@ else: proc hook(st: TStackTrace) {.nimcall.} = if interval == 0: hookAux(st, 1) - elif getticks() - t0 > interval: + elif getTicks() - t0 > interval: hookAux(st, 1) - t0 = getticks() + t0 = getTicks() proc getTotal(x: ptr TProfileEntry): int = result = if isNil(x): 0 else: x.total @@ -150,7 +150,7 @@ proc writeProfile() {.noconv.} = system.profilerHook = nil const filename = "profile_results.txt" echo "writing " & filename & "..." - var f: TFile + var f: File if open(f, filename, fmWrite): sort(profileData, cmpEntries) writeln(f, "total executions of each stack trace:") diff --git a/lib/pure/numeric.nim b/lib/pure/numeric.nim index 8ef5fabda..9b298c0a0 100644 --- a/lib/pure/numeric.nim +++ b/lib/pure/numeric.nim @@ -1,16 +1,17 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Robert Persson # # See the file "copying.txt", included in this # distribution, for details about the copyright. # +type OneVarFunction* = proc (x: float): float -type TOneVarFunction* =proc (x:float):float +{.deprecated: [TOneVarFunction: OneVarFunction].} -proc brent*(xmin,xmax:float ,function:TOneVarFunction, tol:float,maxiter=1000): +proc brent*(xmin,xmax:float, function:OneVarFunction, tol:float,maxiter=1000): tuple[rootx, rooty: float, success: bool]= ## Searches `function` for a root between `xmin` and `xmax` ## using brents method. If the function value at `xmin`and `xmax` has the diff --git a/lib/pure/oids.nim b/lib/pure/oids.nim index 2843e6c65..7c58a2dda 100644 --- a/lib/pure/oids.nim +++ b/lib/pure/oids.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Nimrod OID support. An OID is a global ID that consists of a timestamp, +## Nim OID support. An OID is a global ID that consists of a timestamp, ## a unique counter and a random value. This combination should suffice to ## produce a globally distributed unique ID. This implementation was extracted ## from the Mongodb interface and it thus binary compatible with a Mongo OID. @@ -18,11 +18,13 @@ import times, endians type - Toid* {.pure, final.} = object ## an OID + Oid* = object ## an OID time: int32 ## fuzz: int32 ## count: int32 ## +{.deprecated: [Toid: Oid].} + proc hexbyte*(hex: char): int = case hex of '0'..'9': result = (ord(hex) - ord('0')) @@ -30,7 +32,7 @@ proc hexbyte*(hex: char): int = of 'A'..'F': result = (ord(hex) - ord('A') + 10) else: discard -proc parseOid*(str: cstring): TOid = +proc parseOid*(str: cstring): Oid = ## parses an OID. var bytes = cast[cstring](addr(result.time)) var i = 0 @@ -38,7 +40,7 @@ proc parseOid*(str: cstring): TOid = bytes[i] = chr((hexbyte(str[2 * i]) shl 4) or hexbyte(str[2 * i + 1])) inc(i) -proc oidToString*(oid: TOid, str: cstring) = +proc oidToString*(oid: Oid, str: cstring) = const hex = "0123456789abcdef" # work around a compiler bug: var str = str @@ -52,7 +54,7 @@ proc oidToString*(oid: TOid, str: cstring) = inc(i) str[24] = '\0' -proc `$`*(oid: TOid): string = +proc `$`*(oid: Oid): string = result = newString(25) oidToString(oid, result) @@ -60,7 +62,7 @@ var incr: int fuzz: int32 -proc genOid*(): TOid = +proc genOid*(): Oid = ## generates a new OID. proc rand(): cint {.importc: "rand", header: "<stdlib.h>", nodecl.} proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".} @@ -79,13 +81,13 @@ proc genOid*(): TOid = result.fuzz = fuzz bigEndian32(addr result.count, addr(i)) -proc generatedTime*(oid: TOid): TTime = +proc generatedTime*(oid: Oid): Time = ## returns the generated timestamp of the OID. var tmp: int32 var dummy = oid.time bigEndian32(addr(tmp), addr(dummy)) - result = TTime(tmp) + result = Time(tmp) when isMainModule: - let xo = genOID() + let xo = genOid() echo xo.generatedTime diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 71089494f..3a6930654 100644 --- a/lib/pure/os.nim +++ b/lib/pure/os.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -29,18 +29,23 @@ else: include "system/ansi_c" type - FReadEnv* = object of FReadIO ## effect that denotes a read - ## from an environment variable - FWriteEnv* = object of FWriteIO ## effect that denotes a write - ## to an environment variable - - FReadDir* = object of FReadIO ## effect that denotes a write operation to - ## the directory structure - FWriteDir* = object of FWriteIO ## effect that denotes a write operation to - ## the directory structure - - TOSErrorCode* = distinct int32 ## Specifies an OS Error Code. - + ReadEnvEffect* = object of ReadIOEffect ## effect that denotes a read + ## from an environment variable + WriteEnvEffect* = object of WriteIOEffect ## effect that denotes a write + ## to an environment variable + + ReadDirEffect* = object of ReadIOEffect ## effect that denotes a write + ## operation to the directory structure + WriteDirEffect* = object of WriteIOEffect ## effect that denotes a write operation to + ## the directory structure + + OSErrorCode* = distinct int32 ## Specifies an OS Error Code. + +{.deprecated: [FReadEnv: ReadEnvEffect, FWriteEnv: WriteEnvEffect, + FReadDir: ReadDirEffect, + FWriteDir: WriteDirEffect, + TOSErrorCode: OSErrorCode +].} const doslike = defined(windows) or defined(OS2) or defined(DOS) # DOS-like filesystem @@ -75,7 +80,7 @@ when defined(Nimdoc): # only for proper documentation: ## search patch components (as in PATH), such as ':' for POSIX or ';' for ## Windows. - FileSystemCaseSensitive* = True + FileSystemCaseSensitive* = true ## True if the file system is case sensitive, false otherwise. Used by ## `cmpPaths` to compare filenames properly. @@ -182,7 +187,7 @@ proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} = ## On Windows ``GetLastError`` is checked before ``errno``. ## Returns "" if no error occured. ## - ## **Deprecated since version 0.9.4**: use the other ``OSErrorMsg`` proc. + ## **Deprecated since version 0.9.4**: use the other ``osErrorMsg`` proc. result = "" when defined(Windows): @@ -204,7 +209,8 @@ proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} = result = $os.strerror(errno) {.push warning[deprecated]: off.} -proc osError*(msg: string = "") {.noinline, rtl, extern: "nos$1", deprecated.} = +proc raiseOSError*(msg: string = "") {.noinline, rtl, extern: "nos$1", + deprecated.} = ## raises an EOS exception with the given message ``msg``. ## If ``msg == ""``, the operating system's error flag ## (``errno``) is converted to a readable error message. On Windows @@ -214,15 +220,18 @@ proc osError*(msg: string = "") {.noinline, rtl, extern: "nos$1", deprecated.} = ## **Deprecated since version 0.9.4**: use the other ``OSError`` proc. if len(msg) == 0: var m = osErrorMsg() - raise newException(EOS, if m.len > 0: m else: "unknown OS error") + raise newException(OSError, if m.len > 0: m else: "unknown OS error") else: - raise newException(EOS, msg) + raise newException(OSError, msg) {.pop.} -proc `==`*(err1, err2: TOSErrorCode): bool {.borrow.} -proc `$`*(err: TOSErrorCode): string {.borrow.} +when not defined(nimfix): + {.deprecated: [osError: raiseOSError].} -proc osErrorMsg*(errorCode: TOSErrorCode): string = +proc `==`*(err1, err2: OSErrorCode): bool {.borrow.} +proc `$`*(err: OSErrorCode): string {.borrow.} + +proc osErrorMsg*(errorCode: OSErrorCode): string = ## Converts an OS error code into a human readable string. ## ## The error code can be retrieved using the ``OSLastError`` proc. @@ -235,7 +244,7 @@ proc osErrorMsg*(errorCode: TOSErrorCode): string = ## message. result = "" when defined(Windows): - if errorCode != TOSErrorCode(0'i32): + if errorCode != OSErrorCode(0'i32): when useWinUnicode: var msgbuf: WideCString if formatMessageW(0x00000100 or 0x00001000 or 0x00000200, @@ -249,10 +258,10 @@ proc osErrorMsg*(errorCode: TOSErrorCode): string = result = $msgbuf if msgbuf != nil: localFree(msgbuf) else: - if errorCode != TOSErrorCode(0'i32): + if errorCode != OSErrorCode(0'i32): result = $os.strerror(errorCode.int32) -proc osError*(errorCode: TOSErrorCode) = +proc raiseOSError*(errorCode: OSErrorCode) = ## Raises an ``EOS`` exception. The ``errorCode`` will determine the ## message, ``OSErrorMsg`` will be used to get this message. ## @@ -260,7 +269,7 @@ proc osError*(errorCode: TOSErrorCode) = ## ## If the error code is ``0`` or an error message could not be retrieved, ## the message ``unknown OS error`` will be used. - var e: ref EOS; new(e) + var e: ref OSError; new(e) e.errorCode = errorCode.int32 e.msg = osErrorMsg(errorCode) if e.msg == "": @@ -268,7 +277,7 @@ proc osError*(errorCode: TOSErrorCode) = raise e {.push stackTrace:off.} -proc osLastError*(): TOSErrorCode = +proc osLastError*(): OSErrorCode = ## Retrieves the last operating system error code. ## ## This procedure is useful in the event when an OS call fails. In that case @@ -283,9 +292,9 @@ proc osLastError*(): TOSErrorCode = ## immediately after an OS call fails. On POSIX systems this is not a problem. when defined(windows): - result = TOSErrorCode(getLastError()) + result = OSErrorCode(getLastError()) else: - result = TOSErrorCode(errno) + result = OSErrorCode(errno) {.pop.} proc unixToNativePath*(path: string, drive=""): string {. @@ -371,7 +380,7 @@ when defined(windows): f.cFileName[1].int == dot and f.cFileName[2].int == 0) proc existsFile*(filename: string): bool {.rtl, extern: "nos$1", - tags: [FReadDir].} = + tags: [ReadDirEffect].} = ## Returns true if the file exists, false otherwise. when defined(windows): when useWinUnicode: @@ -384,7 +393,7 @@ proc existsFile*(filename: string): bool {.rtl, extern: "nos$1", var res: TStat return stat(filename, res) >= 0'i32 and S_ISREG(res.st_mode) -proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [FReadDir].} = +proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [ReadDirEffect].} = ## Returns true iff the directory `dir` exists. If `dir` is a file, false ## is returned. when defined(windows): @@ -399,7 +408,7 @@ proc existsDir*(dir: string): bool {.rtl, extern: "nos$1", tags: [FReadDir].} = return stat(dir, res) >= 0'i32 and S_ISDIR(res.st_mode) proc symlinkExists*(link: string): bool {.rtl, extern: "nos$1", - tags: [FReadDir].} = + tags: [ReadDirEffect].} = ## Returns true iff the symlink `link` exists. Will return true ## regardless of whether the link points to a directory or file. when defined(windows): @@ -421,44 +430,44 @@ proc dirExists*(dir: string): bool {.inline.} = ## Synonym for existsDir existsDir(dir) -proc getLastModificationTime*(file: string): TTime {.rtl, extern: "nos$1".} = +proc getLastModificationTime*(file: string): Time {.rtl, extern: "nos$1".} = ## Returns the `file`'s last modification time. when defined(posix): var res: TStat - if stat(file, res) < 0'i32: osError(osLastError()) + if stat(file, res) < 0'i32: raiseOSError(osLastError()) return res.st_mtime else: var f: TWIN32_FIND_DATA var h = findFirstFile(file, f) - if h == -1'i32: osError(osLastError()) + if h == -1'i32: raiseOSError(osLastError()) result = winTimeToUnixTime(rdFileTime(f.ftLastWriteTime)) findClose(h) -proc getLastAccessTime*(file: string): TTime {.rtl, extern: "nos$1".} = +proc getLastAccessTime*(file: string): Time {.rtl, extern: "nos$1".} = ## Returns the `file`'s last read or write access time. when defined(posix): var res: TStat - if stat(file, res) < 0'i32: osError(osLastError()) + if stat(file, res) < 0'i32: raiseOSError(osLastError()) return res.st_atime else: var f: TWIN32_FIND_DATA var h = findFirstFile(file, f) - if h == -1'i32: osError(osLastError()) + if h == -1'i32: raiseOSError(osLastError()) result = winTimeToUnixTime(rdFileTime(f.ftLastAccessTime)) findClose(h) -proc getCreationTime*(file: string): TTime {.rtl, extern: "nos$1".} = +proc getCreationTime*(file: string): Time {.rtl, extern: "nos$1".} = ## Returns the `file`'s creation time. ## Note that under posix OS's, the returned time may actually be the time at ## which the file's attribute's were last modified. when defined(posix): var res: TStat - if stat(file, res) < 0'i32: osError(osLastError()) + if stat(file, res) < 0'i32: raiseOSError(osLastError()) return res.st_ctime else: var f: TWIN32_FIND_DATA var h = findFirstFile(file, f) - if h == -1'i32: osError(osLastError()) + if h == -1'i32: raiseOSError(osLastError()) result = winTimeToUnixTime(rdFileTime(f.ftCreationTime)) findClose(h) @@ -474,19 +483,19 @@ proc getCurrentDir*(): string {.rtl, extern: "nos$1", tags: [].} = when useWinUnicode: var res = newWideCString("", bufsize) var L = getCurrentDirectoryW(bufsize, res) - if L == 0'i32: osError(osLastError()) + if L == 0'i32: raiseOSError(osLastError()) result = res$L else: result = newString(bufsize) var L = getCurrentDirectoryA(bufsize, result) - if L == 0'i32: osError(osLastError()) + if L == 0'i32: raiseOSError(osLastError()) setLen(result, L) else: result = newString(bufsize) if getcwd(result, bufsize) != nil: setLen(result, c_strlen(result)) else: - osError(osLastError()) + raiseOSError(osLastError()) proc setCurrentDir*(newDir: string) {.inline, tags: [].} = ## Sets the `current working directory`:idx:; `EOS` is raised if @@ -494,11 +503,11 @@ proc setCurrentDir*(newDir: string) {.inline, tags: [].} = when defined(Windows): when useWinUnicode: if setCurrentDirectoryW(newWideCString(newDir)) == 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) else: - if setCurrentDirectoryA(newDir) == 0'i32: osError(osLastError()) + if setCurrentDirectoryA(newDir) == 0'i32: raiseOSError(osLastError()) else: - if chdir(newDir) != 0'i32: osError(osLastError()) + if chdir(newDir) != 0'i32: raiseOSError(osLastError()) proc joinPath*(head, tail: string): string {. noSideEffect, rtl, extern: "nos$1".} = @@ -506,12 +515,12 @@ proc joinPath*(head, tail: string): string {. ## ## For example on Unix: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## joinPath("usr", "lib") ## ## results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "usr/lib" ## ## If head is the empty string, tail is returned. If tail is the empty @@ -520,7 +529,7 @@ proc joinPath*(head, tail: string): string {. ## path separators not located on boundaries won't be modified. More ## examples on Unix: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## assert joinPath("usr", "") == "usr/" ## assert joinPath("", "lib") == "lib" ## assert joinPath("", "/lib") == "/lib" @@ -552,7 +561,7 @@ proc `/` * (head, tail: string): string {.noSideEffect.} = ## ## Here are some examples for Unix: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## assert "usr" / "" == "usr/" ## assert "" / "lib" == "lib" ## assert "" / "/lib" == "/lib" @@ -566,7 +575,7 @@ proc splitPath*(path: string): tuple[head, tail: string] {. ## ## Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## splitPath("usr/local/bin") -> ("usr/local", "bin") ## splitPath("usr/local/bin/") -> ("usr/local/bin", "") ## splitPath("bin") -> ("", "bin") @@ -666,10 +675,10 @@ proc splitFile*(path: string): tuple[dir, name, ext: string] {. ## ## Example: ## - ## .. code-block:: nimrod - ## var (dir, name, ext) = splitFile("usr/local/nimrodc.html") + ## .. code-block:: nim + ## var (dir, name, ext) = splitFile("usr/local/nimc.html") ## assert dir == "usr/local" - ## assert name == "nimrodc" + ## assert name == "nimc" ## assert ext == ".html" ## ## If `path` has no extension, `ext` is the empty string. @@ -701,7 +710,7 @@ proc extractFilename*(path: string): string {. result = splitPath(path).tail proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", - tags: [FReadDir].} = + tags: [ReadDirEffect].} = ## Returns the full path of `filename`, raises EOS in case of an error. when defined(windows): const bufsize = 3072'i32 @@ -710,19 +719,19 @@ proc expandFilename*(filename: string): string {.rtl, extern: "nos$1", var res = newWideCString("", bufsize div 2) var L = getFullPathNameW(newWideCString(filename), bufsize, res, unused) if L <= 0'i32 or L >= bufsize: - osError(osLastError()) + raiseOSError(osLastError()) result = res$L else: var unused: cstring result = newString(bufsize) var L = getFullPathNameA(filename, bufsize, result, unused) - if L <= 0'i32 or L >= bufsize: osError(osLastError()) + if L <= 0'i32 or L >= bufsize: raiseOSError(osLastError()) setLen(result, L) else: # careful, realpath needs to take an allocated buffer according to Posix: result = newString(pathMax) var r = realpath(filename, result) - if r.isNil: osError(osLastError()) + if r.isNil: raiseOSError(osLastError()) setLen(result, c_strlen(result)) proc changeFileExt*(filename, ext: string): string {. @@ -800,7 +809,7 @@ when defined(Windows): ) proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", - tags: [FReadDir].} = + tags: [ReadDirEffect].} = ## Returns True if both pathname arguments refer to the same physical ## file or directory. Raises an exception if any of the files does not ## exist or information about it can not be obtained. @@ -812,7 +821,7 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", var f1 = openHandle(path1) var f2 = openHandle(path2) - var lastErr: TOSErrorCode + var lastErr: OSErrorCode if f1 != INVALID_HANDLE_VALUE and f2 != INVALID_HANDLE_VALUE: var fi1, fi2: TBY_HANDLE_FILE_INFORMATION @@ -831,22 +840,22 @@ proc sameFile*(path1, path2: string): bool {.rtl, extern: "nos$1", discard closeHandle(f1) discard closeHandle(f2) - if not success: osError(lastErr) + if not success: raiseOSError(lastErr) else: var a, b: TStat if stat(path1, a) < 0'i32 or stat(path2, b) < 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) else: result = a.st_dev == b.st_dev and a.st_ino == b.st_ino proc sameFileContent*(path1, path2: string): bool {.rtl, extern: "nos$1", - tags: [FReadIO].} = + tags: [ReadIOEffect].} = ## Returns True if both pathname arguments refer to files with identical ## binary content. const bufSize = 8192 # 8K buffer var - a, b: TFile + a, b: File if not open(a, path1): return false if not open(b, path2): close(a) @@ -883,13 +892,13 @@ type fpOthersRead ## read access for others proc getFilePermissions*(filename: string): set[TFilePermission] {. - rtl, extern: "nos$1", tags: [FReadDir].} = + rtl, extern: "nos$1", tags: [ReadDirEffect].} = ## retrieves file permissions for `filename`. `OSError` is raised in case of ## an error. On Windows, only the ``readonly`` flag is checked, every other ## permission is available in any case. when defined(posix): var a: TStat - if stat(filename, a) < 0'i32: osError(osLastError()) + if stat(filename, a) < 0'i32: raiseOSError(osLastError()) result = {} if (a.st_mode and S_IRUSR) != 0'i32: result.incl(fpUserRead) if (a.st_mode and S_IWUSR) != 0'i32: result.incl(fpUserWrite) @@ -907,7 +916,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {. wrapUnary(res, getFileAttributesW, filename) else: var res = getFileAttributesA(filename) - if res == -1'i32: osError(osLastError()) + if res == -1'i32: raiseOSError(osLastError()) if (res and FILE_ATTRIBUTE_READONLY) != 0'i32: result = {fpUserExec, fpUserRead, fpGroupExec, fpGroupRead, fpOthersExec, fpOthersRead} @@ -915,7 +924,7 @@ proc getFilePermissions*(filename: string): set[TFilePermission] {. result = {fpUserExec..fpOthersRead} proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {. - rtl, extern: "nos$1", tags: [FWriteDir].} = + rtl, extern: "nos$1", tags: [WriteDirEffect].} = ## sets the file permissions for `filename`. `OSError` is raised in case of ## an error. On Windows, only the ``readonly`` flag is changed, depending on ## ``fpUserWrite``. @@ -933,13 +942,13 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {. if fpOthersWrite in permissions: p = p or S_IWOTH if fpOthersExec in permissions: p = p or S_IXOTH - if chmod(filename, p) != 0: osError(osLastError()) + if chmod(filename, p) != 0: raiseOSError(osLastError()) else: when useWinUnicode: wrapUnary(res, getFileAttributesW, filename) else: var res = getFileAttributesA(filename) - if res == -1'i32: osError(osLastError()) + if res == -1'i32: raiseOSError(osLastError()) if fpUserWrite in permissions: res = res and not FILE_ATTRIBUTE_READONLY else: @@ -948,10 +957,10 @@ proc setFilePermissions*(filename: string, permissions: set[TFilePermission]) {. wrapBinary(res2, setFileAttributesW, filename, res) else: var res2 = setFileAttributesA(filename, res) - if res2 == - 1'i32: osError(osLastError()) + if res2 == - 1'i32: raiseOSError(osLastError()) proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", - tags: [FReadIO, FWriteIO].} = + tags: [ReadIOEffect, WriteIOEffect].} = ## Copies a file from `source` to `dest`. ## ## If this fails, `EOS` is raised. On the Windows platform this proc will @@ -966,17 +975,17 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", when useWinUnicode: let s = newWideCString(source) let d = newWideCString(dest) - if copyFileW(s, d, 0'i32) == 0'i32: osError(osLastError()) + if copyFileW(s, d, 0'i32) == 0'i32: raiseOSError(osLastError()) else: - if copyFileA(source, dest, 0'i32) == 0'i32: osError(osLastError()) + if copyFileA(source, dest, 0'i32) == 0'i32: raiseOSError(osLastError()) else: # generic version of copyFile which works for any platform: const bufSize = 8000 # better for memory manager - var d, s: TFile - if not open(s, source): osError(osLastError()) + var d, s: File + if not open(s, source): raiseOSError(osLastError()) if not open(d, dest, fmWrite): close(s) - osError(osLastError()) + raiseOSError(osLastError()) var buf = alloc(bufSize) while true: var bytesread = readBuffer(s, buf, bufSize) @@ -986,17 +995,17 @@ proc copyFile*(source, dest: string) {.rtl, extern: "nos$1", dealloc(buf) close(s) close(d) - osError(osLastError()) + raiseOSError(osLastError()) if bytesread != bufSize: break dealloc(buf) close(s) close(d) proc moveFile*(source, dest: string) {.rtl, extern: "nos$1", - tags: [FReadIO, FWriteIO].} = + tags: [ReadIOEffect, WriteIOEffect].} = ## Moves a file from `source` to `dest`. If this fails, `EOS` is raised. if c_rename(source, dest) != 0'i32: - raise newException(EOS, $strerror(errno)) + raise newException(OSError, $strerror(errno)) when not declared(ENOENT) and not defined(Windows): when NoFakeVars: @@ -1014,7 +1023,7 @@ when defined(Windows): template setFileAttributes(file, attrs: expr): expr {.immediate.} = setFileAttributesA(file, attrs) -proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} = +proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} = ## Removes the `file`. If this fails, `EOS` is raised. This does not fail ## if the file never existed in the first place. ## On Windows, ignores the read-only attribute. @@ -1026,15 +1035,15 @@ proc removeFile*(file: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} = if deleteFile(f) == 0: if getLastError() == ERROR_ACCESS_DENIED: if setFileAttributes(f, FILE_ATTRIBUTE_NORMAL) == 0: - osError(osLastError()) + raiseOSError(osLastError()) if deleteFile(f) == 0: - osError(osLastError()) + raiseOSError(osLastError()) else: if c_remove(file) != 0'i32 and errno != ENOENT: - raise newException(EOS, $strerror(errno)) + raise newException(OSError, $strerror(errno)) proc execShellCmd*(command: string): int {.rtl, extern: "nos$1", - tags: [FExecIO].} = + tags: [ExecIOEffect].} = ## Executes a `shell command`:idx:. ## ## Command has the form 'program args' where args are the command @@ -1076,7 +1085,7 @@ when defined(windows): while true: var eend = strEnd(e) add(environment, $e) - e = cast[WideCString](cast[TAddress](eend)+2) + e = cast[WideCString](cast[ByteAddress](eend)+2) if eend[1].int == 0: break discard freeEnvironmentStringsW(env) else: @@ -1087,7 +1096,7 @@ when defined(windows): while true: var eend = strEnd(e) add(environment, $e) - e = cast[cstring](cast[TAddress](eend)+1) + e = cast[cstring](cast[ByteAddress](eend)+1) if eend[1] == '\0': break discard freeEnvironmentStringsA(env) envComputed = true @@ -1130,7 +1139,7 @@ proc findEnvVar(key: string): int = if startsWith(environment[i], temp): return i return -1 -proc getEnv*(key: string): TaintedString {.tags: [FReadEnv].} = +proc getEnv*(key: string): TaintedString {.tags: [ReadEnvEffect].} = ## Returns the value of the `environment variable`:idx: named `key`. ## ## If the variable does not exist, "" is returned. To distinguish @@ -1144,13 +1153,13 @@ proc getEnv*(key: string): TaintedString {.tags: [FReadEnv].} = if env == nil: return TaintedString("") result = TaintedString($env) -proc existsEnv*(key: string): bool {.tags: [FReadEnv].} = +proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = ## Checks whether the environment variable named `key` exists. ## Returns true if it exists, false otherwise. if c_getenv(key) != nil: return true else: return findEnvVar(key) >= 0 -proc putEnv*(key, val: string) {.tags: [FWriteEnv].} = +proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} = ## Sets the value of the `environment variable`:idx: named `key` to `val`. ## If an error occurs, `EInvalidEnvVar` is raised. @@ -1166,16 +1175,16 @@ proc putEnv*(key, val: string) {.tags: [FWriteEnv].} = indx = high(environment) when defined(unix): if c_putenv(environment[indx]) != 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) else: when useWinUnicode: var k = newWideCString(key) var v = newWideCString(val) - if setEnvironmentVariableW(k, v) == 0'i32: osError(osLastError()) + if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError()) else: - if setEnvironmentVariableA(key, val) == 0'i32: osError(osLastError()) + if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError()) -iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} = +iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = ## Iterate over all `environments variables`:idx:. In the first component ## of the tuple is the name of the current variable stored, in the second ## its value. @@ -1185,7 +1194,7 @@ iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [FReadEnv].} = yield (TaintedString(substr(environment[i], 0, p-1)), TaintedString(substr(environment[i], p+1))) -iterator walkFiles*(pattern: string): string {.tags: [FReadDir].} = +iterator walkFiles*(pattern: string): string {.tags: [ReadDirEffect].} = ## Iterate over all the files that match the `pattern`. On POSIX this uses ## the `glob`:idx: call. ## @@ -1225,7 +1234,7 @@ type pcLinkToDir ## path refers to a symbolic link to a directory iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {. - tags: [FReadDir].} = + tags: [ReadDirEffect].} = ## walks over the directory `dir` and yields for each directory or file in ## `dir`. The component type and full path for each item is returned. ## Walking is not recursive. @@ -1237,7 +1246,7 @@ iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {. ## ## and this code: ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## for kind, path in walkDir("dirA"): ## echo(path) ## @@ -1278,7 +1287,7 @@ iterator walkDir*(dir: string): tuple[kind: TPathComponent, path: string] {. discard closedir(d) iterator walkDirRec*(dir: string, filter={pcFile, pcDir}): string {. - tags: [FReadDir].} = + tags: [ReadDirEffect].} = ## walks over the directory `dir` and yields for each file in `dir`. The ## full path for each file is returned. ## **Warning**: @@ -1313,12 +1322,12 @@ proc rawRemoveDir(dir: string) = let lastError = osLastError() if res == 0'i32 and lastError.int32 != 3'i32 and lastError.int32 != 18'i32 and lastError.int32 != 2'i32: - osError(lastError) + raiseOSError(lastError) else: - if rmdir(dir) != 0'i32 and errno != ENOENT: osError(osLastError()) + if rmdir(dir) != 0'i32 and errno != ENOENT: raiseOSError(osLastError()) proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ - FWriteDir, FReadDir].} = + WriteDirEffect, ReadDirEffect].} = ## Removes the directory `dir` including all subdirectories and files ## in `dir` (recursively). ## @@ -1333,19 +1342,19 @@ proc removeDir*(dir: string) {.rtl, extern: "nos$1", tags: [ proc rawCreateDir(dir: string) = when defined(solaris): if mkdir(dir, 0o777) != 0'i32 and errno != EEXIST and errno != ENOSYS: - osError(osLastError()) + raiseOSError(osLastError()) elif defined(unix): if mkdir(dir, 0o777) != 0'i32 and errno != EEXIST: - osError(osLastError()) + raiseOSError(osLastError()) else: when useWinUnicode: wrapUnary(res, createDirectoryW, dir) else: var res = createDirectoryA(dir) if res == 0'i32 and getLastError() != 183'i32: - osError(osLastError()) + raiseOSError(osLastError()) -proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} = +proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [WriteDirEffect].} = ## Creates the `directory`:idx: `dir`. ## ## The directory may contain several subdirectories that do not exist yet. @@ -1364,7 +1373,7 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1", tags: [FWriteDir].} = rawCreateDir(dir) proc copyDir*(source, dest: string) {.rtl, extern: "nos$1", - tags: [FWriteIO, FReadIO].} = + tags: [WriteIOEffect, ReadIOEffect].} = ## Copies a directory from `source` to `dest`. ## ## If this fails, `EOS` is raised. On the Windows platform this proc will @@ -1395,13 +1404,13 @@ proc createSymlink*(src, dest: string) = var wSrc = newWideCString(src) var wDst = newWideCString(dest) if createSymbolicLinkW(wDst, wSrc, flag) == 0 or getLastError() != 0: - osError(osLastError()) + raiseOSError(osLastError()) else: if createSymbolicLinkA(dest, src, flag) == 0 or getLastError() != 0: - osError(osLastError()) + raiseOSError(osLastError()) else: if symlink(src, dest) != 0: - osError(osLastError()) + raiseOSError(osLastError()) proc createHardlink*(src, dest: string) = ## Create a hard link at `dest` which points to the item specified @@ -1414,13 +1423,13 @@ proc createHardlink*(src, dest: string) = var wSrc = newWideCString(src) var wDst = newWideCString(dest) if createHardLinkW(wDst, wSrc, nil) == 0: - osError(osLastError()) + raiseOSError(osLastError()) else: if createHardLinkA(dest, src, nil) == 0: - osError(osLastError()) + raiseOSError(osLastError()) else: if link(src, dest) != 0: - osError(osLastError()) + raiseOSError(osLastError()) proc parseCmdLine*(c: string): seq[string] {. noSideEffect, rtl, extern: "nos$1".} = @@ -1537,7 +1546,7 @@ proc copyFileWithPermissions*(source, dest: string, proc copyDirWithPermissions*(source, dest: string, ignorePermissionErrors = true) {.rtl, extern: "nos$1", - tags: [FWriteIO, FReadIO].} = + tags: [WriteIOEffect, ReadIOEffect].} = ## Copies a directory from `source` to `dest` preserving file permissions. ## ## If this fails, `EOS` is raised. This is a wrapper proc around `copyDir() @@ -1568,23 +1577,23 @@ proc copyDirWithPermissions*(source, dest: string, proc inclFilePermissions*(filename: string, permissions: set[TFilePermission]) {. - rtl, extern: "nos$1", tags: [FReadDir, FWriteDir].} = + rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} = ## a convenience procedure for: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## setFilePermissions(filename, getFilePermissions(filename)+permissions) setFilePermissions(filename, getFilePermissions(filename)+permissions) proc exclFilePermissions*(filename: string, permissions: set[TFilePermission]) {. - rtl, extern: "nos$1", tags: [FReadDir, FWriteDir].} = + rtl, extern: "nos$1", tags: [ReadDirEffect, WriteDirEffect].} = ## a convenience procedure for: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## setFilePermissions(filename, getFilePermissions(filename)-permissions) setFilePermissions(filename, getFilePermissions(filename)-permissions) -proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} = +proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} = ## Returns the home directory of the current user. ## ## This proc is wrapped by the expandTilde proc for the convenience of @@ -1592,12 +1601,12 @@ proc getHomeDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} = when defined(windows): return string(getEnv("USERPROFILE")) & "\\" else: return string(getEnv("HOME")) & "/" -proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} = +proc getConfigDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} = ## Returns the config directory of the current user for applications. when defined(windows): return string(getEnv("APPDATA")) & "\\" else: return string(getEnv("HOME")) & "/.config/" -proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} = +proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [ReadEnvEffect].} = ## Returns the temporary directory of the current user for applications to ## save temporary files in. when defined(windows): return string(getEnv("TEMP")) & "\\" @@ -1605,7 +1614,7 @@ proc getTempDir*(): string {.rtl, extern: "nos$1", tags: [FReadEnv].} = when defined(nimdoc): # Common forward declaration docstring block for parameter retrieval procs. - proc paramCount*(): int {.tags: [FReadIO].} = + proc paramCount*(): int {.tags: [ReadIOEffect].} = ## Returns the number of `command line arguments`:idx: given to the ## application. ## @@ -1619,13 +1628,13 @@ when defined(nimdoc): ## can test for its availability with `declared() <system.html#declared>`_. ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## when declared(paramCount): ## # Use paramCount() here ## else: ## # Do something else! - proc paramStr*(i: int): TaintedString {.tags: [FReadIO].} = + proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = ## Returns the `i`-th `command line argument`:idx: given to the application. ## ## `i` should be in the range `1..paramCount()`, the `EInvalidIndex` @@ -1642,14 +1651,14 @@ when defined(nimdoc): ## can test for its availability with `declared() <system.html#declared>`_. ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## when declared(paramStr): ## # Use paramStr() here ## else: ## # Do something else! elif defined(windows): - # Since we support GUI applications with Nimrod, we sometimes generate + # Since we support GUI applications with Nim, we sometimes generate # a WinMain entry proc. But a WinMain proc has no access to the parsed # command line arguments. The way to get them differs. Thus we parse them # ourselves. This has the additional benefit that the program's behaviour @@ -1657,13 +1666,13 @@ elif defined(windows): var ownArgv {.threadvar.}: seq[string] - proc paramCount*(): int {.rtl, extern: "nos$1", tags: [FReadIO].} = + proc paramCount*(): int {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = # Docstring in nimdoc block. if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine()) result = ownArgv.len-1 proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1", - tags: [FReadIO].} = + tags: [ReadIOEffect].} = # Docstring in nimdoc block. if isNil(ownArgv): ownArgv = parseCmdLine($getCommandLine()) return TaintedString(ownArgv[i]) @@ -1674,12 +1683,12 @@ elif not defined(createNimRtl): cmdCount {.importc: "cmdCount".}: cint cmdLine {.importc: "cmdLine".}: cstringArray - proc paramStr*(i: int): TaintedString {.tags: [FReadIO].} = + proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = # Docstring in nimdoc block. if i < cmdCount and i >= 0: return TaintedString($cmdLine[i]) - raise newException(EInvalidIndex, "invalid index") + raise newException(IndexError, "invalid index") - proc paramCount*(): int {.tags: [FReadIO].} = + proc paramCount*(): int {.tags: [ReadIOEffect].} = # Docstring in nimdoc block. result = cmdCount-1 @@ -1695,7 +1704,7 @@ when declared(paramCount) or defined(nimdoc): ## can test for its availability with `declared() <system.html#declared>`_. ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## when declared(commandLineParams): ## # Use commandLineParams() here ## else: @@ -1739,7 +1748,7 @@ when defined(macosx): proc getExecPath2(c: cstring, size: var cuint32): bool {. importc: "_NSGetExecutablePath", header: "<mach-o/dyld.h>".} -proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} = +proc getAppFilename*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = ## Returns the filename of the application's executable. ## ## This procedure will resolve symlinks. @@ -1795,38 +1804,38 @@ proc getApplicationDir*(): string {.rtl, extern: "nos$1", deprecated.} = ## instead. result = splitFile(getAppFilename()).dir -proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [FReadIO].} = +proc getAppDir*(): string {.rtl, extern: "nos$1", tags: [ReadIOEffect].} = ## Returns the directory of the application's executable. ## **Note**: This does not work reliably on BSD. result = splitFile(getAppFilename()).dir -proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [FTime].} = +proc sleep*(milsecs: int) {.rtl, extern: "nos$1", tags: [TimeEffect].} = ## sleeps `milsecs` milliseconds. when defined(windows): winlean.sleep(int32(milsecs)) else: var a, b: Ttimespec - a.tv_sec = TTime(milsecs div 1000) + a.tv_sec = Time(milsecs div 1000) a.tv_nsec = (milsecs mod 1000) * 1000 * 1000 discard posix.nanosleep(a, b) proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1", - tags: [FReadIO].} = + tags: [ReadIOEffect].} = ## returns the file size of `file`. Can raise ``EOS``. when defined(windows): var a: TWIN32_FIND_DATA var resA = findFirstFile(file, a) - if resA == -1: osError(osLastError()) + if resA == -1: raiseOSError(osLastError()) result = rdFileSize(a) findClose(resA) else: - var f: TFile + var f: File if open(f, file): result = getFileSize(f) close(f) - else: osError(osLastError()) + else: raiseOSError(osLastError()) -proc findExe*(exe: string): string {.tags: [FReadDir, FReadEnv].} = +proc findExe*(exe: string): string {.tags: [ReadDirEffect, ReadEnvEffect].} = ## Searches for `exe` in the current working directory and then ## in directories listed in the ``PATH`` environment variable. ## Returns "" if the `exe` cannot be found. On DOS-like platforms, `exe` @@ -1850,11 +1859,10 @@ proc expandTilde*(path: string): string = ## The behaviour of this proc is the same on the Windows platform despite not ## having this convention. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## let configFile = expandTilde("~" / "appname.cfg") ## echo configFile ## # --> C:\Users\amber\appname.cfg - if len(path) > 1 and path[0] == '~' and (path[1] == '/' or path[1] == '\\'): result = getHomeDir() / path[2..len(path)-1] else: @@ -1867,7 +1875,7 @@ when defined(Windows): else: type DeviceId* = TDev - FileId* = TIno + FileId* = Tino type FileInfo* = object @@ -1877,12 +1885,12 @@ type size*: BiggestInt # Size of file. permissions*: set[TFilePermission] # File permissions linkCount*: BiggestInt # Number of hard links the file object has. - lastAccessTime*: TTime # Time file was last accessed. - lastWriteTime*: TTime # Time file was last modified/written to. - creationTime*: TTime # Time file was created. Not supported on all systems! + lastAccessTime*: Time # Time file was last accessed. + lastWriteTime*: Time # Time file was last modified/written to. + creationTime*: Time # Time file was created. Not supported on all systems! template rawToFormalFileInfo(rawInfo, formalInfo): expr = - ## Transforms the native file info structure into the one nimrod uses. + ## Transforms the native file info structure into the one nim uses. ## 'rawInfo' is either a 'TBY_HANDLE_FILE_INFORMATION' structure on Windows, ## or a 'TStat' structure on posix when defined(Windows): @@ -1939,7 +1947,7 @@ template rawToFormalFileInfo(rawInfo, formalInfo): expr = if S_ISDIR(rawInfo.st_mode): formalInfo.kind = pcDir if S_ISLNK(rawInfo.st_mode): formalInfo.kind.inc() -proc getFileInfo*(handle: TFileHandle): FileInfo = +proc getFileInfo*(handle: FileHandle): FileInfo = ## Retrieves file information for the file object represented by the given ## handle. ## @@ -1952,16 +1960,16 @@ proc getFileInfo*(handle: TFileHandle): FileInfo = # To transform the C file descripter to a native file handle. var realHandle = get_osfhandle(handle) if getFileInformationByHandle(realHandle, addr rawInfo) == 0: - osError(osLastError()) + raiseOSError(osLastError()) rawToFormalFileInfo(rawInfo, result) else: var rawInfo: TStat if fstat(handle, rawInfo) < 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) rawToFormalFileInfo(rawInfo, result) -proc getFileInfo*(file: TFile): FileInfo = - result = getFileInfo(file.fileHandle()) +proc getFileInfo*(file: File): FileInfo = + result = getFileInfo(file.getFileHandle()) proc getFileInfo*(path: string, followSymlink = true): FileInfo = ## Retrieves file information for the file object pointed to by `path`. @@ -1982,19 +1990,19 @@ proc getFileInfo*(path: string, followSymlink = true): FileInfo = handle = openHandle(path, followSymlink) rawInfo: TBY_HANDLE_FILE_INFORMATION if handle == INVALID_HANDLE_VALUE: - osError(osLastError()) + raiseOSError(osLastError()) if getFileInformationByHandle(handle, addr rawInfo) == 0: - osError(osLastError()) + raiseOSError(osLastError()) rawToFormalFileInfo(rawInfo, result) discard closeHandle(handle) else: var rawInfo: TStat if followSymlink: if lstat(path, rawInfo) < 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) else: if stat(path, rawInfo) < 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) rawToFormalFileInfo(rawInfo, result) proc isHidden*(path: string): bool = @@ -2006,7 +2014,10 @@ proc isHidden*(path: string): bool = ## On Unix-like systems, a file is hidden if it starts with a '.' (period) ## and is not *just* '.' or '..' ' ." when defined(Windows): - wrapUnary(attributes, getFileAttributesW, path) + when useWinUnicode: + wrapUnary(attributes, getFileAttributesW, path) + else: + var attributes = getFileAttributesA(path) if attributes != -1'i32: result = (attributes and FILE_ATTRIBUTE_HIDDEN) != 0'i32 else: diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index 3c181bf53..f47df73ca 100644 --- a/lib/pure/osproc.nim +++ b/lib/pure/osproc.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -24,20 +24,20 @@ when defined(linux): import linux type - TProcess = object of TObject + ProcessObj = object of RootObj when defined(windows): fProcessHandle: THandle - inHandle, outHandle, errHandle: TFileHandle + inHandle, outHandle, errHandle: FileHandle id: THandle else: - inHandle, outHandle, errHandle: TFileHandle - inStream, outStream, errStream: PStream + inHandle, outHandle, errHandle: FileHandle + inStream, outStream, errStream: Stream id: TPid exitCode: cint - PProcess* = ref TProcess ## represents an operating system process + Process* = ref ProcessObj ## represents an operating system process - TProcessOption* = enum ## options that can be passed `startProcess` + ProcessOption* = enum ## options that can be passed `startProcess` poEchoCmd, ## echo the command before execution poUsePath, ## Asks system to search for executable using PATH environment ## variable. @@ -47,6 +47,9 @@ type poStdErrToStdOut, ## merge stdout and stderr to the stdout stream poParentStreams ## use the parent's streams +{.deprecated: [TProcess: ProcessObj, PProcess: Process, + TProcessOption: ProcessOption].} + const poUseShell* {.deprecated.} = poUsePath ## Deprecated alias for poUsePath. @@ -103,19 +106,19 @@ proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} = {.error:"quoteShell is not supported on your system".} proc execProcess*(command: string, - args: openarray[string] = [], - env: PStringTable = nil, - options: set[TProcessOption] = {poStdErrToStdOut, + args: openArray[string] = [], + env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): TaintedString {. rtl, extern: "nosp$1", - tags: [FExecIO, FReadIO].} + tags: [ExecIOEffect, ReadIOEffect].} ## A convenience procedure that executes ``command`` with ``startProcess`` ## and returns its output as a string. ## WARNING: this function uses poEvalCommand by default for backward compatibility. ## Make sure to pass options explicitly. -proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [FExecIO].} +proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [ExecIOEffect].} ## Executes ``command`` and returns its error code. Standard input, output, ## error streams are inherited from the calling process. This operation ## is also often called `system`:idx:. @@ -123,9 +126,9 @@ proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [FExecIO].} proc startProcess*(command: string, workingDir: string = "", args: openArray[string] = [], - env: PStringTable = nil, - options: set[TProcessOption] = {poStdErrToStdOut}): - PProcess {.rtl, extern: "nosp$1", tags: [FExecIO, FReadEnv].} + env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut}): + Process {.rtl, extern: "nosp$1", tags: [ExecIOEffect, ReadEnvEffect].} ## Starts a process. `Command` is the executable file, `workingDir` is the ## process's working directory. If ``workingDir == ""`` the current directory ## is used. `args` are the command line arguments that are passed to the @@ -148,60 +151,60 @@ proc startProcess*(command: string, ## Return value: The newly created process object. Nil is never returned, ## but ``EOS`` is raised in case of an error. -proc startCmd*(command: string, options: set[TProcessOption] = { - poStdErrToStdOut, poUsePath}): PProcess {. - tags: [FExecIO, FReadEnv], deprecated.} = +proc startCmd*(command: string, options: set[ProcessOption] = { + poStdErrToStdOut, poUsePath}): Process {. + tags: [ExecIOEffect, ReadEnvEffect], deprecated.} = ## Deprecated - use `startProcess` directly. result = startProcess(command=command, options=options + {poEvalCommand}) -proc close*(p: PProcess) {.rtl, extern: "nosp$1", tags: [].} +proc close*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## When the process has finished executing, cleanup related handles -proc suspend*(p: PProcess) {.rtl, extern: "nosp$1", tags: [].} +proc suspend*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## Suspends the process `p`. -proc resume*(p: PProcess) {.rtl, extern: "nosp$1", tags: [].} +proc resume*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## Resumes the process `p`. -proc terminate*(p: PProcess) {.rtl, extern: "nosp$1", tags: [].} +proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].} ## Terminates the process `p`. -proc running*(p: PProcess): bool {.rtl, extern: "nosp$1", tags: [].} +proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].} ## Returns true iff the process `p` is still running. Returns immediately. -proc processID*(p: PProcess): int {.rtl, extern: "nosp$1".} = +proc processID*(p: Process): int {.rtl, extern: "nosp$1".} = ## returns `p`'s process ID. return p.id -proc waitForExit*(p: PProcess, timeout: int = -1): int {.rtl, +proc waitForExit*(p: Process, timeout: int = -1): int {.rtl, extern: "nosp$1", tags: [].} ## waits for the process to finish and returns `p`'s error code. ## ## **Warning**: Be careful when using waitForExit for processes created without ## poParentStreams because they may fill output buffers, causing deadlock. -proc peekExitCode*(p: PProcess): int {.tags: [].} +proc peekExitCode*(p: Process): int {.tags: [].} ## return -1 if the process is still running. Otherwise the process' exit code -proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].} +proc inputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s input stream for writing to. ## ## **Warning**: The returned `PStream` should not be closed manually as it ## is closed when closing the PProcess ``p``. -proc outputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].} +proc outputStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s output stream for reading from. ## ## **Warning**: The returned `PStream` should not be closed manually as it ## is closed when closing the PProcess ``p``. -proc errorStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].} +proc errorStream*(p: Process): Stream {.rtl, extern: "nosp$1", tags: [].} ## returns ``p``'s error stream for reading from. ## ## **Warning**: The returned `PStream` should not be closed manually as it ## is closed when closing the PProcess ``p``. -proc inputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1", +proc inputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## returns ``p``'s input file handle for writing to. ## @@ -209,7 +212,7 @@ proc inputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1", ## it is closed when closing the PProcess ``p``. result = p.inHandle -proc outputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1", +proc outputHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## returns ``p``'s output file handle for reading from. ## @@ -217,7 +220,7 @@ proc outputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1", ## it is closed when closing the PProcess ``p``. result = p.outHandle -proc errorHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1", +proc errorHandle*(p: Process): FileHandle {.rtl, extern: "nosp$1", tags: [].} = ## returns ``p``'s error file handle for reading from. ## @@ -233,7 +236,7 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} = proc execProcesses*(cmds: openArray[string], options = {poStdErrToStdOut, poParentStreams}, n = countProcessors()): int {.rtl, extern: "nosp$1", - tags: [FExecIO, FTime, FReadEnv]} = + tags: [ExecIOEffect, TimeEffect, ReadEnvEffect]} = ## executes the commands `cmds` in parallel. Creates `n` processes ## that execute in parallel. The highest return value of all processes ## is returned. @@ -243,7 +246,7 @@ proc execProcesses*(cmds: openArray[string], assert n > 0 if n > 1: - var q: seq[PProcess] + var q: seq[Process] newSeq(q, n) var m = min(n, cmds.len) for i in 0..m-1: @@ -283,8 +286,8 @@ proc execProcesses*(cmds: openArray[string], result = max(waitForExit(p), result) close(p) -proc select*(readfds: var seq[PProcess], timeout = 500): int - ## `select` with a sensible Nimrod interface. `timeout` is in miliseconds. +proc select*(readfds: var seq[Process], timeout = 500): int + ## `select` with a sensible Nim interface. `timeout` is in miliseconds. ## Specify -1 for no timeout. Returns the number of processes that are ## ready to read from. The processes that are ready to be read from are ## removed from `readfds`. @@ -294,9 +297,9 @@ proc select*(readfds: var seq[PProcess], timeout = 500): int when not defined(useNimRtl): proc execProcess(command: string, - args: openarray[string] = [], - env: PStringTable = nil, - options: set[TProcessOption] = {poStdErrToStdOut, + args: openArray[string] = [], + env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): TaintedString = var p = startProcess(command, args=args, env=env, options=options) @@ -316,30 +319,31 @@ when defined(Windows) and not defined(useNimRtl): # We need to implement a handle stream for Windows: type PFileHandleStream = ref TFileHandleStream - TFileHandleStream = object of TStream + TFileHandleStream = object of StreamObj handle: THandle atTheEnd: bool - proc hsClose(s: PStream) = discard # nothing to do here - proc hsAtEnd(s: PStream): bool = return PFileHandleStream(s).atTheEnd + proc hsClose(s: Stream) = discard # nothing to do here + proc hsAtEnd(s: Stream): bool = return PFileHandleStream(s).atTheEnd - proc hsReadData(s: PStream, buffer: pointer, bufLen: int): int = + proc hsReadData(s: Stream, buffer: pointer, bufLen: int): int = var s = PFileHandleStream(s) if s.atTheEnd: return 0 var br: int32 - var a = winlean.readFile(s.handle, buffer, bufLen.cint, br, nil) + var a = winlean.readFile(s.handle, buffer, bufLen.cint, addr br, nil) # TRUE and zero bytes returned (EOF). # TRUE and n (>0) bytes returned (good data). # FALSE and bytes returned undefined (system error). - if a == 0 and br != 0: osError(osLastError()) + if a == 0 and br != 0: raiseOSError(osLastError()) s.atTheEnd = br < bufLen result = br - proc hsWriteData(s: PStream, buffer: pointer, bufLen: int) = + proc hsWriteData(s: Stream, buffer: pointer, bufLen: int) = var s = PFileHandleStream(s) var bytesWritten: int32 - var a = winlean.writeFile(s.handle, buffer, bufLen.cint, bytesWritten, nil) - if a == 0: osError(osLastError()) + var a = winlean.writeFile(s.handle, buffer, bufLen.cint, + addr bytesWritten, nil) + if a == 0: raiseOSError(osLastError()) proc newFileHandleStream(handle: THandle): PFileHandleStream = new(result) @@ -357,7 +361,7 @@ when defined(Windows) and not defined(useNimRtl): result = cast[cstring](alloc0(res.len+1)) copyMem(result, cstring(res), res.len) - proc buildEnv(env: PStringTable): cstring = + proc buildEnv(env: StringTableRef): cstring = var L = 0 for key, val in pairs(env): inc(L, key.len + val.len + 2) result = cast[cstring](alloc0(L+2)) @@ -380,7 +384,7 @@ when defined(Windows) and not defined(useNimRtl): piInheritablePipe.lpSecurityDescriptor = nil piInheritablePipe.bInheritHandle = 1 if createPipe(rdHandle, wrHandle, piInheritablePipe, 1024) == 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) proc fileClose(h: THandle) {.inline.} = if h > 4: discard closeHandle(h) @@ -388,8 +392,8 @@ when defined(Windows) and not defined(useNimRtl): proc startProcess(command: string, workingDir: string = "", args: openArray[string] = [], - env: PStringTable = nil, - options: set[TProcessOption] = {poStdErrToStdOut}): PProcess = + env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut}): Process = var si: TSTARTUPINFO procInfo: TPROCESS_INFORMATION @@ -406,16 +410,16 @@ when defined(Windows) and not defined(useNimRtl): he = ho else: createPipeHandles(he, si.hStdError) - result.inHandle = TFileHandle(hi) - result.outHandle = TFileHandle(ho) - result.errHandle = TFileHandle(he) + result.inHandle = FileHandle(hi) + result.outHandle = FileHandle(ho) + result.errHandle = FileHandle(he) else: si.hStdError = getStdHandle(STD_ERROR_HANDLE) si.hStdInput = getStdHandle(STD_INPUT_HANDLE) si.hStdOutput = getStdHandle(STD_OUTPUT_HANDLE) - result.inHandle = TFileHandle(si.hStdInput) - result.outHandle = TFileHandle(si.hStdOutput) - result.errHandle = TFileHandle(si.hStdError) + result.inHandle = FileHandle(si.hStdInput) + result.outHandle = FileHandle(si.hStdOutput) + result.errHandle = FileHandle(si.hStdError) var cmdl: cstring if poEvalCommand in options: @@ -447,13 +451,13 @@ when defined(Windows) and not defined(useNimRtl): fileClose(si.hStdError) if e != nil: dealloc(e) - if success == 0: osError(lastError) + if success == 0: raiseOSError(lastError) # Close the handle now so anyone waiting is woken: discard closeHandle(procInfo.hThread) result.fProcessHandle = procInfo.hProcess result.id = procInfo.dwProcessId - proc close(p: PProcess) = + proc close(p: Process) = when false: # somehow this does not work on Windows: discard closeHandle(p.inHandle) @@ -461,21 +465,21 @@ when defined(Windows) and not defined(useNimRtl): discard closeHandle(p.errHandle) discard closeHandle(p.FProcessHandle) - proc suspend(p: PProcess) = + proc suspend(p: Process) = discard suspendThread(p.fProcessHandle) - proc resume(p: PProcess) = + proc resume(p: Process) = discard resumeThread(p.fProcessHandle) - proc running(p: PProcess): bool = + proc running(p: Process): bool = var x = waitForSingleObject(p.fProcessHandle, 50) return x == WAIT_TIMEOUT - proc terminate(p: PProcess) = + proc terminate(p: Process) = if running(p): discard terminateProcess(p.fProcessHandle, 0) - proc waitForExit(p: PProcess, timeout: int = -1): int = + proc waitForExit(p: Process, timeout: int = -1): int = discard waitForSingleObject(p.fProcessHandle, timeout.int32) var res: int32 @@ -483,7 +487,7 @@ when defined(Windows) and not defined(useNimRtl): result = res discard closeHandle(p.fProcessHandle) - proc peekExitCode(p: PProcess): int = + proc peekExitCode(p: Process): int = var b = waitForSingleObject(p.fProcessHandle, 50) == WAIT_TIMEOUT if b: result = -1 else: @@ -491,13 +495,13 @@ when defined(Windows) and not defined(useNimRtl): discard getExitCodeProcess(p.fProcessHandle, res) return res - proc inputStream(p: PProcess): PStream = + proc inputStream(p: Process): Stream = result = newFileHandleStream(p.inHandle) - proc outputStream(p: PProcess): PStream = + proc outputStream(p: Process): Stream = result = newFileHandleStream(p.outHandle) - proc errorStream(p: PProcess): PStream = + proc errorStream(p: Process): Stream = result = newFileHandleStream(p.errHandle) proc execCmd(command: string): int = @@ -518,7 +522,7 @@ when defined(Windows) and not defined(useNimRtl): var res = winlean.createProcessA(nil, command, nil, nil, 0, NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo) if res == 0: - osError(osLastError()) + raiseOSError(osLastError()) else: process = procInfo.hProcess discard closeHandle(procInfo.hThread) @@ -529,7 +533,7 @@ when defined(Windows) and not defined(useNimRtl): result = -1 discard closeHandle(process) - proc select(readfds: var seq[PProcess], timeout = 500): int = + proc select(readfds: var seq[Process], timeout = 500): int = assert readfds.len <= MAXIMUM_WAIT_OBJECTS var rfds: TWOHandleArray for i in 0..readfds.len()-1: @@ -541,7 +545,7 @@ when defined(Windows) and not defined(useNimRtl): of WAIT_TIMEOUT: return 0 of WAIT_FAILED: - osError(osLastError()) + raiseOSError(osLastError()) else: var i = ret - WAIT_OBJECT_0 readfds.del(i) @@ -552,7 +556,7 @@ elif not defined(useNimRtl): readIdx = 0 writeIdx = 1 - proc envToCStringArray(t: PStringTable): cstringArray = + proc envToCStringArray(t: StringTableRef): cstringArray = result = cast[cstringArray](alloc0((t.len + 1) * sizeof(cstring))) var i = 0 for key, val in pairs(t): @@ -584,19 +588,19 @@ elif not defined(useNimRtl): when not defined(useFork): proc startProcessAuxSpawn(data: TStartProcessData): TPid {. - tags: [FExecIO, FReadEnv], gcsafe.} + tags: [ExecIOEffect, ReadEnvEffect], gcsafe.} proc startProcessAuxFork(data: TStartProcessData): TPid {. - tags: [FExecIO, FReadEnv], gcsafe.} + tags: [ExecIOEffect, ReadEnvEffect], gcsafe.} {.push stacktrace: off, profiler: off.} proc startProcessAfterFork(data: ptr TStartProcessData) {. - tags: [FExecIO, FReadEnv], cdecl, gcsafe.} + tags: [ExecIOEffect, ReadEnvEffect], cdecl, gcsafe.} {.pop.} proc startProcess(command: string, workingDir: string = "", args: openArray[string] = [], - env: PStringTable = nil, - options: set[TProcessOption] = {poStdErrToStdOut}): PProcess = + env: StringTableRef = nil, + options: set[ProcessOption] = {poStdErrToStdOut}): Process = var pStdin, pStdout, pStderr: array [0..1, cint] new(result) @@ -604,7 +608,7 @@ elif not defined(useNimRtl): if poParentStreams notin options: if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or pipe(pStderr) != 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) var sysCommand: string var sysArgsRaw: seq[string] @@ -680,7 +684,7 @@ elif not defined(useNimRtl): var fops: Tposix_spawn_file_actions template chck(e: expr) = - if e != 0'i32: osError(osLastError()) + if e != 0'i32: raiseOSError(osLastError()) chck posix_spawn_file_actions_init(fops) chck posix_spawnattr_init(attr) @@ -723,7 +727,7 @@ elif not defined(useNimRtl): proc startProcessAuxFork(data: TStartProcessData): TPid = if pipe(data.pErrorPipe) != 0: - osError(osLastError()) + raiseOSError(osLastError()) finally: discard close(data.pErrorPipe[readIdx]) @@ -748,12 +752,12 @@ elif not defined(useNimRtl): exitnow(1) discard close(data.pErrorPipe[writeIdx]) - if pid < 0: osError(osLastError()) + if pid < 0: raiseOSError(osLastError()) var error: cint let sizeRead = read(data.pErrorPipe[readIdx], addr error, sizeof(error)) if sizeRead == sizeof(error): - osError($strerror(error)) + raiseOSError($strerror(error)) return pid @@ -768,7 +772,7 @@ elif not defined(useNimRtl): proc startProcessAfterFork(data: ptr TStartProcessData) = # Warning: no GC here! - # Or anything that touches global structures - all called nimrod procs + # Or anything that touches global structures - all called nim procs # must be marked with stackTrace:off. Inspect C code after making changes. if not data.optionPoParentStreams: discard close(data.pStdin[writeIdx]) @@ -806,7 +810,7 @@ elif not defined(useNimRtl): startProcessFail(data) {.pop} - proc close(p: PProcess) = + proc close(p: Process) = if p.inStream != nil: close(p.inStream) if p.outStream != nil: close(p.outStream) if p.errStream != nil: close(p.errStream) @@ -814,24 +818,24 @@ elif not defined(useNimRtl): discard close(p.outHandle) discard close(p.errHandle) - proc suspend(p: PProcess) = - if kill(-p.id, SIGSTOP) != 0'i32: osError(osLastError()) + proc suspend(p: Process) = + if kill(-p.id, SIGSTOP) != 0'i32: raiseOSError(osLastError()) - proc resume(p: PProcess) = - if kill(-p.id, SIGCONT) != 0'i32: osError(osLastError()) + proc resume(p: Process) = + if kill(-p.id, SIGCONT) != 0'i32: raiseOSError(osLastError()) - proc running(p: PProcess): bool = + proc running(p: Process): bool = var ret = waitpid(p.id, p.exitCode, WNOHANG) if ret == 0: return true # Can't establish status. Assume running. result = ret == int(p.id) - proc terminate(p: PProcess) = + proc terminate(p: Process) = if kill(-p.id, SIGTERM) == 0'i32: if p.running(): - if kill(-p.id, SIGKILL) != 0'i32: osError(osLastError()) - else: osError(osLastError()) + if kill(-p.id, SIGKILL) != 0'i32: raiseOSError(osLastError()) + else: raiseOSError(osLastError()) - proc waitForExit(p: PProcess, timeout: int = -1): int = + proc waitForExit(p: Process, timeout: int = -1): int = #if waitPid(p.id, p.exitCode, 0) == int(p.id): # ``waitPid`` fails if the process is not running anymore. But then # ``running`` probably set ``p.exitCode`` for us. Since ``p.exitCode`` is @@ -839,10 +843,10 @@ elif not defined(useNimRtl): if p.exitCode != -3: return p.exitCode if waitpid(p.id, p.exitCode, 0) < 0: p.exitCode = -3 - osError(osLastError()) + raiseOSError(osLastError()) result = int(p.exitCode) shr 8 - proc peekExitCode(p: PProcess): int = + proc peekExitCode(p: Process): int = if p.exitCode != -3: return p.exitCode var ret = waitpid(p.id, p.exitCode, WNOHANG) var b = ret == int(p.id) @@ -850,23 +854,23 @@ elif not defined(useNimRtl): if p.exitCode == -3: result = -1 else: result = p.exitCode.int shr 8 - proc createStream(stream: var PStream, handle: var TFileHandle, - fileMode: TFileMode) = - var f: TFile - if not open(f, handle, fileMode): osError(osLastError()) + proc createStream(stream: var Stream, handle: var FileHandle, + fileMode: FileMode) = + var f: File + if not open(f, handle, fileMode): raiseOSError(osLastError()) stream = newFileStream(f) - proc inputStream(p: PProcess): PStream = + proc inputStream(p: Process): Stream = if p.inStream == nil: createStream(p.inStream, p.inHandle, fmWrite) return p.inStream - proc outputStream(p: PProcess): PStream = + proc outputStream(p: Process): Stream = if p.outStream == nil: createStream(p.outStream, p.outHandle, fmRead) return p.outStream - proc errorStream(p: PProcess): PStream = + proc errorStream(p: Process): Stream = if p.errStream == nil: createStream(p.errStream, p.errHandle, fmRead) return p.errStream @@ -879,13 +883,13 @@ elif not defined(useNimRtl): else: result = csystem(command) - proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) = + proc createFdSet(fd: var TFdSet, s: seq[Process], m: var int) = FD_ZERO(fd) for i in items(s): m = max(m, int(i.outHandle)) - FD_SET(cint(i.outHandle), fd) + fdSet(cint(i.outHandle), fd) - proc pruneProcessSet(s: var seq[PProcess], fd: var TFdSet) = + proc pruneProcessSet(s: var seq[Process], fd: var TFdSet) = var i = 0 var L = s.len while i < L: @@ -896,8 +900,8 @@ elif not defined(useNimRtl): inc(i) setLen(s, L) - proc select(readfds: var seq[PProcess], timeout = 500): int = - var tv: TTimeVal + proc select(readfds: var seq[Process], timeout = 500): int = + var tv: Timeval tv.tv_sec = 0 tv.tv_usec = timeout * 1000 @@ -913,10 +917,10 @@ elif not defined(useNimRtl): pruneProcessSet(readfds, (rd)) -proc execCmdEx*(command: string, options: set[TProcessOption] = { +proc execCmdEx*(command: string, options: set[ProcessOption] = { poStdErrToStdOut, poUsePath}): tuple[ output: TaintedString, - exitCode: int] {.tags: [FExecIO, FReadIO], gcsafe.} = + 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) diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 1d61a967b..bb9d2aed2 100644 --- a/lib/pure/parsecfg.nim +++ b/lib/pure/parsecfg.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ ## parser. The configuration file's syntax is similar to the Windows ``.ini`` ## format, but much more powerful, as it is not a line based parser. String ## literals, raw string literals and triple quoted string literals are supported -## as in the Nimrod programming language. +## as in the Nim programming language. ## This is an example of how a configuration file may look like: ## @@ -20,25 +20,25 @@ ## The file ``examples/parsecfgex.nim`` demonstrates how to use the ## configuration file parser: ## -## .. code-block:: nimrod +## .. code-block:: nim ## :file: examples/parsecfgex.nim -import +import hashes, strutils, lexbase, streams include "system/inclrtl" -type - TCfgEventKind* = enum ## enumeration of all events that may occur when parsing +type + CfgEventKind* = enum ## enumeration of all events that may occur when parsing cfgEof, ## end of file reached 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 - TCfgEvent* = object of TObject ## describes a parsing event - case kind*: TCfgEventKind ## the kind of the event + CfgEvent* = object of RootObj ## describes a parsing event + case kind*: CfgEventKind ## the kind of the event of cfgEof: nil of cfgSectionStart: section*: string ## `section` contains the name of the @@ -53,28 +53,29 @@ type msg*: string ## contains the error message. No exceptions ## are thrown if a parse error occurs. - TTokKind = enum + TokKind = enum tkInvalid, tkEof, tkSymbol, tkEquals, tkColon, tkBracketLe, tkBracketRi, tkDashDash - TToken {.final.} = object # a token - kind: TTokKind # the type of the token + Token = object # a token + kind: TokKind # the type of the token literal: string # the parsed (string) literal - TCfgParser* = object of TBaseLexer ## the parser object. - tok: TToken + CfgParser* = object of BaseLexer ## the parser object. + tok: Token filename: string +{.deprecated: [TCfgEventKind: CfgEventKind, TCfgEvent: CfgEvent, + TTokKind: TokKind, TToken: Token, TCfgParser: CfgParser].} + # implementation const - SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.', - '/', '\\'} + SymChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\x80'..'\xFF', '.', '/', '\\'} -proc rawGetTok(c: var TCfgParser, tok: var TToken) {.gcsafe.} +proc rawGetTok(c: var CfgParser, tok: var Token) {.gcsafe.} -proc open*(c: var TCfgParser, input: PStream, filename: string, - lineOffset = 0) {. - rtl, extern: "npc$1".} = +proc open*(c: var CfgParser, input: Stream, filename: string, + lineOffset = 0) {.rtl, extern: "npc$1".} = ## initializes the parser with an input stream. `Filename` is only used ## for nice error messages. `lineOffset` can be used to influence the line ## number information in the generated error messages. @@ -85,23 +86,23 @@ proc open*(c: var TCfgParser, input: PStream, filename: string, inc(c.lineNumber, lineOffset) rawGetTok(c, c.tok) -proc close*(c: var TCfgParser) {.rtl, extern: "npc$1".} = +proc close*(c: var CfgParser) {.rtl, extern: "npc$1".} = ## closes the parser `c` and its associated input stream. lexbase.close(c) -proc getColumn*(c: TCfgParser): int {.rtl, extern: "npc$1".} = +proc getColumn*(c: CfgParser): int {.rtl, extern: "npc$1".} = ## get the current column the parser has arrived at. result = getColNumber(c, c.bufpos) -proc getLine*(c: TCfgParser): int {.rtl, extern: "npc$1".} = +proc getLine*(c: CfgParser): int {.rtl, extern: "npc$1".} = ## get the current line the parser has arrived at. result = c.lineNumber -proc getFilename*(c: TCfgParser): string {.rtl, extern: "npc$1".} = +proc getFilename*(c: CfgParser): string {.rtl, extern: "npc$1".} = ## get the filename of the file that the parser processes. result = c.filename -proc handleHexChar(c: var TCfgParser, xi: var int) = +proc handleHexChar(c: var CfgParser, xi: var int) = case c.buf[c.bufpos] of '0'..'9': xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) @@ -115,12 +116,12 @@ proc handleHexChar(c: var TCfgParser, xi: var int) = else: discard -proc handleDecChars(c: var TCfgParser, xi: var int) = +proc handleDecChars(c: var CfgParser, xi: var int) = while c.buf[c.bufpos] in {'0'..'9'}: xi = (xi * 10) + (ord(c.buf[c.bufpos]) - ord('0')) inc(c.bufpos) -proc getEscapedChar(c: var TCfgParser, tok: var TToken) = +proc getEscapedChar(c: var CfgParser, tok: var Token) = inc(c.bufpos) # skip '\' case c.buf[c.bufpos] of 'n', 'N': @@ -169,13 +170,13 @@ proc getEscapedChar(c: var TCfgParser, tok: var TToken) = else: tok.kind = tkInvalid else: tok.kind = tkInvalid -proc handleCRLF(c: var TCfgParser, pos: int): int = +proc handleCRLF(c: var CfgParser, pos: int): int = case c.buf[pos] of '\c': result = lexbase.handleCR(c, pos) of '\L': result = lexbase.handleLF(c, pos) else: result = pos -proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) = +proc getString(c: var CfgParser, tok: var Token, rawMode: bool) = var pos = c.bufpos + 1 # skip " var buf = c.buf # put `buf` in a register tok.kind = tkSymbol @@ -221,7 +222,7 @@ proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) = inc(pos) c.bufpos = pos -proc getSymbol(c: var TCfgParser, tok: var TToken) = +proc getSymbol(c: var CfgParser, tok: var Token) = var pos = c.bufpos var buf = c.buf while true: @@ -231,7 +232,7 @@ proc getSymbol(c: var TCfgParser, tok: var TToken) = c.bufpos = pos tok.kind = tkSymbol -proc skip(c: var TCfgParser) = +proc skip(c: var CfgParser) = var pos = c.bufpos var buf = c.buf while true: @@ -247,7 +248,7 @@ proc skip(c: var TCfgParser) = break # EndOfFile also leaves the loop c.bufpos = pos -proc rawGetTok(c: var TCfgParser, tok: var TToken) = +proc rawGetTok(c: var CfgParser, tok: var Token) = tok.kind = tkInvalid setLen(tok.literal, 0) skip(c) @@ -286,19 +287,19 @@ proc rawGetTok(c: var TCfgParser, tok: var TToken) = tok.literal = "[EOF]" else: getSymbol(c, tok) -proc errorStr*(c: TCfgParser, msg: string): string {.rtl, extern: "npc$1".} = +proc errorStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} = ## returns a properly formated error message containing current line and ## column information. result = `%`("$1($2, $3) Error: $4", [c.filename, $getLine(c), $getColumn(c), msg]) -proc warningStr*(c: TCfgParser, msg: string): string {.rtl, extern: "npc$1".} = +proc warningStr*(c: CfgParser, msg: string): string {.rtl, extern: "npc$1".} = ## returns a properly formated warning message containing current line and ## column information. result = `%`("$1($2, $3) Warning: $4", [c.filename, $getLine(c), $getColumn(c), msg]) -proc ignoreMsg*(c: TCfgParser, e: TCfgEvent): string {.rtl, extern: "npc$1".} = +proc ignoreMsg*(c: CfgParser, e: CfgEvent): string {.rtl, extern: "npc$1".} = ## returns a properly formated warning message containing that ## an entry is ignored. case e.kind @@ -309,7 +310,7 @@ proc ignoreMsg*(c: TCfgParser, e: TCfgEvent): string {.rtl, extern: "npc$1".} = of cfgError: result = e.msg of cfgEof: result = "" -proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent = +proc getKeyValPair(c: var CfgParser, kind: CfgEventKind): CfgEvent = if c.tok.kind == tkSymbol: result.kind = kind result.key = c.tok.literal @@ -329,7 +330,7 @@ proc getKeyValPair(c: var TCfgParser, kind: TCfgEventKind): TCfgEvent = result.msg = errorStr(c, "symbol expected, but found: " & c.tok.literal) rawGetTok(c, c.tok) -proc next*(c: var TCfgParser): TCfgEvent {.rtl, extern: "npc$1".} = +proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} = ## retrieves the first/next event. This controls the parser. case c.tok.kind of tkEof: diff --git a/lib/pure/parsecsv.nim b/lib/pure/parsecsv.nim index 4b25babec..f4943ed89 100644 --- a/lib/pure/parsecsv.nim +++ b/lib/pure/parsecsv.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,16 +13,16 @@ ## Example: How to use the parser ## ============================== ## -## .. code-block:: nimrod +## .. code-block:: nim ## import os, parsecsv, streams -## var s = newFileStream(ParamStr(1), fmRead) -## if s == nil: quit("cannot open the file" & ParamStr(1)) -## var x: TCsvParser -## open(x, s, ParamStr(1)) +## var s = newFileStream(paramStr(1), fmRead) +## if s == nil: quit("cannot open the file" & paramStr(1)) +## var x: CsvParser +## open(x, s, paramStr(1)) ## while readRow(x): -## Echo "new row: " +## echo "new row: " ## for val in items(x.row): -## Echo "##", val, "##" +## echo "##", val, "##" ## close(x) ## @@ -30,28 +30,30 @@ import lexbase, streams type - TCsvRow* = seq[string] ## a row in a CSV file - TCsvParser* = object of TBaseLexer ## the parser object. - row*: TCsvRow ## the current row + CsvRow* = seq[string] ## a row in a CSV file + CsvParser* = object of BaseLexer ## the parser object. + row*: CsvRow ## the current row filename: string sep, quote, esc: char skipWhite: bool currRow: int - EInvalidCsv* = object of EIO ## exception that is raised if - ## a parsing error occurs + CsvError* = object of IOError ## exception that is raised if + ## a parsing error occurs + +{.deprecated: [TCsvRow: CsvRow, TCsvParser: CsvParser, EInvalidCsv: CsvError].} proc raiseEInvalidCsv(filename: string, line, col: int, msg: string) {.noreturn.} = - var e: ref EInvalidCsv + var e: ref CsvError new(e) e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg raise e -proc error(my: TCsvParser, pos: int, msg: string) = - raiseEInvalidCsv(my.filename, my.LineNumber, getColNumber(my, pos), msg) +proc error(my: CsvParser, pos: int, msg: string) = + raiseEInvalidCsv(my.filename, my.lineNumber, getColNumber(my, pos), msg) -proc open*(my: var TCsvParser, input: PStream, filename: string, +proc open*(my: var CsvParser, input: Stream, filename: string, separator = ',', quote = '"', escape = '\0', skipInitialSpace = false) = ## initializes the parser with an input stream. `Filename` is only used @@ -75,7 +77,7 @@ proc open*(my: var TCsvParser, input: PStream, filename: string, my.row = @[] my.currRow = 0 -proc parseField(my: var TCsvParser, a: var string) = +proc parseField(my: var CsvParser, a: var string) = var pos = my.bufpos var buf = my.buf if my.skipWhite: @@ -83,7 +85,7 @@ proc parseField(my: var TCsvParser, a: var string) = setLen(a, 0) # reuse memory if buf[pos] == my.quote and my.quote != '\0': inc(pos) - while true: + while true: var c = buf[pos] if c == '\0': my.bufpos = pos # can continue after exception? @@ -121,11 +123,11 @@ proc parseField(my: var TCsvParser, a: var string) = inc(pos) my.bufpos = pos -proc processedRows*(my: var TCsvParser): int = +proc processedRows*(my: var CsvParser): int = ## returns number of the processed rows return my.currRow -proc readRow*(my: var TCsvParser, columns = 0): bool = +proc readRow*(my: var CsvParser, columns = 0): bool = ## reads the next row; if `columns` > 0, it expects the row to have ## exactly this many columns. Returns false if the end of the file ## has been encountered else true. @@ -153,26 +155,26 @@ proc readRow*(my: var TCsvParser, columns = 0): bool = else: error(my, my.bufpos, my.sep & " expected") break - setlen(my.row, col) + setLen(my.row, col) result = col > 0 if result and col != columns and columns > 0: error(my, oldpos+1, $columns & " columns expected, but found " & $col & " columns") inc(my.currRow) -proc close*(my: var TCsvParser) {.inline.} = +proc close*(my: var CsvParser) {.inline.} = ## closes the parser `my` and its associated input stream. lexbase.close(my) when isMainModule: import os - var s = newFileStream(ParamStr(1), fmRead) - if s == nil: quit("cannot open the file" & ParamStr(1)) - var x: TCsvParser - open(x, s, ParamStr(1)) + var s = newFileStream(paramStr(1), fmRead) + if s == nil: quit("cannot open the file" & paramStr(1)) + var x: CsvParser + open(x, s, paramStr(1)) while readRow(x): - Echo "new row: " + echo "new row: " for val in items(x.row): - Echo "##", val, "##" + echo "##", val, "##" close(x) diff --git a/lib/pure/parseopt.nim b/lib/pure/parseopt.nim index f43853fe6..8af6920c1 100644 --- a/lib/pure/parseopt.nim +++ b/lib/pure/parseopt.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# Nim's Runtime Library +# (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This module provides the standard Nimrod command line parser. +## This module provides the standard Nim command line parser. ## It supports one convenience iterator over all command line options and some ## lower-level features. ## @@ -22,26 +22,28 @@ import os, strutils type - TCmdLineKind* = enum ## the detected command line token + CmdLineKind* = enum ## the detected command line token cmdEnd, ## end of command line reached cmdArgument, ## argument detected - cmdLongoption, ## a long option ``--option`` detected + cmdLongOption, ## a long option ``--option`` detected cmdShortOption ## a short option ``-c`` detected - TOptParser* = - object of TObject ## this object implements the command line parser + OptParser* = + object of RootObj ## this object implements the command line parser cmd: string pos: int inShortState: bool - kind*: TCmdLineKind ## the dected command line token + kind*: CmdLineKind ## the dected command line token key*, val*: TaintedString ## key and value pair; ``key`` is the option ## or the argument, ``value`` is not "" if ## the option was given a value +{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].} + when declared(os.paramCount): # we cannot provide this for NimRtl creation on Posix, because we can't # access the command line arguments then! - proc initOptParser*(cmdline = ""): TOptParser = + proc initOptParser*(cmdline = ""): OptParser = ## inits the option parser. If ``cmdline == ""``, the real command line ## (as provided by the ``OS`` module) is taken. result.pos = 0 @@ -57,7 +59,7 @@ when declared(os.paramCount): result.val = TaintedString"" proc parseWord(s: string, i: int, w: var string, - delim: TCharSet = {'\x09', ' ', '\0'}): int = + delim: set[char] = {'\x09', ' ', '\0'}): int = result = i if s[result] == '\"': inc(result) @@ -70,7 +72,7 @@ proc parseWord(s: string, i: int, w: var string, add(w, s[result]) inc(result) -proc handleShortOption(p: var TOptParser) = +proc handleShortOption(p: var OptParser) = var i = p.pos p.kind = cmdShortOption add(p.key.string, p.cmd[i]) @@ -87,8 +89,7 @@ proc handleShortOption(p: var TOptParser) = if p.cmd[i] == '\0': p.inShortState = false p.pos = i -proc next*(p: var TOptParser) {. - rtl, extern: "npo$1".} = +proc next*(p: var OptParser) {.rtl, extern: "npo$1".} = ## parses the first or next option; ``p.kind`` describes what token has been ## parsed. ``p.key`` and ``p.val`` are set accordingly. var i = p.pos @@ -122,18 +123,16 @@ proc next*(p: var TOptParser) {. p.kind = cmdArgument p.pos = parseWord(p.cmd, i, p.key.string) -proc cmdLineRest*(p: TOptParser): TaintedString {. - rtl, extern: "npo$1".} = +proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} = ## retrieves the rest of the command line that has not been parsed yet. result = strip(substr(p.cmd, p.pos, len(p.cmd) - 1)).TaintedString when declared(initOptParser): - - iterator getopt*(): tuple[kind: TCmdLineKind, key, val: TaintedString] = + iterator getopt*(): tuple[kind: CmdLineKind, key, val: TaintedString] = ## This is an convenience iterator for iterating over the command line. ## This uses the TOptParser object. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var ## filename = "" ## for kind, key, val in getopt(): diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim index 7638171d1..5b1f50958 100644 --- a/lib/pure/parseopt2.nim +++ b/lib/pure/parseopt2.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Andreas Rumpf +# Nim's Runtime Library +# (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This module provides the standard Nimrod command line parser. +## This module provides the standard Nim command line parser. ## It supports one convenience iterator over all command line options and some ## lower-level features. ## @@ -25,22 +25,24 @@ import os, strutils type - TCmdLineKind* = enum ## the detected command line token + CmdLineKind* = enum ## the detected command line token cmdEnd, ## end of command line reached cmdArgument, ## argument detected cmdLongOption, ## a long option ``--option`` detected cmdShortOption ## a short option ``-c`` detected - TOptParser* = - object of TObject ## this object implements the command line parser + OptParser* = + object of RootObj ## this object implements the command line parser cmd: seq[string] pos: int remainingShortOptions: string - kind*: TCmdLineKind ## the dected command line token + kind*: CmdLineKind ## the dected command line token key*, val*: TaintedString ## key and value pair; ``key`` is the option ## or the argument, ``value`` is not "" if ## the option was given a value -proc initOptParser*(cmdline: seq[string]): TOptParser {.rtl.} = +{.deprecated: [TCmdLineKind: CmdLineKind, TOptParser: OptParser].} + +proc initOptParser*(cmdline: seq[string]): OptParser {.rtl.} = ## Initalizes option parses with cmdline. cmdline should not contain ## argument 0 - program name. ## If cmdline == nil default to current command line arguments. @@ -54,7 +56,7 @@ proc initOptParser*(cmdline: seq[string]): TOptParser {.rtl.} = result.cmd = @cmdline -proc initOptParser*(cmdline: string): TOptParser {.rtl, deprecated.} = +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. @@ -64,13 +66,13 @@ proc initOptParser*(cmdline: string): TOptParser {.rtl, deprecated.} = return initOptParser(cmdline.split) when not defined(createNimRtl): - proc initOptParser*(): TOptParser = + proc initOptParser*(): OptParser = ## Initializes option parser from current command line arguments. return initOptParser(commandLineParams()) -proc next*(p: var TOptParser) {.rtl, extern: "npo$1".} +proc next*(p: var OptParser) {.rtl, extern: "npo$1".} -proc nextOption(p: var TOptParser, token: string, allowEmpty: bool) = +proc nextOption(p: var OptParser, token: string, allowEmpty: bool) = for splitchar in [':', '=']: if splitchar in token: let pos = token.find(splitchar) @@ -85,7 +87,7 @@ proc nextOption(p: var TOptParser, token: string, allowEmpty: bool) = p.remainingShortOptions = token[0..token.len-1] p.next() -proc next(p: var TOptParser) = +proc next(p: var OptParser) = if p.remainingShortOptions.len != 0: p.kind = cmdShortOption p.key = TaintedString(p.remainingShortOptions[0..0]) @@ -100,10 +102,10 @@ proc next(p: var TOptParser) = let token = p.cmd[p.pos] p.pos += 1 - if token.startswith("--"): + if token.startsWith("--"): p.kind = cmdLongOption nextOption(p, token[2..token.len-1], allowEmpty=true) - elif token.startswith("-"): + elif token.startsWith("-"): p.kind = cmdShortOption nextOption(p, token[1..token.len-1], allowEmpty=true) else: @@ -111,20 +113,22 @@ proc next(p: var TOptParser) = p.key = token p.val = "" -proc cmdLineRest*(p: TOptParser): TaintedString {.rtl, extern: "npo$1", deprecated.} = +proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1", deprecated.} = ## Returns part of command line string that has not been parsed yet. ## Do not use - does not correctly handle whitespace. return p.cmd[p.pos..p.cmd.len-1].join(" ") type - TGetoptResult* = tuple[kind: TCmdLineKind, key, val: TaintedString] + GetoptResult* = tuple[kind: CmdLineKind, key, val: TaintedString] + +{.deprecated: [TGetoptResult: GetoptResult].} when declared(paramCount): - iterator getopt*(): TGetoptResult = + iterator getopt*(): GetoptResult = ## This is an convenience iterator for iterating over the command line. - ## This uses the TOptParser object. Example: + ## This uses the OptParser object. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var ## filename = "" ## for kind, key, val in getopt(): diff --git a/lib/pure/parsesql.nim b/lib/pure/parsesql.nim index bd8836f7c..bb4ede779 100644 --- a/lib/pure/parsesql.nim +++ b/lib/pure/parsesql.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this @@ -10,13 +10,13 @@ ## The ``parsesql`` module implements a high performance SQL file ## parser. It parses PostgreSQL syntax and the SQL ANSI standard. -import +import hashes, strutils, lexbase, streams # ------------------- scanner ------------------------------------------------- type - TTokKind = enum ## enumeration of all SQL tokens + TokKind = enum ## enumeration of all SQL tokens tkInvalid, ## invalid token tkEof, ## end of file reached tkIdentifier, ## abc @@ -38,36 +38,38 @@ type tkBracketRi, ## ']' tkDot ## '.' - TToken {.final.} = object # a token - kind: TTokKind # the type of the token + Token = object # a token + kind: TokKind # the type of the token literal: string # the parsed (string) literal - TSqlLexer* = object of TBaseLexer ## the parser object. + SqlLexer* = object of BaseLexer ## the parser object. filename: string +{.deprecated: [TToken: Token, TSqlLexer: SqlLexer].} + const - tokKindToStr: array[TTokKind, string] = [ + tokKindToStr: array[TokKind, string] = [ "invalid", "[EOF]", "identifier", "quoted identifier", "string constant", "escape string constant", "dollar quoted constant", "bit string constant", "hex string constant", "integer constant", "numeric constant", "operator", ";", ":", ",", "(", ")", "[", "]", "." ] -proc open(L: var TSqlLexer, input: PStream, filename: string) = +proc open(L: var SqlLexer, input: Stream, filename: string) = lexbase.open(L, input) L.filename = filename -proc close(L: var TSqlLexer) = +proc close(L: var SqlLexer) = lexbase.close(L) -proc getColumn(L: TSqlLexer): int = +proc getColumn(L: SqlLexer): int = ## get the current column the parser has arrived at. - result = getColNumber(L, L.bufPos) + result = getColNumber(L, L.bufpos) -proc getLine(L: TSqlLexer): int = - result = L.linenumber +proc getLine(L: SqlLexer): int = + result = L.lineNumber -proc handleHexChar(c: var TSqlLexer, xi: var int) = +proc handleHexChar(c: var SqlLexer, xi: var int) = case c.buf[c.bufpos] of '0'..'9': xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) @@ -81,76 +83,76 @@ proc handleHexChar(c: var TSqlLexer, xi: var int) = else: discard -proc handleOctChar(c: var TSqlLexer, xi: var int) = +proc handleOctChar(c: var SqlLexer, xi: var int) = if c.buf[c.bufpos] in {'0'..'7'}: xi = (xi shl 3) or (ord(c.buf[c.bufpos]) - ord('0')) inc(c.bufpos) -proc getEscapedChar(c: var TSqlLexer, tok: var TToken) = +proc getEscapedChar(c: var SqlLexer, tok: var Token) = inc(c.bufpos) case c.buf[c.bufpos] of 'n', 'N': add(tok.literal, '\L') - Inc(c.bufpos) + inc(c.bufpos) of 'r', 'R', 'c', 'C': add(tok.literal, '\c') - Inc(c.bufpos) + inc(c.bufpos) of 'l', 'L': add(tok.literal, '\L') - Inc(c.bufpos) + inc(c.bufpos) of 'f', 'F': add(tok.literal, '\f') inc(c.bufpos) of 'e', 'E': add(tok.literal, '\e') - Inc(c.bufpos) + inc(c.bufpos) of 'a', 'A': add(tok.literal, '\a') - Inc(c.bufpos) + inc(c.bufpos) of 'b', 'B': add(tok.literal, '\b') - Inc(c.bufpos) + inc(c.bufpos) of 'v', 'V': add(tok.literal, '\v') - Inc(c.bufpos) + inc(c.bufpos) of 't', 'T': add(tok.literal, '\t') - Inc(c.bufpos) + inc(c.bufpos) of '\'', '\"': add(tok.literal, c.buf[c.bufpos]) - Inc(c.bufpos) + inc(c.bufpos) of '\\': add(tok.literal, '\\') - Inc(c.bufpos) + inc(c.bufpos) of 'x', 'X': inc(c.bufpos) var xi = 0 handleHexChar(c, xi) handleHexChar(c, xi) - add(tok.literal, Chr(xi)) + add(tok.literal, chr(xi)) of '0'..'7': var xi = 0 handleOctChar(c, xi) handleOctChar(c, xi) handleOctChar(c, xi) - if (xi <= 255): add(tok.literal, Chr(xi)) + if (xi <= 255): add(tok.literal, chr(xi)) else: tok.kind = tkInvalid else: tok.kind = tkInvalid -proc HandleCRLF(c: var TSqlLexer, pos: int): int = +proc handleCRLF(c: var SqlLexer, pos: int): int = case c.buf[pos] - of '\c': result = lexbase.HandleCR(c, pos) - of '\L': result = lexbase.HandleLF(c, pos) + of '\c': result = lexbase.handleCR(c, pos) + of '\L': result = lexbase.handleLF(c, pos) else: result = pos -proc skip(c: var TSqlLexer) = +proc skip(c: var SqlLexer) = var pos = c.bufpos var buf = c.buf var nested = 0 while true: case buf[pos] of ' ', '\t': - Inc(pos) + inc(pos) of '-': if buf[pos+1] == '-': while not (buf[pos] in {'\c', '\L', lexbase.EndOfFile}): inc(pos) @@ -163,7 +165,7 @@ proc skip(c: var TSqlLexer) = case buf[pos] of '\0': break of '\c', '\L': - pos = HandleCRLF(c, pos) + pos = handleCRLF(c, pos) buf = c.buf of '*': if buf[pos+1] == '/': @@ -181,14 +183,14 @@ proc skip(c: var TSqlLexer) = else: inc(pos) else: break of '\c', '\L': - pos = HandleCRLF(c, pos) + pos = handleCRLF(c, pos) buf = c.buf else: break # EndOfFile also leaves the loop c.bufpos = pos -proc getString(c: var TSqlLexer, tok: var TToken, kind: TTokKind) = - var pos = c.bufPos + 1 +proc getString(c: var SqlLexer, tok: var Token, kind: TokKind) = + var pos = c.bufpos + 1 var buf = c.buf tok.kind = kind block parseLoop: @@ -206,16 +208,16 @@ proc getString(c: var TSqlLexer, tok: var TToken, kind: TTokKind) = tok.kind = tkInvalid break parseLoop elif (ch == '\\') and kind == tkEscapeConstant: - c.bufPos = pos + c.bufpos = pos getEscapedChar(c, tok) - pos = c.bufPos + pos = c.bufpos else: add(tok.literal, ch) - Inc(pos) + inc(pos) c.bufpos = pos - var line = c.linenumber + var line = c.lineNumber skip(c) - if c.linenumber > line: + if c.lineNumber > line: # a new line whitespace has been parsed, so we check if the string # continues after the whitespace: buf = c.buf # may have been reallocated @@ -225,8 +227,8 @@ proc getString(c: var TSqlLexer, tok: var TToken, kind: TTokKind) = else: break parseLoop c.bufpos = pos -proc getDollarString(c: var TSqlLexer, tok: var TToken) = - var pos = c.bufPos + 1 +proc getDollarString(c: var SqlLexer, tok: var Token) = + var pos = c.bufpos + 1 var buf = c.buf tok.kind = tkDollarQuotedConstant var tag = "$" @@ -240,7 +242,7 @@ proc getDollarString(c: var TSqlLexer, tok: var TToken) = while true: case buf[pos] of '\c', '\L': - pos = HandleCRLF(c, pos) + pos = handleCRLF(c, pos) buf = c.buf add(tok.literal, "\L") of '\0': @@ -261,19 +263,19 @@ proc getDollarString(c: var TSqlLexer, tok: var TToken) = inc(pos) c.bufpos = pos -proc getSymbol(c: var TSqlLexer, tok: var TToken) = +proc getSymbol(c: var SqlLexer, tok: var Token) = var pos = c.bufpos var buf = c.buf while true: add(tok.literal, buf[pos]) - Inc(pos) + inc(pos) if buf[pos] notin {'a'..'z','A'..'Z','0'..'9','_','$', '\128'..'\255'}: break c.bufpos = pos tok.kind = tkIdentifier -proc getQuotedIdentifier(c: var TSqlLexer, tok: var TToken) = - var pos = c.bufPos + 1 +proc getQuotedIdentifier(c: var SqlLexer, tok: var Token) = + var pos = c.bufpos + 1 var buf = c.buf tok.kind = tkQuotedIdentifier while true: @@ -290,11 +292,11 @@ proc getQuotedIdentifier(c: var TSqlLexer, tok: var TToken) = break else: add(tok.literal, ch) - Inc(pos) + inc(pos) c.bufpos = pos -proc getBitHexString(c: var TSqlLexer, tok: var TToken, validChars: TCharSet) = - var pos = c.bufPos + 1 +proc getBitHexString(c: var SqlLexer, tok: var Token, validChars: set[char]) = + var pos = c.bufpos + 1 var buf = c.buf block parseLoop: while true: @@ -302,7 +304,7 @@ proc getBitHexString(c: var TSqlLexer, tok: var TToken, validChars: TCharSet) = var ch = buf[pos] if ch in validChars: add(tok.literal, ch) - Inc(pos) + inc(pos) elif ch == '\'': inc(pos) break @@ -310,9 +312,9 @@ proc getBitHexString(c: var TSqlLexer, tok: var TToken, validChars: TCharSet) = tok.kind = tkInvalid break parseLoop c.bufpos = pos - var line = c.linenumber + var line = c.lineNumber skip(c) - if c.linenumber > line: + if c.lineNumber > line: # a new line whitespace has been parsed, so we check if the string # continues after the whitespace: buf = c.buf # may have been reallocated @@ -322,9 +324,9 @@ proc getBitHexString(c: var TSqlLexer, tok: var TToken, validChars: TCharSet) = else: break parseLoop c.bufpos = pos -proc getNumeric(c: var TSqlLexer, tok: var TToken) = +proc getNumeric(c: var SqlLexer, tok: var Token) = tok.kind = tkInteger - var pos = c.bufPos + var pos = c.bufpos var buf = c.buf while buf[pos] in Digits: add(tok.literal, buf[pos]) @@ -353,11 +355,11 @@ proc getNumeric(c: var TSqlLexer, tok: var TToken) = tok.kind = tkInvalid c.bufpos = pos -proc getOperator(c: var TSqlLexer, tok: var TToken) = +proc getOperator(c: var SqlLexer, tok: var Token) = const operators = {'+', '-', '*', '/', '<', '>', '=', '~', '!', '@', '#', '%', '^', '&', '|', '`', '?'} tok.kind = tkOperator - var pos = c.bufPos + var pos = c.bufpos var buf = c.buf var trailingPlusMinus = false while true: @@ -379,14 +381,14 @@ proc getOperator(c: var TSqlLexer, tok: var TToken) = inc(pos) c.bufpos = pos -proc getTok(c: var TSqlLexer, tok: var TToken) = +proc getTok(c: var SqlLexer, tok: var Token) = tok.kind = tkInvalid - setlen(tok.literal, 0) + setLen(tok.literal, 0) skip(c) case c.buf[c.bufpos] of ';': - tok.kind = tkSemiColon - inc(c.bufPos) + tok.kind = tkSemicolon + inc(c.bufpos) add(tok.literal, ';') of ',': tok.kind = tkComma @@ -397,19 +399,19 @@ proc getTok(c: var TSqlLexer, tok: var TToken) = inc(c.bufpos) add(tok.literal, ':') of 'e', 'E': - if c.buf[c.bufPos + 1] == '\'': - Inc(c.bufPos) + if c.buf[c.bufpos + 1] == '\'': + inc(c.bufpos) getString(c, tok, tkEscapeConstant) else: getSymbol(c, tok) of 'b', 'B': - if c.buf[c.bufPos + 1] == '\'': + if c.buf[c.bufpos + 1] == '\'': tok.kind = tkBitStringConstant getBitHexString(c, tok, {'0'..'1'}) else: getSymbol(c, tok) of 'x', 'X': - if c.buf[c.bufPos + 1] == '\'': + if c.buf[c.bufpos + 1] == '\'': tok.kind = tkHexStringConstant getBitHexString(c, tok, {'a'..'f','A'..'F','0'..'9'}) else: @@ -421,18 +423,18 @@ proc getTok(c: var TSqlLexer, tok: var TToken) = add(tok.literal, '[') of ']': tok.kind = tkBracketRi - Inc(c.bufpos) + inc(c.bufpos) add(tok.literal, ']') of '(': tok.kind = tkParLe - Inc(c.bufpos) + inc(c.bufpos) add(tok.literal, '(') of ')': tok.kind = tkParRi - Inc(c.bufpos) + inc(c.bufpos) add(tok.literal, ')') of '.': - if c.buf[c.bufPos + 1] in Digits: + if c.buf[c.bufpos + 1] in Digits: getNumeric(c, tok) else: tok.kind = tkDot @@ -454,7 +456,7 @@ proc getTok(c: var TSqlLexer, tok: var TToken) = add(tok.literal, c.buf[c.bufpos]) inc(c.bufpos) -proc errorStr(L: TSqlLexer, msg: string): string = +proc errorStr(L: SqlLexer, msg: string): string = result = "$1($2, $3) Error: $4" % [L.filename, $getLine(L), $getColumn(L), msg] @@ -465,7 +467,7 @@ proc errorStr(L: TSqlLexer, msg: string): string = # :: left PostgreSQL-style typecast # [ ] left array element selection # - right unary minus -# ^ left exponentiation +# ^ left exponentiation # * / % left multiplication, division, modulo # + - left addition, subtraction # IS IS TRUE, IS FALSE, IS UNKNOWN, IS NULL @@ -483,7 +485,7 @@ proc errorStr(L: TSqlLexer, msg: string): string = # OR left logical disjunction type - TSqlNodeKind* = enum ## kind of SQL abstract syntax tree + SqlNodeKind* = enum ## kind of SQL abstract syntax tree nkNone, nkIdent, nkStringLit, @@ -536,79 +538,82 @@ type nkEnumDef type - EInvalidSql* = object of EInvalidValue ## Invalid SQL encountered - PSqlNode* = ref TSqlNode ## an SQL abstract syntax tree node - TSqlNode* = object ## an SQL abstract syntax tree node - case kind*: TSqlNodeKind ## kind of syntax tree + SqlParseError* = object of ValueError ## Invalid SQL encountered + SqlNode* = ref SqlNodeObj ## an SQL abstract syntax tree node + SqlNodeObj* = object ## an SQL abstract syntax tree node + case kind*: SqlNodeKind ## kind of syntax tree of nkIdent, nkStringLit, nkBitStringLit, nkHexStringLit, nkIntegerLit, nkNumericLit: strVal*: string ## AST leaf: the identifier, numeric literal ## string literal, etc. else: - sons*: seq[PSqlNode] ## the node's children + sons*: seq[SqlNode] ## the node's children + + SqlParser* = object of SqlLexer ## SQL parser object + tok: Token - TSqlParser* = object of TSqlLexer ## SQL parser object - tok: TToken +{.deprecated: [EInvalidSql: SqlParseError, PSqlNode: SqlNode, + TSqlNode: SqlNodeObj, TSqlParser: SqlParser, TSqlNodeKind: SqlNodeKind].} -proc newNode(k: TSqlNodeKind): PSqlNode = +proc newNode(k: SqlNodeKind): SqlNode = new(result) result.kind = k -proc newNode(k: TSqlNodeKind, s: string): PSqlNode = +proc newNode(k: SqlNodeKind, s: string): SqlNode = new(result) result.kind = k result.strVal = s -proc len*(n: PSqlNode): int = +proc len*(n: SqlNode): int = if isNil(n.sons): result = 0 else: result = n.sons.len -proc add*(father, n: PSqlNode) = +proc add*(father, n: SqlNode) = if isNil(father.sons): father.sons = @[] add(father.sons, n) -proc getTok(p: var TSqlParser) = +proc getTok(p: var SqlParser) = getTok(p, p.tok) -proc sqlError(p: TSqlParser, msg: string) = - var e: ref EInvalidSql +proc sqlError(p: SqlParser, msg: string) = + var e: ref SqlParseError new(e) e.msg = errorStr(p, msg) raise e -proc isKeyw(p: TSqlParser, keyw: string): bool = +proc isKeyw(p: SqlParser, keyw: string): bool = result = p.tok.kind == tkIdentifier and cmpIgnoreCase(p.tok.literal, keyw) == 0 -proc isOpr(p: TSqlParser, opr: string): bool = +proc isOpr(p: SqlParser, opr: string): bool = result = p.tok.kind == tkOperator and cmpIgnoreCase(p.tok.literal, opr) == 0 -proc optKeyw(p: var TSqlParser, keyw: string) = +proc optKeyw(p: var SqlParser, keyw: string) = if p.tok.kind == tkIdentifier and cmpIgnoreCase(p.tok.literal, keyw) == 0: getTok(p) -proc expectIdent(p: TSqlParser) = +proc expectIdent(p: SqlParser) = if p.tok.kind != tkIdentifier and p.tok.kind != tkQuotedIdentifier: sqlError(p, "identifier expected") -proc expect(p: TSqlParser, kind: TTokKind) = +proc expect(p: SqlParser, kind: TokKind) = if p.tok.kind != kind: sqlError(p, tokKindToStr[kind] & " expected") -proc eat(p: var TSqlParser, kind: TTokKind) = +proc eat(p: var SqlParser, kind: TokKind) = if p.tok.kind == kind: getTok(p) else: sqlError(p, tokKindToStr[kind] & " expected") -proc eat(p: var TSqlParser, keyw: string) = +proc eat(p: var SqlParser, keyw: string) = if isKeyw(p, keyw): getTok(p) else: sqlError(p, keyw.toUpper() & " expected") -proc parseDataType(p: var TSqlParser): PSqlNode = +proc parseDataType(p: var SqlParser): SqlNode = if isKeyw(p, "enum"): result = newNode(nkEnumDef) getTok(p) @@ -636,7 +641,7 @@ proc parseDataType(p: var TSqlParser): PSqlNode = getTok(p) eat(p, tkParRi) -proc getPrecedence(p: TSqlParser): int = +proc getPrecedence(p: SqlParser): int = if isOpr(p, "*") or isOpr(p, "/") or isOpr(p, "%"): result = 6 elif isOpr(p, "+") or isOpr(p, "-"): @@ -655,9 +660,9 @@ proc getPrecedence(p: TSqlParser): int = else: result = - 1 -proc parseExpr(p: var TSqlParser): PSqlNode +proc parseExpr(p: var SqlParser): SqlNode -proc identOrLiteral(p: var TSqlParser): PSqlNode = +proc identOrLiteral(p: var SqlParser): SqlNode = case p.tok.kind of tkIdentifier, tkQuotedIdentifier: result = newNode(nkIdent, p.tok.literal) @@ -685,7 +690,7 @@ proc identOrLiteral(p: var TSqlParser): PSqlNode = sqlError(p, "expression expected") getTok(p) # we must consume a token here to prevend endless loops! -proc primary(p: var TSqlParser): PSqlNode = +proc primary(p: var SqlParser): SqlNode = if p.tok.kind == tkOperator or isKeyw(p, "not"): result = newNode(nkPrefix) result.add(newNode(nkIdent, p.tok.literal)) @@ -723,9 +728,9 @@ proc primary(p: var TSqlParser): PSqlNode = getTok(p) else: break -proc lowestExprAux(p: var TSqlParser, v: var PSqlNode, limit: int): int = +proc lowestExprAux(p: var SqlParser, v: var SqlNode, limit: int): int = var - v2, node, opNode: PSqlNode + v2, node, opNode: SqlNode v = primary(p) # expand while operators have priorities higher than 'limit' var opPred = getPrecedence(p) result = opPred @@ -740,14 +745,14 @@ proc lowestExprAux(p: var TSqlParser, v: var PSqlNode, limit: int): int = v = node opPred = getPrecedence(p) -proc parseExpr(p: var TSqlParser): PSqlNode = +proc parseExpr(p: var SqlParser): SqlNode = discard lowestExprAux(p, result, - 1) -proc parseTableName(p: var TSqlParser): PSqlNode = +proc parseTableName(p: var SqlParser): SqlNode = expectIdent(p) result = primary(p) -proc parseColumnReference(p: var TSqlParser): PSqlNode = +proc parseColumnReference(p: var SqlParser): SqlNode = result = parseTableName(p) if p.tok.kind == tkParLe: getTok(p) @@ -760,12 +765,12 @@ proc parseColumnReference(p: var TSqlParser): PSqlNode = result.add(parseTableName(p)) eat(p, tkParRi) -proc parseCheck(p: var TSqlParser): PSqlNode = +proc parseCheck(p: var SqlParser): SqlNode = getTok(p) result = newNode(nkCheck) result.add(parseExpr(p)) -proc parseConstraint(p: var TSqlParser): PSqlNode = +proc parseConstraint(p: var SqlParser): SqlNode = getTok(p) result = newNode(nkConstraint) expectIdent(p) @@ -774,7 +779,7 @@ proc parseConstraint(p: var TSqlParser): PSqlNode = eat(p, "check") result.add(parseExpr(p)) -proc parseColumnConstraints(p: var TSqlParser, result: PSqlNode) = +proc parseColumnConstraints(p: var SqlParser, result: SqlNode) = while true: if isKeyw(p, "default"): getTok(p) @@ -806,7 +811,7 @@ proc parseColumnConstraints(p: var TSqlParser, result: PSqlNode) = else: break -proc parseColumnDef(p: var TSqlParser): PSqlNode = +proc parseColumnDef(p: var SqlParser): SqlNode = expectIdent(p) result = newNode(nkColumnDef) result.add(newNode(nkIdent, p.tok.literal)) @@ -814,7 +819,7 @@ proc parseColumnDef(p: var TSqlParser): PSqlNode = result.add(parseDataType(p)) parseColumnConstraints(p, result) -proc parseIfNotExists(p: var TSqlParser, k: TSqlNodeKind): PSqlNode = +proc parseIfNotExists(p: var SqlParser, k: SqlNodeKind): SqlNode = getTok(p) if isKeyw(p, "if"): getTok(p) @@ -824,7 +829,7 @@ proc parseIfNotExists(p: var TSqlParser, k: TSqlNodeKind): PSqlNode = else: result = newNode(k) -proc parseParIdentList(p: var TSqlParser, father: PSqlNode) = +proc parseParIdentList(p: var SqlParser, father: SqlNode) = eat(p, tkParLe) while true: expectIdent(p) @@ -834,7 +839,7 @@ proc parseParIdentList(p: var TSqlParser, father: PSqlNode) = getTok(p) eat(p, tkParRi) -proc parseTableConstraint(p: var TSqlParser): PSqlNode = +proc parseTableConstraint(p: var SqlParser): SqlNode = if isKeyw(p, "primary"): getTok(p) eat(p, "key") @@ -861,7 +866,7 @@ proc parseTableConstraint(p: var TSqlParser): PSqlNode = else: sqlError(p, "column definition expected") -proc parseTableDef(p: var TSqlParser): PSqlNode = +proc parseTableDef(p: var SqlParser): SqlNode = result = parseIfNotExists(p, nkCreateTable) expectIdent(p) result.add(newNode(nkIdent, p.tok.literal)) @@ -876,7 +881,7 @@ proc parseTableDef(p: var TSqlParser): PSqlNode = if p.tok.kind != tkComma: break eat(p, tkParRi) -proc parseTypeDef(p: var TSqlParser): PSqlNode = +proc parseTypeDef(p: var SqlParser): SqlNode = result = parseIfNotExists(p, nkCreateType) expectIdent(p) result.add(newNode(nkIdent, p.tok.literal)) @@ -884,12 +889,12 @@ proc parseTypeDef(p: var TSqlParser): PSqlNode = eat(p, "as") result.add(parseDataType(p)) -proc parseWhere(p: var TSqlParser): PSqlNode = +proc parseWhere(p: var SqlParser): SqlNode = getTok(p) result = newNode(nkWhere) result.add(parseExpr(p)) -proc parseIndexDef(p: var TSqlParser): PSqlNode = +proc parseIndexDef(p: var SqlParser): SqlNode = result = parseIfNotExists(p, nkCreateIndex) if isKeyw(p, "primary"): getTok(p) @@ -914,7 +919,7 @@ proc parseIndexDef(p: var TSqlParser): PSqlNode = getTok(p) eat(p, tkParRi) -proc parseInsert(p: var TSqlParser): PSqlNode = +proc parseInsert(p: var SqlParser): SqlNode = getTok(p) eat(p, "into") expectIdent(p) @@ -941,7 +946,7 @@ proc parseInsert(p: var TSqlParser): PSqlNode = result.add(n) eat(p, tkParRi) -proc parseUpdate(p: var TSqlParser): PSqlNode = +proc parseUpdate(p: var SqlParser): SqlNode = getTok(p) result = newNode(nkUpdate) result.add(primary(p)) @@ -962,7 +967,7 @@ proc parseUpdate(p: var TSqlParser): PSqlNode = else: result.add(nil) -proc parseDelete(p: var TSqlParser): PSqlNode = +proc parseDelete(p: var SqlParser): SqlNode = getTok(p) result = newNode(nkDelete) eat(p, "from") @@ -972,7 +977,7 @@ proc parseDelete(p: var TSqlParser): PSqlNode = else: result.add(nil) -proc parseSelect(p: var TSqlParser): PSqlNode = +proc parseSelect(p: var SqlParser): SqlNode = getTok(p) if isKeyw(p, "distinct"): getTok(p) @@ -1041,7 +1046,7 @@ proc parseSelect(p: var TSqlParser): PSqlNode = getTok(p) result.add(n) -proc parseStmt(p: var TSqlParser): PSqlNode = +proc parseStmt(p: var SqlParser): SqlNode = if isKeyw(p, "create"): getTok(p) optKeyw(p, "cached") @@ -1071,43 +1076,43 @@ proc parseStmt(p: var TSqlParser): PSqlNode = else: sqlError(p, "CREATE expected") -proc open(p: var TSqlParser, input: PStream, filename: string) = +proc open(p: var SqlParser, input: Stream, filename: string) = ## opens the parser `p` and assigns the input stream `input` to it. ## `filename` is only used for error messages. - open(TSqlLexer(p), input, filename) + open(SqlLexer(p), input, filename) p.tok.kind = tkInvalid p.tok.literal = "" getTok(p) -proc parse(p: var TSqlParser): PSqlNode = +proc parse(p: var SqlParser): SqlNode = ## parses the content of `p`'s input stream and returns the SQL AST. ## Syntax errors raise an `EInvalidSql` exception. result = newNode(nkStmtList) while p.tok.kind != tkEof: var s = parseStmt(p) - eat(p, tkSemiColon) + eat(p, tkSemicolon) result.add(s) if result.len == 1: result = result.sons[0] -proc close(p: var TSqlParser) = +proc close(p: var SqlParser) = ## closes the parser `p`. The associated input stream is closed too. - close(TSqlLexer(p)) + close(SqlLexer(p)) -proc parseSQL*(input: PStream, filename: string): PSqlNode = +proc parseSQL*(input: Stream, filename: string): SqlNode = ## parses the SQL from `input` into an AST and returns the AST. ## `filename` is only used for error messages. ## Syntax errors raise an `EInvalidSql` exception. - var p: TSqlParser + var p: SqlParser open(p, input, filename) try: result = parse(p) finally: close(p) -proc ra(n: PSqlNode, s: var string, indent: int) +proc ra(n: SqlNode, s: var string, indent: int) -proc rs(n: PSqlNode, s: var string, indent: int, +proc rs(n: SqlNode, s: var string, indent: int, prefix = "(", suffix = ")", sep = ", ") = if n.len > 0: @@ -1117,7 +1122,7 @@ proc rs(n: PSqlNode, s: var string, indent: int, ra(n.sons[i], s, indent) s.add(suffix) -proc ra(n: PSqlNode, s: var string, indent: int) = +proc ra(n: SqlNode, s: var string, indent: int) = if n == nil: return case n.kind of nkNone: discard @@ -1320,7 +1325,7 @@ proc ra(n: PSqlNode, s: var string, indent: int) = #for x, y, z in db.select(fromm = a, b where = a.name == b.name): # writeln x, y, z -proc renderSQL*(n: PSqlNode): string = +proc renderSQL*(n: SqlNode): string = ## Converts an SQL abstract syntax tree to its string representation. result = "" ra(n, result, 0) diff --git a/lib/pure/parseurl.nim b/lib/pure/parseurl.nim index 67c6de905..32e69b89a 100644 --- a/lib/pure/parseurl.nim +++ b/lib/pure/parseurl.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # # See the file "copying.txt", included in this @@ -15,12 +15,14 @@ import strutils type - TUrl* = tuple[ ## represents a *Uniform Resource Locator* (URL) - ## any optional component is "" if it does not exist + Url* = tuple[ ## represents a *Uniform Resource Locator* (URL) + ## any optional component is "" if it does not exist scheme, username, password, hostname, port, path, query, anchor: string] - -proc parseUrl*(url: string): TUrl {.deprecated.} = + +{.deprecated: [TUrl: Url].} + +proc parseUrl*(url: string): Url {.deprecated.} = var i = 0 var scheme, username, password: string = "" @@ -29,12 +31,12 @@ proc parseUrl*(url: string): TUrl {.deprecated.} = var temp = "" if url[i] != '/': # url isn't a relative path - while True: + while true: # Scheme if url[i] == ':': if url[i+1] == '/' and url[i+2] == '/': scheme = temp - temp.setlen(0) + temp.setLen(0) inc(i, 3) # Skip the // # Authority(username, password) if url[i] == '@': @@ -43,7 +45,7 @@ proc parseUrl*(url: string): TUrl {.deprecated.} = if colon >= 0: password = username.substr(colon+1) username = username.substr(0, colon-1) - temp.setlen(0) + temp.setLen(0) inc(i) #Skip the @ # hostname(subdomain, domain, port) if url[i] == '/' or url[i] == '\0': @@ -53,7 +55,7 @@ proc parseUrl*(url: string): TUrl {.deprecated.} = port = hostname.substr(colon+1) hostname = hostname.substr(0, colon-1) - temp.setlen(0) + temp.setLen(0) break temp.add(url[i]) @@ -61,16 +63,16 @@ proc parseUrl*(url: string): TUrl {.deprecated.} = if url[i] == '/': inc(i) # Skip the '/' # Path - while True: + while true: if url[i] == '?': path = temp - temp.setlen(0) + temp.setLen(0) if url[i] == '#': if temp[0] == '?': query = temp else: path = temp - temp.setlen(0) + temp.setLen(0) if url[i] == '\0': if temp[0] == '?': @@ -86,7 +88,7 @@ proc parseUrl*(url: string): TUrl {.deprecated.} = return (scheme, username, password, hostname, port, path, query, anchor) -proc `$`*(u: TUrl): string {.deprecated.} = +proc `$`*(u: Url): string {.deprecated.} = ## turns the URL `u` into its string representation. result = "" if u.scheme.len > 0: diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim index 06ee07aa8..8f8ca6ab3 100644 --- a/lib/pure/parseutils.nim +++ b/lib/pure/parseutils.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -35,7 +35,7 @@ proc parseHex*(s: string, number: var int, start = 0): int {. ## can use this feature to *chain* calls, though the result int will quickly ## overflow. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var value = 0 ## discard parseHex("0x38", value) ## assert value == 56 @@ -227,7 +227,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {. result = parseBiggestInt(s, res, start) if (sizeof(int) <= 4) and ((res < low(int)) or (res > high(int))): - raise newException(EOverflow, "overflow") + raise newException(OverflowError, "overflow") else: number = int(res) @@ -332,7 +332,7 @@ proc parseFloat*(s: string, number: var float, start = 0): int {. number = bf type - TInterpolatedKind* = enum ## describes for `interpolatedFragments` + InterpolatedKind* = enum ## describes for `interpolatedFragments` ## which part of the interpolated string is ## yielded; for example in "str$$$var${expr}" ikStr, ## ``str`` part of the interpolated string @@ -340,19 +340,21 @@ type ikVar, ## ``var`` part of the interpolated string ikExpr ## ``expr`` part of the interpolated string -iterator interpolatedFragments*(s: string): tuple[kind: TInterpolatedKind, +{.deprecated: [TInterpolatedKind: InterpolatedKind].} + +iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind, value: string] = ## Tokenizes the string `s` into substrings for interpolation purposes. ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for k, v in interpolatedFragments(" $this is ${an example} $$"): ## echo "(", k, ", \"", v, "\")" ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## (ikString, " ") ## (ikExpr, "this") ## (ikString, " is ") @@ -360,7 +362,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: TInterpolatedKind, ## (ikString, " ") ## (ikDollar, "$") var i = 0 - var kind: TInterpolatedKind + var kind: InterpolatedKind while true: var j = i if s[j] == '$': @@ -376,7 +378,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: TInterpolatedKind, break dec nesting of '\0': - raise newException(EInvalidValue, + raise newException(ValueError, "Expected closing '}': " & s[i..s.len]) else: discard inc j @@ -392,7 +394,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: TInterpolatedKind, inc i # skip $ kind = ikDollar else: - raise newException(EInvalidValue, + raise newException(ValueError, "Unable to parse a varible name at " & s[i..s.len]) else: while j < s.len and s[j] != '$': inc j diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 667b8aed6..39dead3c0 100644 --- a/lib/pure/parsexml.nim +++ b/lib/pure/parsexml.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this @@ -33,7 +33,7 @@ ## XML parser to accomplish a simple task: To determine the title of an HTML ## document. ## -## .. code-block:: nimrod +## .. code-block:: nim ## :file: examples/htmltitle.nim ## ## @@ -44,7 +44,7 @@ ## XML parser to accomplish another simple task: To determine all the links ## an HTML document contains. ## -## .. code-block:: nimrod +## .. code-block:: nim ## :file: examples/htmlrefs.nim ## @@ -56,7 +56,7 @@ import # xmlElementCloseEnd, ## ``/>`` type - TXmlEventKind* = enum ## enumation of all events that may occur when parsing + XmlEventKind* = enum ## enumation of all events that may occur when parsing xmlError, ## an error ocurred during parsing xmlEof, ## end of file reached xmlCharData, ## character data @@ -72,7 +72,7 @@ type xmlEntity, ## &entity; xmlSpecial ## ``<! ... data ... >`` - TXmlError* = enum ## enumeration that lists all errors that can occur + XmlErrorKind* = enum ## enumeration that lists all errors that can occur errNone, ## no error errEndOfCDataExpected, ## ``]]>`` expected errNameExpected, ## name expected @@ -83,23 +83,26 @@ type errQuoteExpected, ## ``"`` or ``'`` expected errEndOfCommentExpected ## ``-->`` expected - TParserState = enum + ParserState = enum stateStart, stateNormal, stateAttr, stateEmptyElementTag, stateError - TXmlParseOption* = enum ## options for the XML parser + XmlParseOption* = enum ## options for the XML parser reportWhitespace, ## report whitespace reportComments ## report comments - TXmlParser* = object of TBaseLexer ## the parser object. + XmlParser* = object of BaseLexer ## the parser object. a, b, c: string - kind: TXmlEventKind - err: TXmlError - state: TParserState + kind: XmlEventKind + err: XmlErrorKind + state: ParserState filename: string - options: set[TXmlParseOption] - + options: set[XmlParseOption] + +{.deprecated: [TXmlParser: XmlParser, TXmlParseOptions: XmlParseOption, + TXmlError: XmlErrorKind, TXmlEventKind: XmlEventKind].} + const - errorMessages: array [TXmlError, string] = [ + errorMessages: array[XmlErrorKind, string] = [ "no error", "']]>' expected", "name expected", @@ -111,8 +114,8 @@ const "'-->' expected" ] -proc open*(my: var TXmlParser, input: PStream, filename: string, - options: set[TXmlParseOption] = {}) = +proc open*(my: var XmlParser, input: Stream, filename: string, + options: set[XmlParseOption] = {}) = ## initializes the parser with an input stream. `Filename` is only used ## for nice error messages. The parser's behaviour can be controlled by ## the `options` parameter: If `options` contains ``reportWhitespace`` @@ -127,97 +130,97 @@ proc open*(my: var TXmlParser, input: PStream, filename: string, my.b = "" my.options = options -proc close*(my: var TXmlParser) {.inline.} = +proc close*(my: var XmlParser) {.inline.} = ## closes the parser `my` and its associated input stream. lexbase.close(my) -proc kind*(my: TXmlParser): TXmlEventKind {.inline.} = +proc kind*(my: XmlParser): XmlEventKind {.inline.} = ## returns the current event type for the XML parser return my.kind -proc charData*(my: TXmlParser): string {.inline.} = +proc charData*(my: XmlParser): string {.inline.} = ## returns the character data for the events: ``xmlCharData``, ## ``xmlWhitespace``, ``xmlComment``, ``xmlCData``, ``xmlSpecial`` assert(my.kind in {xmlCharData, xmlWhitespace, xmlComment, xmlCData, xmlSpecial}) return my.a -proc elementName*(my: TXmlParser): string {.inline.} = +proc elementName*(my: XmlParser): string {.inline.} = ## returns the element name for the events: ``xmlElementStart``, ## ``xmlElementEnd``, ``xmlElementOpen`` assert(my.kind in {xmlElementStart, xmlElementEnd, xmlElementOpen}) return my.a -proc entityName*(my: TXmlParser): string {.inline.} = +proc entityName*(my: XmlParser): string {.inline.} = ## returns the entity name for the event: ``xmlEntity`` assert(my.kind == xmlEntity) return my.a -proc attrKey*(my: TXmlParser): string {.inline.} = +proc attrKey*(my: XmlParser): string {.inline.} = ## returns the attribute key for the event ``xmlAttribute`` assert(my.kind == xmlAttribute) return my.a -proc attrValue*(my: TXmlParser): string {.inline.} = +proc attrValue*(my: XmlParser): string {.inline.} = ## returns the attribute value for the event ``xmlAttribute`` assert(my.kind == xmlAttribute) return my.b -proc PIName*(my: TXmlParser): string {.inline.} = +proc piName*(my: XmlParser): string {.inline.} = ## returns the processing instruction name for the event ``xmlPI`` assert(my.kind == xmlPI) return my.a -proc PIRest*(my: TXmlParser): string {.inline.} = +proc piRest*(my: XmlParser): string {.inline.} = ## returns the rest of the processing instruction for the event ``xmlPI`` assert(my.kind == xmlPI) return my.b -proc rawData*(my: TXmlParser): string {.inline.} = +proc rawData*(my: XmlParser): string {.inline.} = ## returns the underlying 'data' string by reference. ## This is only used for speed hacks. shallowCopy(result, my.a) -proc rawData2*(my: TXmlParser): string {.inline.} = +proc rawData2*(my: XmlParser): string {.inline.} = ## returns the underlying second 'data' string by reference. ## This is only used for speed hacks. shallowCopy(result, my.b) -proc getColumn*(my: TXmlParser): int {.inline.} = +proc getColumn*(my: XmlParser): int {.inline.} = ## get the current column the parser has arrived at. - result = getColNumber(my, my.bufPos) + result = getColNumber(my, my.bufpos) -proc getLine*(my: TXmlParser): int {.inline.} = +proc getLine*(my: XmlParser): int {.inline.} = ## get the current line the parser has arrived at. - result = my.linenumber + result = my.lineNumber -proc getFilename*(my: TXmlParser): string {.inline.} = +proc getFilename*(my: XmlParser): string {.inline.} = ## get the filename of the file that the parser processes. result = my.filename -proc errorMsg*(my: TXmlParser): string = +proc errorMsg*(my: XmlParser): string = ## returns a helpful error message for the event ``xmlError`` assert(my.kind == xmlError) result = "$1($2, $3) Error: $4" % [ my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]] -proc errorMsgExpected*(my: TXmlParser, tag: string): string = +proc errorMsgExpected*(my: XmlParser, tag: string): string = ## returns an error message "<tag> expected" in the same format as the ## other error messages result = "$1($2, $3) Error: $4" % [ my.filename, $getLine(my), $getColumn(my), "<$1> expected" % tag] -proc errorMsg*(my: TXmlParser, msg: string): string = +proc errorMsg*(my: XmlParser, msg: string): string = ## returns an error message with text `msg` in the same format as the ## other error messages result = "$1($2, $3) Error: $4" % [ my.filename, $getLine(my), $getColumn(my), msg] -proc markError(my: var TXmlParser, kind: TXmlError) {.inline.} = +proc markError(my: var XmlParser, kind: XmlErrorKind) {.inline.} = my.err = kind my.state = stateError -proc parseCDATA(my: var TXMLParser) = +proc parseCDATA(my: var XmlParser) = var pos = my.bufpos + len("<![CDATA[") var buf = my.buf while true: @@ -232,20 +235,20 @@ proc parseCDATA(my: var TXMLParser) = markError(my, errEndOfCDataExpected) break of '\c': - pos = lexbase.HandleCR(my, pos) + pos = lexbase.handleCR(my, pos) buf = my.buf add(my.a, '\L') of '\L': - pos = lexbase.HandleLF(my, pos) + pos = lexbase.handleLF(my, pos) buf = my.buf add(my.a, '\L') else: add(my.a, buf[pos]) inc(pos) my.bufpos = pos # store back - my.kind = xmlCDATA + my.kind = xmlCData -proc parseComment(my: var TXMLParser) = +proc parseComment(my: var XmlParser) = var pos = my.bufpos + len("<!--") var buf = my.buf while true: @@ -260,11 +263,11 @@ proc parseComment(my: var TXMLParser) = markError(my, errEndOfCommentExpected) break of '\c': - pos = lexbase.HandleCR(my, pos) + pos = lexbase.handleCR(my, pos) buf = my.buf if my.options.contains(reportComments): add(my.a, '\L') of '\L': - pos = lexbase.HandleLF(my, pos) + pos = lexbase.handleLF(my, pos) buf = my.buf if my.options.contains(reportComments): add(my.a, '\L') else: @@ -273,21 +276,21 @@ proc parseComment(my: var TXMLParser) = my.bufpos = pos my.kind = xmlComment -proc parseWhitespace(my: var TXmlParser, skip=False) = +proc parseWhitespace(my: var XmlParser, skip=false) = var pos = my.bufpos var buf = my.buf while true: case buf[pos] of ' ', '\t': if not skip: add(my.a, buf[pos]) - Inc(pos) + inc(pos) of '\c': # the specification says that CR-LF, CR are to be transformed to LF - pos = lexbase.HandleCR(my, pos) + pos = lexbase.handleCR(my, pos) buf = my.buf if not skip: add(my.a, '\L') of '\L': - pos = lexbase.HandleLF(my, pos) + pos = lexbase.handleLF(my, pos) buf = my.buf if not skip: add(my.a, '\L') else: @@ -298,10 +301,10 @@ const NameStartChar = {'A'..'Z', 'a'..'z', '_', ':', '\128'..'\255'} NameChar = {'A'..'Z', 'a'..'z', '0'..'9', '.', '-', '_', ':', '\128'..'\255'} -proc parseName(my: var TXmlParser, dest: var string) = +proc parseName(my: var XmlParser, dest: var string) = var pos = my.bufpos var buf = my.buf - if buf[pos] in nameStartChar: + if buf[pos] in NameStartChar: while true: add(dest, buf[pos]) inc(pos) @@ -310,7 +313,7 @@ proc parseName(my: var TXmlParser, dest: var string) = else: markError(my, errNameExpected) -proc parseEntity(my: var TXmlParser, dest: var string) = +proc parseEntity(my: var XmlParser, dest: var string) = var pos = my.bufpos+1 var buf = my.buf my.kind = xmlCharData @@ -330,7 +333,7 @@ proc parseEntity(my: var TXmlParser, dest: var string) = while buf[pos] in {'0'..'9'}: r = r * 10 + (ord(buf[pos]) - ord('0')) inc(pos) - add(dest, toUTF8(TRune(r))) + add(dest, toUTF8(Rune(r))) elif buf[pos] == 'l' and buf[pos+1] == 't' and buf[pos+2] == ';': add(dest, '<') inc(pos, 2) @@ -360,10 +363,10 @@ proc parseEntity(my: var TXmlParser, dest: var string) = if buf[pos] == ';': inc(pos) else: - markError(my, errSemiColonExpected) + markError(my, errSemicolonExpected) my.bufpos = pos -proc parsePI(my: var TXmlParser) = +proc parsePI(my: var XmlParser) = inc(my.bufpos, "<?".len) parseName(my, my.a) var pos = my.bufpos @@ -382,11 +385,11 @@ proc parsePI(my: var TXmlParser) = inc(pos) of '\c': # the specification says that CR-LF, CR are to be transformed to LF - pos = lexbase.HandleCR(my, pos) + pos = lexbase.handleCR(my, pos) buf = my.buf add(my.b, '\L') of '\L': - pos = lexbase.HandleLF(my, pos) + pos = lexbase.handleLF(my, pos) buf = my.buf add(my.b, '\L') else: @@ -395,7 +398,7 @@ proc parsePI(my: var TXmlParser) = my.bufpos = pos my.kind = xmlPI -proc parseSpecial(my: var TXmlParser) = +proc parseSpecial(my: var XmlParser) = # things that start with <! var pos = my.bufpos + 2 var buf = my.buf @@ -417,11 +420,11 @@ proc parseSpecial(my: var TXmlParser) = inc(pos) add(my.a, '>') of '\c': - pos = lexbase.HandleCR(my, pos) + pos = lexbase.handleCR(my, pos) buf = my.buf add(my.a, '\L') of '\L': - pos = lexbase.HandleLF(my, pos) + pos = lexbase.handleLF(my, pos) buf = my.buf add(my.a, '\L') else: @@ -430,7 +433,7 @@ proc parseSpecial(my: var TXmlParser) = my.bufpos = pos my.kind = xmlSpecial -proc parseTag(my: var TXmlParser) = +proc parseTag(my: var XmlParser) = inc(my.bufpos) parseName(my, my.a) # if we have no name, do not interpret the '<': @@ -438,7 +441,7 @@ proc parseTag(my: var TXmlParser) = my.kind = xmlCharData add(my.a, '<') return - parseWhitespace(my, skip=True) + parseWhitespace(my, skip=true) if my.buf[my.bufpos] in NameStartChar: # an attribute follows: my.kind = xmlElementOpen @@ -455,17 +458,17 @@ proc parseTag(my: var TXmlParser) = else: markError(my, errGtExpected) -proc parseEndTag(my: var TXmlParser) = +proc parseEndTag(my: var XmlParser) = inc(my.bufpos, 2) parseName(my, my.a) - parseWhitespace(my, skip=True) + parseWhitespace(my, skip=true) if my.buf[my.bufpos] == '>': inc(my.bufpos) else: markError(my, errGtExpected) my.kind = xmlElementEnd -proc parseAttribute(my: var TXmlParser) = +proc parseAttribute(my: var XmlParser) = my.kind = xmlAttribute setLen(my.a, 0) setLen(my.b, 0) @@ -474,12 +477,12 @@ proc parseAttribute(my: var TXmlParser) = if my.a.len == 0: markError(my, errGtExpected) return - parseWhitespace(my, skip=True) + parseWhitespace(my, skip=true) if my.buf[my.bufpos] != '=': markError(my, errEqExpected) return inc(my.bufpos) - parseWhitespace(my, skip=True) + parseWhitespace(my, skip=true) var pos = my.bufpos var buf = my.buf @@ -504,11 +507,11 @@ proc parseAttribute(my: var TXmlParser) = pendingSpace = true inc(pos) of '\c': - pos = lexbase.HandleCR(my, pos) + pos = lexbase.handleCR(my, pos) buf = my.buf pendingSpace = true of '\L': - pos = lexbase.HandleLF(my, pos) + pos = lexbase.handleLF(my, pos) buf = my.buf pendingSpace = true else: @@ -524,9 +527,9 @@ proc parseAttribute(my: var TXmlParser) = else: markError(my, errQuoteExpected) my.bufpos = pos - parseWhitespace(my, skip=True) + parseWhitespace(my, skip=true) -proc parseCharData(my: var TXmlParser) = +proc parseCharData(my: var XmlParser) = var pos = my.bufpos var buf = my.buf while true: @@ -534,11 +537,11 @@ proc parseCharData(my: var TXmlParser) = of '\0', '<', '&': break of '\c': # the specification says that CR-LF, CR are to be transformed to LF - pos = lexbase.HandleCR(my, pos) + pos = lexbase.handleCR(my, pos) buf = my.buf add(my.a, '\L') of '\L': - pos = lexbase.HandleLF(my, pos) + pos = lexbase.handleLF(my, pos) buf = my.buf add(my.a, '\L') else: @@ -547,7 +550,7 @@ proc parseCharData(my: var TXmlParser) = my.bufpos = pos my.kind = xmlCharData -proc rawGetTok(my: var TXmlParser) = +proc rawGetTok(my: var XmlParser) = my.kind = xmlError setLen(my.a, 0) var pos = my.bufpos @@ -571,7 +574,7 @@ proc rawGetTok(my: var TXmlParser) = else: parseTag(my) of ' ', '\t', '\c', '\l': - parseWhiteSpace(my) + parseWhitespace(my) my.kind = xmlWhitespace of '\0': my.kind = xmlEof @@ -581,7 +584,7 @@ proc rawGetTok(my: var TXmlParser) = parseCharData(my) assert my.kind != xmlError -proc getTok(my: var TXmlParser) = +proc getTok(my: var XmlParser) = while true: rawGetTok(my) case my.kind @@ -591,7 +594,7 @@ proc getTok(my: var TXmlParser) = if my.options.contains(reportWhitespace): break else: break -proc next*(my: var TXmlParser) = +proc next*(my: var XmlParser) = ## retrieves the first/next event. This controls the parser. case my.state of stateNormal: @@ -626,19 +629,19 @@ proc next*(my: var TXmlParser) = when isMainModule: import os - var s = newFileStream(ParamStr(1), fmRead) - if s == nil: quit("cannot open the file" & ParamStr(1)) - var x: TXmlParser - open(x, s, ParamStr(1)) + var s = newFileStream(paramStr(1), fmRead) + if s == nil: quit("cannot open the file" & paramStr(1)) + var x: XmlParser + open(x, s, paramStr(1)) while true: next(x) case x.kind - of xmlError: Echo(x.errorMsg()) + of xmlError: echo(x.errorMsg()) of xmlEof: break of xmlCharData: echo(x.charData) of xmlWhitespace: echo("|$1|" % x.charData) of xmlComment: echo("<!-- $1 -->" % x.charData) - of xmlPI: echo("<? $1 ## $2 ?>" % [x.PIName, x.PIRest]) + of xmlPI: echo("<? $1 ## $2 ?>" % [x.piName, x.piRest]) of xmlElementStart: echo("<$1>" % x.elementName) of xmlElementEnd: echo("</$1>" % x.elementName) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index efe169c1d..b2d8a2a4f 100644 --- a/lib/pure/pegs.nim +++ b/lib/pure/pegs.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -32,7 +32,7 @@ const ## can be captured. More subpatterns cannot be captured! type - TPegKind = enum + PegKind = enum pkEmpty, pkAny, ## any character (.) pkAnyRune, ## any Unicode character (_) @@ -67,28 +67,30 @@ type pkRule, ## a <- b pkList, ## a, b pkStartAnchor ## ^ --> Internal DSL: startAnchor() - TNonTerminalFlag = enum + NonTerminalFlag = enum ntDeclared, ntUsed - TNonTerminal {.final.} = object ## represents a non terminal symbol + NonTerminalObj = object ## represents a non terminal symbol name: string ## the name of the symbol line: int ## line the symbol has been declared/used in col: int ## column the symbol has been declared/used in - flags: set[TNonTerminalFlag] ## the nonterminal's flags + flags: set[NonTerminalFlag] ## the nonterminal's flags rule: TNode ## the rule that the symbol refers to - TNode {.final, shallow.} = object - case kind: TPegKind + TNode {.shallow.} = object + case kind: PegKind of pkEmpty..pkWhitespace: nil of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string of pkChar, pkGreedyRepChar: ch: char of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char] - of pkNonTerminal: nt: PNonTerminal + of pkNonTerminal: nt: NonTerminal of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns] else: sons: seq[TNode] - PNonTerminal* = ref TNonTerminal + NonTerminal* = ref NonTerminalObj - TPeg* = TNode ## type that represents a PEG + Peg* = TNode ## type that represents a PEG -proc term*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1Str".} = +{.deprecated: [TPeg: Peg].} + +proc term*(t: string): Peg {.nosideEffect, rtl, extern: "npegs$1Str".} = ## constructs a PEG from a terminal string if t.len != 1: result.kind = pkTerminal @@ -97,35 +99,35 @@ proc term*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1Str".} = result.kind = pkChar result.ch = t[0] -proc termIgnoreCase*(t: string): TPeg {. +proc termIgnoreCase*(t: string): Peg {. nosideEffect, rtl, extern: "npegs$1".} = ## constructs a PEG from a terminal string; ignore case for matching result.kind = pkTerminalIgnoreCase result.term = t -proc termIgnoreStyle*(t: string): TPeg {. +proc termIgnoreStyle*(t: string): Peg {. nosideEffect, rtl, extern: "npegs$1".} = ## constructs a PEG from a terminal string; ignore style for matching result.kind = pkTerminalIgnoreStyle result.term = t -proc term*(t: char): TPeg {.nosideEffect, rtl, extern: "npegs$1Char".} = +proc term*(t: char): Peg {.nosideEffect, rtl, extern: "npegs$1Char".} = ## constructs a PEG from a terminal char assert t != '\0' result.kind = pkChar result.ch = t -proc charSet*(s: set[char]): TPeg {.nosideEffect, rtl, extern: "npegs$1".} = +proc charSet*(s: set[char]): Peg {.nosideEffect, rtl, extern: "npegs$1".} = ## constructs a PEG from a character set `s` assert '\0' notin s result.kind = pkCharChoice new(result.charChoice) result.charChoice[] = s -proc len(a: TPeg): int {.inline.} = return a.sons.len -proc add(d: var TPeg, s: TPeg) {.inline.} = add(d.sons, s) +proc len(a: Peg): int {.inline.} = return a.sons.len +proc add(d: var Peg, s: Peg) {.inline.} = add(d.sons, s) -proc addChoice(dest: var TPeg, elem: TPeg) = +proc addChoice(dest: var Peg, elem: Peg) = var L = dest.len-1 if L >= 0 and dest.sons[L].kind == pkCharChoice: # caution! Do not introduce false aliasing here! @@ -137,7 +139,7 @@ proc addChoice(dest: var TPeg, elem: TPeg) = else: add(dest, elem) else: add(dest, elem) -template multipleOp(k: TPegKind, localOpt: expr) = +template multipleOp(k: PegKind, localOpt: expr) = result.kind = k result.sons = @[] for x in items(a): @@ -149,12 +151,12 @@ template multipleOp(k: TPegKind, localOpt: expr) = if result.len == 1: result = result.sons[0] -proc `/`*(a: varargs[TPeg]): TPeg {. +proc `/`*(a: varargs[Peg]): Peg {. nosideEffect, rtl, extern: "npegsOrderedChoice".} = ## constructs an ordered choice with the PEGs in `a` multipleOp(pkOrderedChoice, addChoice) -proc addSequence(dest: var TPeg, elem: TPeg) = +proc addSequence(dest: var Peg, elem: Peg) = var L = dest.len-1 if L >= 0 and dest.sons[L].kind == pkTerminal: # caution! Do not introduce false aliasing here! @@ -166,12 +168,12 @@ proc addSequence(dest: var TPeg, elem: TPeg) = else: add(dest, elem) else: add(dest, elem) -proc sequence*(a: varargs[TPeg]): TPeg {. +proc sequence*(a: varargs[Peg]): Peg {. nosideEffect, rtl, extern: "npegs$1".} = ## constructs a sequence with all the PEGs from `a` multipleOp(pkSequence, addSequence) -proc `?`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsOptional".} = +proc `?`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsOptional".} = ## constructs an optional for the PEG `a` if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar, pkGreedyRepSet}: @@ -182,7 +184,7 @@ proc `?`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsOptional".} = result.kind = pkOption result.sons = @[a] -proc `*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyRep".} = +proc `*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyRep".} = ## constructs a "greedy repetition" for the PEG `a` case a.kind of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption: @@ -200,111 +202,99 @@ proc `*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyRep".} = result.kind = pkGreedyRep result.sons = @[a] -proc `!*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsSearch".} = +proc `!*`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsSearch".} = ## constructs a "search" for the PEG `a` result.kind = pkSearch result.sons = @[a] -proc `!*\`*(a: TPeg): TPeg {.noSideEffect, rtl, +proc `!*\`*(a: Peg): Peg {.noSideEffect, rtl, extern: "npgegsCapturedSearch".} = ## constructs a "captured search" for the PEG `a` result.kind = pkCapturedSearch result.sons = @[a] - -when false: - proc contains(a: TPeg, k: TPegKind): bool = - if a.kind == k: return true - case a.kind - of pkEmpty, pkAny, pkAnyRune, pkGreedyAny, pkNewLine, pkTerminal, - pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, pkGreedyRepChar, - pkCharChoice, pkGreedyRepSet: nil - of pkNonTerminal: return true - else: - for i in 0..a.sons.len-1: - if contains(a.sons[i], k): return true -proc `+`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} = +proc `+`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} = ## constructs a "greedy positive repetition" with the PEG `a` return sequence(a, *a) -proc `&`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsAndPredicate".} = +proc `&`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsAndPredicate".} = ## constructs an "and predicate" with the PEG `a` result.kind = pkAndPredicate result.sons = @[a] -proc `!`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsNotPredicate".} = +proc `!`*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsNotPredicate".} = ## constructs a "not predicate" with the PEG `a` result.kind = pkNotPredicate result.sons = @[a] -proc any*: TPeg {.inline.} = +proc any*: Peg {.inline.} = ## constructs the PEG `any character`:idx: (``.``) result.kind = pkAny -proc anyRune*: TPeg {.inline.} = +proc anyRune*: Peg {.inline.} = ## constructs the PEG `any rune`:idx: (``_``) result.kind = pkAnyRune -proc newLine*: TPeg {.inline.} = +proc newLine*: Peg {.inline.} = ## constructs the PEG `newline`:idx: (``\n``) - result.kind = pkNewline + result.kind = pkNewLine -proc unicodeLetter*: TPeg {.inline.} = +proc unicodeLetter*: Peg {.inline.} = ## constructs the PEG ``\letter`` which matches any Unicode letter. result.kind = pkLetter -proc unicodeLower*: TPeg {.inline.} = +proc unicodeLower*: Peg {.inline.} = ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter. result.kind = pkLower -proc unicodeUpper*: TPeg {.inline.} = +proc unicodeUpper*: Peg {.inline.} = ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter. result.kind = pkUpper -proc unicodeTitle*: TPeg {.inline.} = +proc unicodeTitle*: Peg {.inline.} = ## constructs the PEG ``\title`` which matches any Unicode title letter. result.kind = pkTitle -proc unicodeWhitespace*: TPeg {.inline.} = +proc unicodeWhitespace*: Peg {.inline.} = ## constructs the PEG ``\white`` which matches any Unicode ## whitespace character. result.kind = pkWhitespace -proc startAnchor*: TPeg {.inline.} = +proc startAnchor*: Peg {.inline.} = ## constructs the PEG ``^`` which matches the start of the input. result.kind = pkStartAnchor -proc endAnchor*: TPeg {.inline.} = +proc endAnchor*: Peg {.inline.} = ## constructs the PEG ``$`` which matches the end of the input. result = !any() -proc capture*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsCapture".} = +proc capture*(a: Peg): Peg {.nosideEffect, rtl, extern: "npegsCapture".} = ## constructs a capture with the PEG `a` result.kind = pkCapture result.sons = @[a] -proc backref*(index: range[1..MaxSubPatterns]): TPeg {. +proc backref*(index: range[1..MaxSubpatterns]): Peg {. nosideEffect, rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting ## from 1. result.kind = pkBackRef result.index = index-1 -proc backrefIgnoreCase*(index: range[1..MaxSubPatterns]): TPeg {. +proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): Peg {. nosideEffect, rtl, extern: "npegs$1".} = ## constructs a back reference of the given `index`. `index` starts counting ## from 1. Ignores case for matching. result.kind = pkBackRefIgnoreCase result.index = index-1 -proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg {. +proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): Peg {. nosideEffect, rtl, extern: "npegs$1".}= ## constructs a back reference of the given `index`. `index` starts counting ## from 1. Ignores style for matching. result.kind = pkBackRefIgnoreStyle result.index = index-1 -proc spaceCost(n: TPeg): int = +proc spaceCost(n: Peg): int = case n.kind of pkEmpty: discard of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, @@ -319,7 +309,7 @@ proc spaceCost(n: TPeg): int = inc(result, spaceCost(n.sons[i])) if result >= InlineThreshold: break -proc nonterminal*(n: PNonTerminal): TPeg {. +proc nonterminal*(n: NonTerminal): Peg {. nosideEffect, rtl, extern: "npegs$1".} = ## constructs a PEG that consists of the nonterminal symbol assert n != nil @@ -330,7 +320,7 @@ proc nonterminal*(n: PNonTerminal): TPeg {. result.kind = pkNonTerminal result.nt = n -proc newNonTerminal*(name: string, line, column: int): PNonTerminal {. +proc newNonTerminal*(name: string, line, column: int): NonTerminal {. nosideEffect, rtl, extern: "npegs$1".} = ## constructs a nonterminal symbol new(result) @@ -415,7 +405,7 @@ proc charSetEsc(cc: set[char]): string = else: result = '[' & charSetEscAux(cc) & ']' -proc toStrAux(r: TPeg, res: var string) = +proc toStrAux(r: Peg, res: var string) = case r.kind of pkEmpty: add(res, "()") of pkAny: add(res, '.') @@ -426,7 +416,7 @@ proc toStrAux(r: TPeg, res: var string) = of pkTitle: add(res, "\\title") of pkWhitespace: add(res, "\\white") - of pkNewline: add(res, "\\n") + of pkNewLine: add(res, "\\n") of pkTerminal: add(res, singleQuoteEsc(r.term)) of pkTerminalIgnoreCase: add(res, 'i') @@ -501,7 +491,7 @@ proc toStrAux(r: TPeg, res: var string) = of pkStartAnchor: add(res, '^') -proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} = +proc `$` *(r: Peg): string {.nosideEffect, rtl, extern: "npegsToString".} = ## converts a PEG to its string representation result = "" toStrAux(r, result) @@ -509,13 +499,15 @@ proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} = # --------------------- core engine ------------------------------------------- type - TCaptures* {.final.} = object ## contains the captured substrings. - matches: array[0..maxSubpatterns-1, tuple[first, last: int]] + Captures* = object ## contains the captured substrings. + matches: array[0..MaxSubpatterns-1, tuple[first, last: int]] ml: int origStart: int -proc bounds*(c: TCaptures, - i: range[0..maxSubpatterns-1]): tuple[first, last: int] = +{.deprecated: [TCaptures: Captures].} + +proc bounds*(c: Captures, + i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = ## returns the bounds ``[first..last]`` of the `i`'th capture. result = c.matches[i] @@ -533,7 +525,7 @@ when not useUnicode: proc isTitle(a: char): bool {.inline.} = return false proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'} -proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. +proc rawMatch*(s: string, p: Peg, start: int, c: var Captures): int {. nosideEffect, rtl, extern: "npegs$1".} = ## low-level matching proc that implements the PEG interpreter. Use this ## for maximum efficiency (every other PEG operation ends up calling this @@ -551,7 +543,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. result = -1 of pkLetter: if s[start] != '\0': - var a: TRune + var a: Rune result = start fastRuneAt(s, result, a) if isAlpha(a): dec(result, start) @@ -560,7 +552,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. result = -1 of pkLower: if s[start] != '\0': - var a: TRune + var a: Rune result = start fastRuneAt(s, result, a) if isLower(a): dec(result, start) @@ -569,7 +561,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. result = -1 of pkUpper: if s[start] != '\0': - var a: TRune + var a: Rune result = start fastRuneAt(s, result, a) if isUpper(a): dec(result, start) @@ -578,7 +570,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. result = -1 of pkTitle: if s[start] != '\0': - var a: TRune + var a: Rune result = start fastRuneAt(s, result, a) if isTitle(a): dec(result, start) @@ -587,7 +579,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. result = -1 of pkWhitespace: if s[start] != '\0': - var a: TRune + var a: Rune result = start fastRuneAt(s, result, a) if isWhiteSpace(a): dec(result, start) @@ -611,7 +603,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. of pkTerminalIgnoreCase: var i = 0 - a, b: TRune + a, b: Rune result = start while i < len(p.term): fastRuneAt(p.term, i, a) @@ -623,15 +615,15 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. of pkTerminalIgnoreStyle: var i = 0 - a, b: TRune + a, b: Rune result = start while i < len(p.term): while true: fastRuneAt(p.term, i, a) - if a != TRune('_'): break + if a != Rune('_'): break while true: fastRuneAt(s, result, b) - if b != TRune('_'): break + if b != Rune('_'): break if toLower(a) != toLower(b): result = -1 break @@ -682,7 +674,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. while start+result < s.len: var x = rawMatch(s, p.sons[0], start+result, c) if x >= 0: - if idx < maxSubpatterns: + if idx < MaxSubpatterns: c.matches[idx] = (start, start+result-1) #else: silently ignore the capture inc(result, x) @@ -726,7 +718,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. inc(c.ml) result = rawMatch(s, p.sons[0], start, c) if result >= 0: - if idx < maxSubpatterns: + if idx < MaxSubpatterns: c.matches[idx] = (start, start+result-1) #else: silently ignore the capture else: @@ -734,7 +726,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {. of pkBackRef..pkBackRefIgnoreStyle: if p.index >= c.ml: return -1 var (a, b) = c.matches[p.index] - var n: TPeg + var n: Peg n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) n.term = s.substr(a, b) result = rawMatch(s, n, start, c) @@ -747,51 +739,51 @@ template fillMatches(s, caps, c: expr) = for k in 0..c.ml-1: caps[k] = substr(s, c.matches[k][0], c.matches[k][1]) -proc match*(s: string, pattern: TPeg, matches: var openArray[string], +proc match*(s: string, pattern: Peg, matches: var openArray[string], start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} = ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and ## the captured substrings in the array ``matches``. If it does not ## match, nothing is written into ``matches`` and ``false`` is ## returned. - var c: TCaptures + var c: Captures c.origStart = start result = rawMatch(s, pattern, start, c) == len(s) - start if result: fillMatches(s, matches, c) -proc match*(s: string, pattern: TPeg, +proc match*(s: string, pattern: Peg, start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} = ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``. - var c: TCaptures + var c: Captures c.origStart = start result = rawMatch(s, pattern, start, c) == len(s)-start -proc matchLen*(s: string, pattern: TPeg, matches: var openArray[string], +proc matchLen*(s: string, pattern: Peg, matches: var openArray[string], start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} = ## the same as ``match``, but it returns the length of the match, ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. It's possible that a suffix of `s` remains ## that does not belong to the match. - var c: TCaptures + var c: Captures c.origStart = start result = rawMatch(s, pattern, start, c) if result >= 0: fillMatches(s, matches, c) -proc matchLen*(s: string, pattern: TPeg, +proc matchLen*(s: string, pattern: Peg, start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} = ## the same as ``match``, but it returns the length of the match, ## if there is no match, -1 is returned. Note that a match length ## of zero can happen. It's possible that a suffix of `s` remains ## that does not belong to the match. - var c: TCaptures + var c: Captures c.origStart = start result = rawMatch(s, pattern, start, c) -proc find*(s: string, pattern: TPeg, matches: var openArray[string], +proc find*(s: string, pattern: Peg, matches: var openArray[string], start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} = ## returns the starting position of ``pattern`` in ``s`` and the captured ## substrings in the array ``matches``. If it does not match, nothing ## is written into ``matches`` and -1 is returned. - var c: TCaptures + var c: Captures c.origStart = start for i in start .. s.len-1: c.ml = 0 @@ -801,14 +793,14 @@ proc find*(s: string, pattern: TPeg, matches: var openArray[string], return -1 # could also use the pattern here: (!P .)* P -proc findBounds*(s: string, pattern: TPeg, matches: var openArray[string], +proc findBounds*(s: string, pattern: Peg, matches: var openArray[string], start = 0): tuple[first, last: int] {. nosideEffect, rtl, extern: "npegs$1Capture".} = ## returns the starting position and end position of ``pattern`` in ``s`` ## and the captured ## substrings in the array ``matches``. If it does not match, nothing ## is written into ``matches`` and (-1,0) is returned. - var c: TCaptures + var c: Captures c.origStart = start for i in start .. s.len-1: c.ml = 0 @@ -818,19 +810,19 @@ proc findBounds*(s: string, pattern: TPeg, matches: var openArray[string], return (i, i+L-1) return (-1, 0) -proc find*(s: string, pattern: TPeg, +proc find*(s: string, pattern: Peg, start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} = ## returns the starting position of ``pattern`` in ``s``. If it does not ## match, -1 is returned. - var c: TCaptures + var c: Captures c.origStart = start for i in start .. s.len-1: if rawMatch(s, pattern, i, c) >= 0: return i return -1 -iterator findAll*(s: string, pattern: TPeg, start = 0): string = +iterator findAll*(s: string, pattern: Peg, start = 0): string = ## yields all matching *substrings* of `s` that match `pattern`. - var c: TCaptures + var c: Captures c.origStart = start var i = start while i < s.len: @@ -842,7 +834,7 @@ iterator findAll*(s: string, pattern: TPeg, start = 0): string = yield substr(s, i, i+L-1) inc(i, L) -proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {. +proc findAll*(s: string, pattern: Peg, start = 0): seq[string] {. nosideEffect, rtl, extern: "npegs$1".} = ## returns all matching *substrings* of `s` that match `pattern`. ## If it does not match, @[] is returned. @@ -851,11 +843,11 @@ proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {. when not defined(nimhygiene): {.pragma: inject.} -template `=~`*(s: string, pattern: TPeg): bool = +template `=~`*(s: string, pattern: Peg): bool = ## This calls ``match`` with an implicit declared ``matches`` array that ## can be used in the scope of the ``=~`` call: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}": ## # matches a key=value pair: @@ -869,53 +861,53 @@ template `=~`*(s: string, pattern: TPeg): bool = ## else: ## echo("syntax error") ## - bind maxSubpatterns + bind MaxSubpatterns when not declaredInScope(matches): var matches {.inject.}: array[0..MaxSubpatterns-1, string] match(s, pattern, matches) # ------------------------- more string handling ------------------------------ -proc contains*(s: string, pattern: TPeg, start = 0): bool {. +proc contains*(s: string, pattern: Peg, start = 0): bool {. nosideEffect, rtl, extern: "npegs$1".} = ## same as ``find(s, pattern, start) >= 0`` return find(s, pattern, start) >= 0 -proc contains*(s: string, pattern: TPeg, matches: var openArray[string], +proc contains*(s: string, pattern: Peg, matches: var openArray[string], start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} = ## same as ``find(s, pattern, matches, start) >= 0`` return find(s, pattern, matches, start) >= 0 -proc startsWith*(s: string, prefix: TPeg, start = 0): bool {. +proc startsWith*(s: string, prefix: Peg, start = 0): bool {. nosideEffect, rtl, extern: "npegs$1".} = ## returns true if `s` starts with the pattern `prefix` result = matchLen(s, prefix, start) >= 0 -proc endsWith*(s: string, suffix: TPeg, start = 0): bool {. +proc endsWith*(s: string, suffix: Peg, start = 0): bool {. nosideEffect, rtl, extern: "npegs$1".} = ## returns true if `s` ends with the pattern `prefix` - var c: TCaptures + var c: Captures c.origStart = start for i in start .. s.len-1: if rawMatch(s, suffix, i, c) == s.len - i: return true -proc replacef*(s: string, sub: TPeg, by: string): string {. +proc replacef*(s: string, sub: Peg, by: string): string {. nosideEffect, rtl, extern: "npegs$1".} = ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## "var1<-keykey; val2<-key2key2" result = "" var i = 0 - var caps: array[0..maxSubpatterns-1, string] - var c: TCaptures + var caps: array[0..MaxSubpatterns-1, string] + var c: Captures while i < s.len: c.ml = 0 var x = rawMatch(s, sub, i, c) @@ -928,13 +920,13 @@ proc replacef*(s: string, sub: TPeg, by: string): string {. inc(i, x) add(result, substr(s, i)) -proc replace*(s: string, sub: TPeg, by = ""): string {. +proc replace*(s: string, sub: Peg, by = ""): string {. nosideEffect, rtl, extern: "npegs$1".} = ## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed ## in `by`. result = "" var i = 0 - var c: TCaptures + var c: Captures while i < s.len: var x = rawMatch(s, sub, i, c) if x <= 0: @@ -946,14 +938,14 @@ proc replace*(s: string, sub: TPeg, by = ""): string {. add(result, substr(s, i)) proc parallelReplace*(s: string, subs: varargs[ - tuple[pattern: TPeg, repl: string]]): string {. + tuple[pattern: Peg, repl: string]]): string {. nosideEffect, rtl, extern: "npegs$1".} = ## Returns a modified copy of `s` with the substitutions in `subs` ## applied in parallel. result = "" var i = 0 - var c: TCaptures - var caps: array[0..maxSubpatterns-1, string] + var c: Captures + var caps: array[0..MaxSubpatterns-1, string] while i < s.len: block searchSubs: for j in 0..high(subs): @@ -970,7 +962,7 @@ proc parallelReplace*(s: string, subs: varargs[ add(result, substr(s, i)) proc transformFile*(infile, outfile: string, - subs: varargs[tuple[pattern: TPeg, repl: string]]) {. + subs: varargs[tuple[pattern: Peg, repl: string]]) {. rtl, extern: "npegs$1".} = ## reads in the file `infile`, performs a parallel replacement (calls ## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an @@ -978,25 +970,25 @@ proc transformFile*(infile, outfile: string, var x = readFile(infile).string writeFile(outfile, x.parallelReplace(subs)) -iterator split*(s: string, sep: TPeg): string = +iterator split*(s: string, sep: Peg): string = ## Splits the string `s` into substrings. ## ## Substrings are separated by the PEG `sep`. ## Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for word in split("00232this02939is39an22example111", peg"\d+"): ## writeln(stdout, word) ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "this" ## "is" ## "an" ## "example" ## - var c: TCaptures + var c: Captures var first = 0 last = 0 @@ -1013,7 +1005,7 @@ iterator split*(s: string, sep: TPeg): string = if first < last: yield substr(s, first, last-1) -proc split*(s: string, sep: TPeg): seq[string] {. +proc split*(s: string, sep: Peg): seq[string] {. nosideEffect, rtl, extern: "npegs$1".} = ## Splits the string `s` into substrings. accumulateResult(split(s, sep)) @@ -1060,10 +1052,10 @@ type charset: set[char] ## if kind == tkCharSet index: int ## if kind == tkBackref - TPegLexer {.inheritable.} = object ## the lexer object. + PegLexer {.inheritable.} = object ## the lexer object. bufpos: int ## the current position within the buffer buf: cstring ## the buffer itself - LineNumber: int ## the current line number + lineNumber: int ## the current line number lineStart: int ## index of last line start in buffer colOffset: int ## column to add filename: string @@ -1076,20 +1068,20 @@ const "@", "built-in", "escaped", "$", "$", "^" ] -proc handleCR(L: var TPegLexer, pos: int): int = +proc handleCR(L: var PegLexer, pos: int): int = assert(L.buf[pos] == '\c') - inc(L.linenumber) + inc(L.lineNumber) result = pos+1 if L.buf[result] == '\L': inc(result) L.lineStart = result -proc handleLF(L: var TPegLexer, pos: int): int = +proc handleLF(L: var PegLexer, pos: int): int = assert(L.buf[pos] == '\L') - inc(L.linenumber) + inc(L.lineNumber) result = pos+1 L.lineStart = result -proc init(L: var TPegLexer, input, filename: string, line = 1, col = 0) = +proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) = L.buf = input L.bufpos = 0 L.lineNumber = line @@ -1097,18 +1089,18 @@ proc init(L: var TPegLexer, input, filename: string, line = 1, col = 0) = L.lineStart = 0 L.filename = filename -proc getColumn(L: TPegLexer): int {.inline.} = +proc getColumn(L: PegLexer): int {.inline.} = result = abs(L.bufpos - L.lineStart) + L.colOffset -proc getLine(L: TPegLexer): int {.inline.} = - result = L.linenumber +proc getLine(L: PegLexer): int {.inline.} = + result = L.lineNumber -proc errorStr(L: TPegLexer, msg: string, line = -1, col = -1): string = +proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string = var line = if line < 0: getLine(L) else: line var col = if col < 0: getColumn(L) else: col result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg] -proc handleHexChar(c: var TPegLexer, xi: var int) = +proc handleHexChar(c: var PegLexer, xi: var int) = case c.buf[c.bufpos] of '0'..'9': xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) @@ -1121,7 +1113,7 @@ proc handleHexChar(c: var TPegLexer, xi: var int) = inc(c.bufpos) else: discard -proc getEscapedChar(c: var TPegLexer, tok: var TToken) = +proc getEscapedChar(c: var PegLexer, tok: var TToken) = inc(c.bufpos) case c.buf[c.bufpos] of 'r', 'R', 'c', 'C': @@ -1167,13 +1159,13 @@ proc getEscapedChar(c: var TPegLexer, tok: var TToken) = else: tok.kind = tkInvalid of '\0'..'\31': tok.kind = tkInvalid - elif c.buf[c.bufpos] in strutils.letters: + elif c.buf[c.bufpos] in strutils.Letters: tok.kind = tkInvalid else: add(tok.literal, c.buf[c.bufpos]) inc(c.bufpos) -proc skip(c: var TPegLexer) = +proc skip(c: var PegLexer) = var pos = c.bufpos var buf = c.buf while true: @@ -1192,9 +1184,9 @@ proc skip(c: var TPegLexer) = break # EndOfFile also leaves the loop c.bufpos = pos -proc getString(c: var TPegLexer, tok: var TToken) = +proc getString(c: var PegLexer, tok: var TToken) = tok.kind = tkStringLit - var pos = c.bufPos + 1 + var pos = c.bufpos + 1 var buf = c.buf var quote = buf[pos-1] while true: @@ -1214,8 +1206,8 @@ proc getString(c: var TPegLexer, tok: var TToken) = inc(pos) c.bufpos = pos -proc getDollar(c: var TPegLexer, tok: var TToken) = - var pos = c.bufPos + 1 +proc getDollar(c: var PegLexer, tok: var TToken) = + var pos = c.bufpos + 1 var buf = c.buf if buf[pos] in {'0'..'9'}: tok.kind = tkBackref @@ -1227,10 +1219,10 @@ proc getDollar(c: var TPegLexer, tok: var TToken) = tok.kind = tkDollar c.bufpos = pos -proc getCharSet(c: var TPegLexer, tok: var TToken) = +proc getCharSet(c: var PegLexer, tok: var TToken) = tok.kind = tkCharSet tok.charset = {} - var pos = c.bufPos + 1 + var pos = c.bufpos + 1 var buf = c.buf var caret = false if buf[pos] == '^': @@ -1278,7 +1270,7 @@ proc getCharSet(c: var TPegLexer, tok: var TToken) = c.bufpos = pos if caret: tok.charset = {'\1'..'\xFF'} - tok.charset -proc getSymbol(c: var TPegLexer, tok: var TToken) = +proc getSymbol(c: var PegLexer, tok: var TToken) = var pos = c.bufpos var buf = c.buf while true: @@ -1288,7 +1280,7 @@ proc getSymbol(c: var TPegLexer, tok: var TToken) = c.bufpos = pos tok.kind = tkIdentifier -proc getBuiltin(c: var TPegLexer, tok: var TToken) = +proc getBuiltin(c: var PegLexer, tok: var TToken) = if c.buf[c.bufpos+1] in strutils.Letters: inc(c.bufpos) getSymbol(c, tok) @@ -1297,7 +1289,7 @@ proc getBuiltin(c: var TPegLexer, tok: var TToken) = tok.kind = tkEscaped getEscapedChar(c, tok) # may set tok.kind to tkInvalid -proc getTok(c: var TPegLexer, tok: var TToken) = +proc getTok(c: var PegLexer, tok: var TToken) = tok.kind = tkInvalid tok.modifier = modNone setLen(tok.literal, 0) @@ -1403,7 +1395,7 @@ proc getTok(c: var TPegLexer, tok: var TToken) = add(tok.literal, c.buf[c.bufpos]) inc(c.bufpos) -proc arrowIsNextTok(c: TPegLexer): bool = +proc arrowIsNextTok(c: PegLexer): bool = # the only look ahead we need var pos = c.bufpos while c.buf[pos] in {'\t', ' '}: inc(pos) @@ -1412,33 +1404,33 @@ proc arrowIsNextTok(c: TPegLexer): bool = # ----------------------------- parser ---------------------------------------- type - EInvalidPeg* = object of EInvalidValue ## raised if an invalid + EInvalidPeg* = object of ValueError ## raised if an invalid ## PEG has been detected - TPegParser = object of TPegLexer ## the PEG parser object + PegParser = object of PegLexer ## the PEG parser object tok: TToken - nonterms: seq[PNonTerminal] + nonterms: seq[NonTerminal] modifier: TModifier captures: int identIsVerbatim: bool - skip: TPeg + skip: Peg -proc pegError(p: TPegParser, msg: string, line = -1, col = -1) = +proc pegError(p: PegParser, msg: string, line = -1, col = -1) = var e: ref EInvalidPeg new(e) e.msg = errorStr(p, msg, line, col) raise e -proc getTok(p: var TPegParser) = +proc getTok(p: var PegParser) = getTok(p, p.tok) if p.tok.kind == tkInvalid: pegError(p, "invalid token") -proc eat(p: var TPegParser, kind: TTokKind) = +proc eat(p: var PegParser, kind: TTokKind) = if p.tok.kind == kind: getTok(p) else: pegError(p, tokKindToStr[kind] & " expected") -proc parseExpr(p: var TPegParser): TPeg +proc parseExpr(p: var PegParser): Peg -proc getNonTerminal(p: var TPegParser, name: string): PNonTerminal = +proc getNonTerminal(p: var PegParser, name: string): NonTerminal = for i in 0..high(p.nonterms): result = p.nonterms[i] if cmpIgnoreStyle(result.name, name) == 0: return @@ -1446,19 +1438,19 @@ proc getNonTerminal(p: var TPegParser, name: string): PNonTerminal = result = newNonTerminal(name, getLine(p), getColumn(p)) add(p.nonterms, result) -proc modifiedTerm(s: string, m: TModifier): TPeg = +proc modifiedTerm(s: string, m: TModifier): Peg = case m of modNone, modVerbatim: result = term(s) of modIgnoreCase: result = termIgnoreCase(s) of modIgnoreStyle: result = termIgnoreStyle(s) -proc modifiedBackref(s: int, m: TModifier): TPeg = +proc modifiedBackref(s: int, m: TModifier): Peg = case m of modNone, modVerbatim: result = backref(s) of modIgnoreCase: result = backrefIgnoreCase(s) of modIgnoreStyle: result = backrefIgnoreStyle(s) -proc builtin(p: var TPegParser): TPeg = +proc builtin(p: var PegParser): Peg = # do not use "y", "skip" or "i" as these would be ambiguous case p.tok.literal of "n": result = newLine() @@ -1478,11 +1470,11 @@ proc builtin(p: var TPegParser): TPeg = of "white": result = unicodeWhitespace() else: pegError(p, "unknown built-in: " & p.tok.literal) -proc token(terminal: TPeg, p: TPegParser): TPeg = +proc token(terminal: Peg, p: PegParser): Peg = if p.skip.kind == pkEmpty: result = terminal else: result = sequence(p.skip, terminal) -proc primary(p: var TPegParser): TPeg = +proc primary(p: var PegParser): Peg = case p.tok.kind of tkAmp: getTok(p) @@ -1571,11 +1563,11 @@ proc primary(p: var TPegParser): TPeg = getTok(p) else: break -proc seqExpr(p: var TPegParser): TPeg = +proc seqExpr(p: var PegParser): Peg = result = primary(p) while true: case p.tok.kind - of tkAmp, tkNot, tkAt, tkStringLit, tkCharset, tkParLe, tkCurlyLe, + of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe, tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, tkHat, tkCurlyAt: result = sequence(result, primary(p)) @@ -1585,13 +1577,13 @@ proc seqExpr(p: var TPegParser): TPeg = else: break else: break -proc parseExpr(p: var TPegParser): TPeg = +proc parseExpr(p: var PegParser): Peg = result = seqExpr(p) while p.tok.kind == tkBar: getTok(p) result = result / seqExpr(p) -proc parseRule(p: var TPegParser): PNonTerminal = +proc parseRule(p: var PegParser): NonTerminal = if p.tok.kind == tkIdentifier and arrowIsNextTok(p): result = getNonTerminal(p, p.tok.literal) if ntDeclared in result.flags: @@ -1605,7 +1597,7 @@ proc parseRule(p: var TPegParser): PNonTerminal = else: pegError(p, "rule expected, but found: " & p.tok.literal) -proc rawParse(p: var TPegParser): TPeg = +proc rawParse(p: var PegParser): Peg = ## parses a rule or a PEG expression while p.tok.kind == tkBuiltin: case p.tok.literal @@ -1635,12 +1627,12 @@ proc rawParse(p: var TPegParser): TPeg = elif ntUsed notin nt.flags and i > 0: pegError(p, "unused rule: " & nt.name, nt.line, nt.col) -proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg = - ## constructs a TPeg object from `pattern`. `filename`, `line`, `col` are +proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): Peg = + ## constructs a Peg object from `pattern`. `filename`, `line`, `col` are ## used for error messages, but they only provide start offsets. `parsePeg` ## keeps track of line and column numbers within `pattern`. - var p: TPegParser - init(TPegLexer(p), pattern, filename, line, col) + var p: PegParser + init(PegLexer(p), pattern, filename, line, col) p.tok.kind = tkInvalid p.tok.modifier = modNone p.tok.literal = "" @@ -1650,8 +1642,8 @@ proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg = getTok(p) result = rawParse(p) -proc peg*(pattern: string): TPeg = - ## constructs a TPeg object from the `pattern`. The short name has been +proc peg*(pattern: string): Peg = + ## constructs a Peg object from the `pattern`. The short name has been ## chosen to encourage its use as a raw string modifier:: ## ## peg"{\ident} \s* '=' \s* {.*}" @@ -1704,7 +1696,7 @@ when isMainModule: expr.rule = sequence(capture(ident), *sequence( nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) - var c: TCaptures + var c: Captures var s = "a+b + c +d+e+f" assert rawMatch(s, expr.rule, 0, c) == len(s) var a = "" @@ -1720,7 +1712,7 @@ when isMainModule: assert match("_______ana", peg"A <- 'ana' / . A") assert match("abcs%%%", peg"A <- ..A / .A / '%'") - var matches: array[0..maxSubpatterns-1, string] + var matches: array[0..MaxSubpatterns-1, string] if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": assert matches[0] == "abc" else: diff --git a/lib/pure/pegs.nimfix b/lib/pure/pegs.nimfix new file mode 100644 index 000000000..8dd172a48 --- /dev/null +++ b/lib/pure/pegs.nimfix @@ -0,0 +1,1770 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Simple PEG (Parsing expression grammar) matching. Uses no memorization, but +## uses superoperators and symbol inlining to improve performance. Note: +## Matching performance is hopefully competitive with optimized regular +## expression engines. +## +## .. include:: ../doc/pegdocs.txt +## + +include "system/inclrtl" + +const + useUnicode = true ## change this to deactivate proper UTF-8 support + +import + strutils + +when useUnicode: + import unicode + +const + InlineThreshold = 5 ## number of leaves; -1 to disable inlining + MaxSubpatterns* = 10 ## defines the maximum number of subpatterns that + ## can be captured. More subpatterns cannot be captured! + +type + PegKind = enum + pkEmpty, + pkAny, ## any character (.) + pkAnyRune, ## any Unicode character (_) + pkNewLine, ## CR-LF, LF, CR + pkLetter, ## Unicode letter + pkLower, ## Unicode lower case letter + pkUpper, ## Unicode upper case letter + pkTitle, ## Unicode title character + pkWhitespace, ## Unicode whitespace character + pkTerminal, + pkTerminalIgnoreCase, + pkTerminalIgnoreStyle, + pkChar, ## single character to match + pkCharChoice, + pkNonTerminal, + pkSequence, ## a b c ... --> Internal DSL: peg(a, b, c) + pkOrderedChoice, ## a / b / ... --> Internal DSL: a / b or /[a, b, c] + pkGreedyRep, ## a* --> Internal DSL: *a + ## a+ --> (a a*) + pkGreedyRepChar, ## x* where x is a single character (superop) + pkGreedyRepSet, ## [set]* (superop) + pkGreedyAny, ## .* or _* (superop) + pkOption, ## a? --> Internal DSL: ?a + pkAndPredicate, ## &a --> Internal DSL: &a + pkNotPredicate, ## !a --> Internal DSL: !a + pkCapture, ## {a} --> Internal DSL: capture(a) + pkBackRef, ## $i --> Internal DSL: backref(i) + pkBackRefIgnoreCase, + pkBackRefIgnoreStyle, + pkSearch, ## @a --> Internal DSL: !*a + pkCapturedSearch, ## {@} a --> Internal DSL: !*\a + pkRule, ## a <- b + pkList, ## a, b + pkStartAnchor ## ^ --> Internal DSL: startAnchor() + NonTerminalFlag = enum + ntDeclared, ntUsed + NonTerminalObj = object ## represents a non terminal symbol + name: string ## the name of the symbol + line: int ## line the symbol has been declared/used in + col: int ## column the symbol has been declared/used in + flags: set[NonTerminalFlag] ## the nonterminal's flags + rule: TNode ## the rule that the symbol refers to + TNode {.shallow.} = object + case kind: PegKind + of pkEmpty..pkWhitespace: nil + of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle: term: string + of pkChar, pkGreedyRepChar: ch: char + of pkCharChoice, pkGreedyRepSet: charChoice: ref set[char] + of pkNonTerminal: nt: PNonTerminal + of pkBackRef..pkBackRefIgnoreStyle: index: range[0..MaxSubpatterns] + else: sons: seq[TNode] + PNonTerminal* = ref NonTerminalObj + TPeg* = TNode + +block: + type + Peg = TNode + NonTerminal = PNonTerminal + {.deprecated: [TPeg: Peg, PNonTerminal: NonTerminal].} + +proc term*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1Str".} = + ## constructs a PEG from a terminal string + if t.len != 1: + result.kind = pkTerminal + result.term = t + else: + result.kind = pkChar + result.ch = t[0] + +proc termIgnoreCase*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1".} = + ## constructs a PEG from a terminal string; ignore case for matching + result.kind = pkTerminalIgnoreCase + result.term = t + +proc termIgnoreStyle*(t: string): TPeg {.nosideEffect, rtl, extern: "npegs$1".} = + ## constructs a PEG from a terminal string; ignore style for matching + result.kind = pkTerminalIgnoreStyle + result.term = t + +proc term*(t: char): TPeg {.nosideEffect, rtl, extern: "npegs$1Char".} = + ## constructs a PEG from a terminal char + assert t != '\0' + result.kind = pkChar + result.ch = t + +proc charSet*(s: set[char]): TPeg {.nosideEffect, rtl, extern: "npegs$1".} = + ## constructs a PEG from a character set `s` + assert '\0' notin s + result.kind = pkCharChoice + new(result.charChoice) + result.charChoice[] = s + +proc len(a: TPeg): int {.inline.} = return a.sons.len +proc add(d: var TPeg, s: TPeg) {.inline.} = add(d.sons, s) + +proc addChoice(dest: var TPeg, elem: TPeg) = + var L = dest.len-1 + if L >= 0 and dest.sons[L].kind == pkCharChoice: + # caution! Do not introduce false aliasing here! + case elem.kind + of pkCharChoice: + dest.sons[L] = charSet(dest.sons[L].charChoice[] + elem.charChoice[]) + of pkChar: + dest.sons[L] = charSet(dest.sons[L].charChoice[] + {elem.ch}) + else: add(dest, elem) + else: add(dest, elem) + +template multipleOp(k: PegKind, localOpt: expr) = + result.kind = k + result.sons = @[] + for x in items(a): + if x.kind == k: + for y in items(x.sons): + localOpt(result, y) + else: + localOpt(result, x) + if result.len == 1: + result = result.sons[0] + +proc `/`*(a: varargs[TPeg]): TPeg {. + nosideEffect, rtl, extern: "npegsOrderedChoice".} = + ## constructs an ordered choice with the PEGs in `a` + multipleOp(pkOrderedChoice, addChoice) + +proc addSequence(dest: var TPeg, elem: TPeg) = + var L = dest.len-1 + if L >= 0 and dest.sons[L].kind == pkTerminal: + # caution! Do not introduce false aliasing here! + case elem.kind + of pkTerminal: + dest.sons[L] = term(dest.sons[L].term & elem.term) + of pkChar: + dest.sons[L] = term(dest.sons[L].term & elem.ch) + else: add(dest, elem) + else: add(dest, elem) + +proc sequence*(a: varargs[TPeg]): TPeg {. + nosideEffect, rtl, extern: "npegs$1".} = + ## constructs a sequence with all the PEGs from `a` + multipleOp(pkSequence, addSequence) + +proc `?`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsOptional".} = + ## constructs an optional for the PEG `a` + if a.kind in {pkOption, pkGreedyRep, pkGreedyAny, pkGreedyRepChar, + pkGreedyRepSet}: + # a* ? --> a* + # a? ? --> a? + result = a + else: + result.kind = pkOption + result.sons = @[a] + +proc `*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyRep".} = + ## constructs a "greedy repetition" for the PEG `a` + case a.kind + of pkGreedyRep, pkGreedyRepChar, pkGreedyRepSet, pkGreedyAny, pkOption: + assert false + # produces endless loop! + of pkChar: + result.kind = pkGreedyRepChar + result.ch = a.ch + of pkCharChoice: + result.kind = pkGreedyRepSet + result.charChoice = a.charChoice # copying a reference suffices! + of pkAny, pkAnyRune: + result.kind = pkGreedyAny + else: + result.kind = pkGreedyRep + result.sons = @[a] + +proc `!*`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsSearch".} = + ## constructs a "search" for the PEG `a` + result.kind = pkSearch + result.sons = @[a] + +proc `!*\`*(a: TPeg): TPeg {.noSideEffect, rtl, + extern: "npgegsCapturedSearch".} = + ## constructs a "captured search" for the PEG `a` + result.kind = pkCapturedSearch + result.sons = @[a] + +proc `+`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsGreedyPosRep".} = + ## constructs a "greedy positive repetition" with the PEG `a` + return sequence(a, *a) + +proc `&`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsAndPredicate".} = + ## constructs an "and predicate" with the PEG `a` + result.kind = pkAndPredicate + result.sons = @[a] + +proc `!`*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsNotPredicate".} = + ## constructs a "not predicate" with the PEG `a` + result.kind = pkNotPredicate + result.sons = @[a] + +proc any*: TPeg {.inline.} = + ## constructs the PEG `any character`:idx: (``.``) + result.kind = pkAny + +proc anyRune*: TPeg {.inline.} = + ## constructs the PEG `any rune`:idx: (``_``) + result.kind = pkAnyRune + +proc newLine*: TPeg {.inline.} = + ## constructs the PEG `newline`:idx: (``\n``) + result.kind = pkNewLine + +proc unicodeLetter*: TPeg {.inline.} = + ## constructs the PEG ``\letter`` which matches any Unicode letter. + result.kind = pkLetter + +proc unicodeLower*: TPeg {.inline.} = + ## constructs the PEG ``\lower`` which matches any Unicode lowercase letter. + result.kind = pkLower + +proc unicodeUpper*: TPeg {.inline.} = + ## constructs the PEG ``\upper`` which matches any Unicode uppercase letter. + result.kind = pkUpper + +proc unicodeTitle*: TPeg {.inline.} = + ## constructs the PEG ``\title`` which matches any Unicode title letter. + result.kind = pkTitle + +proc unicodeWhitespace*: TPeg {.inline.} = + ## constructs the PEG ``\white`` which matches any Unicode + ## whitespace character. + result.kind = pkWhitespace + +proc startAnchor*: TPeg {.inline.} = + ## constructs the PEG ``^`` which matches the start of the input. + result.kind = pkStartAnchor + +proc endAnchor*: TPeg {.inline.} = + ## constructs the PEG ``$`` which matches the end of the input. + result = !any() + +proc capture*(a: TPeg): TPeg {.nosideEffect, rtl, extern: "npegsCapture".} = + ## constructs a capture with the PEG `a` + result.kind = pkCapture + result.sons = @[a] + +proc backref*(index: range[1..MaxSubpatterns]): TPeg {. + nosideEffect, rtl, extern: "npegs$1".} = + ## constructs a back reference of the given `index`. `index` starts counting + ## from 1. + result.kind = pkBackRef + result.index = index-1 + +proc backrefIgnoreCase*(index: range[1..MaxSubpatterns]): TPeg {. + nosideEffect, rtl, extern: "npegs$1".} = + ## constructs a back reference of the given `index`. `index` starts counting + ## from 1. Ignores case for matching. + result.kind = pkBackRefIgnoreCase + result.index = index-1 + +proc backrefIgnoreStyle*(index: range[1..MaxSubpatterns]): TPeg {. + nosideEffect, rtl, extern: "npegs$1".}= + ## constructs a back reference of the given `index`. `index` starts counting + ## from 1. Ignores style for matching. + result.kind = pkBackRefIgnoreStyle + result.index = index-1 + +proc spaceCost(n: TPeg): int = + case n.kind + of pkEmpty: discard + of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar, + pkGreedyRepChar, pkCharChoice, pkGreedyRepSet, + pkAny..pkWhitespace, pkGreedyAny: + result = 1 + of pkNonTerminal: + # we cannot inline a rule with a non-terminal + result = InlineThreshold+1 + else: + for i in 0..n.len-1: + inc(result, spaceCost(n.sons[i])) + if result >= InlineThreshold: break + +proc nonterminal*(n: PNonTerminal): TPeg {. + nosideEffect, rtl, extern: "npegs$1".} = + ## constructs a PEG that consists of the nonterminal symbol + assert n != nil + if ntDeclared in n.flags and spaceCost(n.rule) < InlineThreshold: + when false: echo "inlining symbol: ", n.name + result = n.rule # inlining of rule enables better optimizations + else: + result.kind = pkNonTerminal + result.nt = n + +proc newNonTerminal*(name: string, line, column: int): PNonTerminal {. + nosideEffect, rtl, extern: "npegs$1".} = + ## constructs a nonterminal symbol + new(result) + result.name = name + result.line = line + result.col = column + +template letters*: expr = + ## expands to ``charset({'A'..'Z', 'a'..'z'})`` + charSet({'A'..'Z', 'a'..'z'}) + +template digits*: expr = + ## expands to ``charset({'0'..'9'})`` + charSet({'0'..'9'}) + +template whitespace*: expr = + ## expands to ``charset({' ', '\9'..'\13'})`` + charSet({' ', '\9'..'\13'}) + +template identChars*: expr = + ## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})`` + charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}) + +template identStartChars*: expr = + ## expands to ``charset({'A'..'Z', 'a'..'z', '_'})`` + charSet({'a'..'z', 'A'..'Z', '_'}) + +template ident*: expr = + ## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier + sequence(charSet({'a'..'z', 'A'..'Z', '_'}), + *charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})) + +template natural*: expr = + ## same as ``\d+`` + +digits + +# ------------------------- debugging ----------------------------------------- + +proc esc(c: char, reserved = {'\0'..'\255'}): string = + case c + of '\b': result = "\\b" + of '\t': result = "\\t" + of '\c': result = "\\c" + of '\L': result = "\\l" + of '\v': result = "\\v" + of '\f': result = "\\f" + of '\e': result = "\\e" + of '\a': result = "\\a" + of '\\': result = "\\\\" + of 'a'..'z', 'A'..'Z', '0'..'9', '_': result = $c + elif c < ' ' or c >= '\128': result = '\\' & $ord(c) + elif c in reserved: result = '\\' & c + else: result = $c + +proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'" + +proc singleQuoteEsc(str: string): string = + result = "'" + for c in items(str): add result, esc(c, {'\''}) + add result, '\'' + +proc charSetEscAux(cc: set[char]): string = + const reserved = {'^', '-', ']'} + result = "" + var c1 = 0 + while c1 <= 0xff: + if chr(c1) in cc: + var c2 = c1 + while c2 < 0xff and chr(succ(c2)) in cc: inc(c2) + if c1 == c2: + add result, esc(chr(c1), reserved) + elif c2 == succ(c1): + add result, esc(chr(c1), reserved) & esc(chr(c2), reserved) + else: + add result, esc(chr(c1), reserved) & '-' & esc(chr(c2), reserved) + c1 = c2 + inc(c1) + +proc charSetEsc(cc: set[char]): string = + if card(cc) >= 128+64: + result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']' + else: + result = '[' & charSetEscAux(cc) & ']' + +proc toStrAux(r: TPeg, res: var string) = + case r.kind + of pkEmpty: add(res, "()") + of pkAny: add(res, '.') + of pkAnyRune: add(res, '_') + of pkLetter: add(res, "\\letter") + of pkLower: add(res, "\\lower") + of pkUpper: add(res, "\\upper") + of pkTitle: add(res, "\\title") + of pkWhitespace: add(res, "\\white") + + of pkNewLine: add(res, "\\n") + of pkTerminal: add(res, singleQuoteEsc(r.term)) + of pkTerminalIgnoreCase: + add(res, 'i') + add(res, singleQuoteEsc(r.term)) + of pkTerminalIgnoreStyle: + add(res, 'y') + add(res, singleQuoteEsc(r.term)) + of pkChar: add(res, singleQuoteEsc(r.ch)) + of pkCharChoice: add(res, charSetEsc(r.charChoice[])) + of pkNonTerminal: add(res, r.nt.name) + of pkSequence: + add(res, '(') + toStrAux(r.sons[0], res) + for i in 1 .. high(r.sons): + add(res, ' ') + toStrAux(r.sons[i], res) + add(res, ')') + of pkOrderedChoice: + add(res, '(') + toStrAux(r.sons[0], res) + for i in 1 .. high(r.sons): + add(res, " / ") + toStrAux(r.sons[i], res) + add(res, ')') + of pkGreedyRep: + toStrAux(r.sons[0], res) + add(res, '*') + of pkGreedyRepChar: + add(res, singleQuoteEsc(r.ch)) + add(res, '*') + of pkGreedyRepSet: + add(res, charSetEsc(r.charChoice[])) + add(res, '*') + of pkGreedyAny: + add(res, ".*") + of pkOption: + toStrAux(r.sons[0], res) + add(res, '?') + of pkAndPredicate: + add(res, '&') + toStrAux(r.sons[0], res) + of pkNotPredicate: + add(res, '!') + toStrAux(r.sons[0], res) + of pkSearch: + add(res, '@') + toStrAux(r.sons[0], res) + of pkCapturedSearch: + add(res, "{@}") + toStrAux(r.sons[0], res) + of pkCapture: + add(res, '{') + toStrAux(r.sons[0], res) + add(res, '}') + of pkBackRef: + add(res, '$') + add(res, $r.index) + of pkBackRefIgnoreCase: + add(res, "i$") + add(res, $r.index) + of pkBackRefIgnoreStyle: + add(res, "y$") + add(res, $r.index) + of pkRule: + toStrAux(r.sons[0], res) + add(res, " <- ") + toStrAux(r.sons[1], res) + of pkList: + for i in 0 .. high(r.sons): + toStrAux(r.sons[i], res) + add(res, "\n") + of pkStartAnchor: + add(res, '^') + +proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} = + ## converts a PEG to its string representation + result = "" + toStrAux(r, result) + +# --------------------- core engine ------------------------------------------- + +type + Captures* = object ## contains the captured substrings. + matches: array[0..MaxSubpatterns-1, tuple[first, last: int]] + ml: int + origStart: int + +{.deprecated: [TCaptures: Captures].} + +proc bounds*(c: Captures, + i: range[0..MaxSubpatterns-1]): tuple[first, last: int] = + ## returns the bounds ``[first..last]`` of the `i`'th capture. + result = c.matches[i] + +when not useUnicode: + type + TRune = char + template fastRuneAt(s, i, ch: expr) = + ch = s[i] + inc(i) + template runeLenAt(s, i: expr): expr = 1 + + proc isAlpha(a: char): bool {.inline.} = return a in {'a'..'z','A'..'Z'} + proc isUpper(a: char): bool {.inline.} = return a in {'A'..'Z'} + proc isLower(a: char): bool {.inline.} = return a in {'a'..'z'} + proc isTitle(a: char): bool {.inline.} = return false + proc isWhiteSpace(a: char): bool {.inline.} = return a in {' ', '\9'..'\13'} + +proc rawMatch*(s: string, p: TPeg, start: int, c: var Captures): int {. + nosideEffect, rtl, extern: "npegs$1".} = + ## low-level matching proc that implements the PEG interpreter. Use this + ## for maximum efficiency (every other PEG operation ends up calling this + ## proc). + ## Returns -1 if it does not match, else the length of the match + case p.kind + of pkEmpty: result = 0 # match of length 0 + of pkAny: + if s[start] != '\0': result = 1 + else: result = -1 + of pkAnyRune: + if s[start] != '\0': + result = runeLenAt(s, start) + else: + result = -1 + of pkLetter: + if s[start] != '\0': + var a: Rune + result = start + fastRuneAt(s, result, a) + if isAlpha(a): dec(result, start) + else: result = -1 + else: + result = -1 + of pkLower: + if s[start] != '\0': + var a: Rune + result = start + fastRuneAt(s, result, a) + if isLower(a): dec(result, start) + else: result = -1 + else: + result = -1 + of pkUpper: + if s[start] != '\0': + var a: Rune + result = start + fastRuneAt(s, result, a) + if isUpper(a): dec(result, start) + else: result = -1 + else: + result = -1 + of pkTitle: + if s[start] != '\0': + var a: Rune + result = start + fastRuneAt(s, result, a) + if isTitle(a): dec(result, start) + else: result = -1 + else: + result = -1 + of pkWhitespace: + if s[start] != '\0': + var a: Rune + result = start + fastRuneAt(s, result, a) + if isWhiteSpace(a): dec(result, start) + else: result = -1 + else: + result = -1 + of pkGreedyAny: + result = len(s) - start + of pkNewLine: + if s[start] == '\L': result = 1 + elif s[start] == '\C': + if s[start+1] == '\L': result = 2 + else: result = 1 + else: result = -1 + of pkTerminal: + result = len(p.term) + for i in 0..result-1: + if p.term[i] != s[start+i]: + result = -1 + break + of pkTerminalIgnoreCase: + var + i = 0 + a, b: Rune + result = start + while i < len(p.term): + fastRuneAt(p.term, i, a) + fastRuneAt(s, result, b) + if toLower(a) != toLower(b): + result = -1 + break + dec(result, start) + of pkTerminalIgnoreStyle: + var + i = 0 + a, b: Rune + result = start + while i < len(p.term): + while true: + fastRuneAt(p.term, i, a) + if a != Rune('_'): break + while true: + fastRuneAt(s, result, b) + if b != Rune('_'): break + if toLower(a) != toLower(b): + result = -1 + break + dec(result, start) + of pkChar: + if p.ch == s[start]: result = 1 + else: result = -1 + of pkCharChoice: + if contains(p.charChoice[], s[start]): result = 1 + else: result = -1 + of pkNonTerminal: + var oldMl = c.ml + when false: echo "enter: ", p.nt.name + result = rawMatch(s, p.nt.rule, start, c) + when false: echo "leave: ", p.nt.name + if result < 0: c.ml = oldMl + of pkSequence: + var oldMl = c.ml + result = 0 + for i in 0..high(p.sons): + var x = rawMatch(s, p.sons[i], start+result, c) + if x < 0: + c.ml = oldMl + result = -1 + break + else: inc(result, x) + of pkOrderedChoice: + var oldMl = c.ml + for i in 0..high(p.sons): + result = rawMatch(s, p.sons[i], start, c) + if result >= 0: break + c.ml = oldMl + of pkSearch: + var oldMl = c.ml + result = 0 + while start+result < s.len: + var x = rawMatch(s, p.sons[0], start+result, c) + if x >= 0: + inc(result, x) + return + inc(result) + result = -1 + c.ml = oldMl + of pkCapturedSearch: + var idx = c.ml # reserve a slot for the subpattern + inc(c.ml) + result = 0 + while start+result < s.len: + var x = rawMatch(s, p.sons[0], start+result, c) + if x >= 0: + if idx < MaxSubpatterns: + c.matches[idx] = (start, start+result-1) + #else: silently ignore the capture + inc(result, x) + return + inc(result) + result = -1 + c.ml = idx + of pkGreedyRep: + result = 0 + while true: + var x = rawMatch(s, p.sons[0], start+result, c) + # if x == 0, we have an endless loop; so the correct behaviour would be + # not to break. But endless loops can be easily introduced: + # ``(comment / \w*)*`` is such an example. Breaking for x == 0 does the + # expected thing in this case. + if x <= 0: break + inc(result, x) + of pkGreedyRepChar: + result = 0 + var ch = p.ch + while ch == s[start+result]: inc(result) + of pkGreedyRepSet: + result = 0 + while contains(p.charChoice[], s[start+result]): inc(result) + of pkOption: + result = max(0, rawMatch(s, p.sons[0], start, c)) + of pkAndPredicate: + var oldMl = c.ml + result = rawMatch(s, p.sons[0], start, c) + if result >= 0: result = 0 # do not consume anything + else: c.ml = oldMl + of pkNotPredicate: + var oldMl = c.ml + result = rawMatch(s, p.sons[0], start, c) + if result < 0: result = 0 + else: + c.ml = oldMl + result = -1 + of pkCapture: + var idx = c.ml # reserve a slot for the subpattern + inc(c.ml) + result = rawMatch(s, p.sons[0], start, c) + if result >= 0: + if idx < MaxSubpatterns: + c.matches[idx] = (start, start+result-1) + #else: silently ignore the capture + else: + c.ml = idx + of pkBackRef..pkBackRefIgnoreStyle: + if p.index >= c.ml: return -1 + var (a, b) = c.matches[p.index] + var n: TPeg + n.kind = succ(pkTerminal, ord(p.kind)-ord(pkBackRef)) + n.term = s.substr(a, b) + result = rawMatch(s, n, start, c) + of pkStartAnchor: + if c.origStart == start: result = 0 + else: result = -1 + of pkRule, pkList: assert false + +template fillMatches(s, caps, c: expr) = + for k in 0..c.ml-1: + caps[k] = substr(s, c.matches[k][0], c.matches[k][1]) + +proc match*(s: string, pattern: TPeg, matches: var openArray[string], + start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} = + ## returns ``true`` if ``s[start..]`` matches the ``pattern`` and + ## the captured substrings in the array ``matches``. If it does not + ## match, nothing is written into ``matches`` and ``false`` is + ## returned. + var c: Captures + c.origStart = start + result = rawMatch(s, pattern, start, c) == len(s) - start + if result: fillMatches(s, matches, c) + +proc match*(s: string, pattern: TPeg, + start = 0): bool {.nosideEffect, rtl, extern: "npegs$1".} = + ## returns ``true`` if ``s`` matches the ``pattern`` beginning from ``start``. + var c: Captures + c.origStart = start + result = rawMatch(s, pattern, start, c) == len(s)-start + +proc matchLen*(s: string, pattern: TPeg, matches: var openArray[string], + start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} = + ## the same as ``match``, but it returns the length of the match, + ## if there is no match, -1 is returned. Note that a match length + ## of zero can happen. It's possible that a suffix of `s` remains + ## that does not belong to the match. + var c: Captures + c.origStart = start + result = rawMatch(s, pattern, start, c) + if result >= 0: fillMatches(s, matches, c) + +proc matchLen*(s: string, pattern: TPeg, + start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} = + ## the same as ``match``, but it returns the length of the match, + ## if there is no match, -1 is returned. Note that a match length + ## of zero can happen. It's possible that a suffix of `s` remains + ## that does not belong to the match. + var c: Captures + c.origStart = start + result = rawMatch(s, pattern, start, c) + +proc find*(s: string, pattern: TPeg, matches: var openArray[string], + start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} = + ## returns the starting position of ``pattern`` in ``s`` and the captured + ## substrings in the array ``matches``. If it does not match, nothing + ## is written into ``matches`` and -1 is returned. + var c: Captures + c.origStart = start + for i in start .. s.len-1: + c.ml = 0 + if rawMatch(s, pattern, i, c) >= 0: + fillMatches(s, matches, c) + return i + return -1 + # could also use the pattern here: (!P .)* P + +proc findBounds*(s: string, pattern: TPeg, matches: var openArray[string], + start = 0): tuple[first, last: int] {. + nosideEffect, rtl, extern: "npegs$1Capture".} = + ## returns the starting position and end position of ``pattern`` in ``s`` + ## and the captured + ## substrings in the array ``matches``. If it does not match, nothing + ## is written into ``matches`` and (-1,0) is returned. + var c: Captures + c.origStart = start + for i in start .. s.len-1: + c.ml = 0 + var L = rawMatch(s, pattern, i, c) + if L >= 0: + fillMatches(s, matches, c) + return (i, i+L-1) + return (-1, 0) + +proc find*(s: string, pattern: TPeg, + start = 0): int {.nosideEffect, rtl, extern: "npegs$1".} = + ## returns the starting position of ``pattern`` in ``s``. If it does not + ## match, -1 is returned. + var c: Captures + c.origStart = start + for i in start .. s.len-1: + if rawMatch(s, pattern, i, c) >= 0: return i + return -1 + +iterator findAll*(s: string, pattern: TPeg, start = 0): string = + ## yields all matching *substrings* of `s` that match `pattern`. + var c: Captures + c.origStart = start + var i = start + while i < s.len: + c.ml = 0 + var L = rawMatch(s, pattern, i, c) + if L < 0: + inc(i, 1) + else: + yield substr(s, i, i+L-1) + inc(i, L) + +proc findAll*(s: string, pattern: TPeg, start = 0): seq[string] {. + nosideEffect, rtl, extern: "npegs$1".} = + ## returns all matching *substrings* of `s` that match `pattern`. + ## If it does not match, @[] is returned. + accumulateResult(findAll(s, pattern, start)) + +when not defined(nimhygiene): + {.pragma: inject.} + +template `=~`*(s: string, pattern: TPeg): bool = + ## This calls ``match`` with an implicit declared ``matches`` array that + ## can be used in the scope of the ``=~`` call: + ## + ## .. code-block:: nim + ## + ## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}": + ## # matches a key=value pair: + ## echo("Key: ", matches[0]) + ## echo("Value: ", matches[1]) + ## elif line =~ peg"\s*{'#'.*}": + ## # matches a comment + ## # note that the implicit ``matches`` array is different from the + ## # ``matches`` array of the first branch + ## echo("comment: ", matches[0]) + ## else: + ## echo("syntax error") + ## + bind MaxSubpatterns + when not declaredInScope(matches): + var matches {.inject.}: array[0..MaxSubpatterns-1, string] + match(s, pattern, matches) + +# ------------------------- more string handling ------------------------------ + +proc contains*(s: string, pattern: TPeg, start = 0): bool {. + nosideEffect, rtl, extern: "npegs$1".} = + ## same as ``find(s, pattern, start) >= 0`` + return find(s, pattern, start) >= 0 + +proc contains*(s: string, pattern: TPeg, matches: var openArray[string], + start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} = + ## same as ``find(s, pattern, matches, start) >= 0`` + return find(s, pattern, matches, start) >= 0 + +proc startsWith*(s: string, prefix: TPeg, start = 0): bool {. + nosideEffect, rtl, extern: "npegs$1".} = + ## returns true if `s` starts with the pattern `prefix` + result = matchLen(s, prefix, start) >= 0 + +proc endsWith*(s: string, suffix: TPeg, start = 0): bool {. + nosideEffect, rtl, extern: "npegs$1".} = + ## returns true if `s` ends with the pattern `prefix` + var c: Captures + c.origStart = start + for i in start .. s.len-1: + if rawMatch(s, suffix, i, c) == s.len - i: return true + +proc replacef*(s: string, sub: TPeg, by: string): string {. + nosideEffect, rtl, extern: "npegs$1".} = + ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` + ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: + ## + ## .. code-block:: nim + ## "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") + ## + ## Results in: + ## + ## .. code-block:: nim + ## + ## "var1<-keykey; val2<-key2key2" + result = "" + var i = 0 + var caps: array[0..MaxSubpatterns-1, string] + var c: Captures + while i < s.len: + c.ml = 0 + var x = rawMatch(s, sub, i, c) + if x <= 0: + add(result, s[i]) + inc(i) + else: + fillMatches(s, caps, c) + addf(result, by, caps) + inc(i, x) + add(result, substr(s, i)) + +proc replace*(s: string, sub: TPeg, by = ""): string {. + nosideEffect, rtl, extern: "npegs$1".} = + ## Replaces `sub` in `s` by the string `by`. Captures cannot be accessed + ## in `by`. + result = "" + var i = 0 + var c: Captures + while i < s.len: + var x = rawMatch(s, sub, i, c) + if x <= 0: + add(result, s[i]) + inc(i) + else: + add(result, by) + inc(i, x) + add(result, substr(s, i)) + +proc parallelReplace*(s: string, subs: varargs[ + tuple[pattern: TPeg, repl: string]]): string {. + nosideEffect, rtl, extern: "npegs$1".} = + ## Returns a modified copy of `s` with the substitutions in `subs` + ## applied in parallel. + result = "" + var i = 0 + var c: Captures + var caps: array[0..MaxSubpatterns-1, string] + while i < s.len: + block searchSubs: + for j in 0..high(subs): + c.ml = 0 + var x = rawMatch(s, subs[j][0], i, c) + if x > 0: + fillMatches(s, caps, c) + addf(result, subs[j][1], caps) + inc(i, x) + break searchSubs + add(result, s[i]) + inc(i) + # copy the rest: + add(result, substr(s, i)) + +proc transformFile*(infile, outfile: string, + subs: varargs[tuple[pattern: TPeg, repl: string]]) {. + rtl, extern: "npegs$1".} = + ## reads in the file `infile`, performs a parallel replacement (calls + ## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an + ## error occurs. This is supposed to be used for quick scripting. + var x = readFile(infile).string + writeFile(outfile, x.parallelReplace(subs)) + +iterator split*(s: string, sep: TPeg): string = + ## Splits the string `s` into substrings. + ## + ## Substrings are separated by the PEG `sep`. + ## Examples: + ## + ## .. code-block:: nim + ## for word in split("00232this02939is39an22example111", peg"\d+"): + ## writeln(stdout, word) + ## + ## Results in: + ## + ## .. code-block:: nim + ## "this" + ## "is" + ## "an" + ## "example" + ## + var c: Captures + var + first = 0 + last = 0 + while last < len(s): + c.ml = 0 + var x = rawMatch(s, sep, last, c) + if x > 0: inc(last, x) + first = last + while last < len(s): + inc(last) + c.ml = 0 + x = rawMatch(s, sep, last, c) + if x > 0: break + if first < last: + yield substr(s, first, last-1) + +proc split*(s: string, sep: TPeg): seq[string] {. + nosideEffect, rtl, extern: "npegs$1".} = + ## Splits the string `s` into substrings. + accumulateResult(split(s, sep)) + +# ------------------- scanner ------------------------------------------------- + +type + TModifier = enum + modNone, + modVerbatim, + modIgnoreCase, + modIgnoreStyle + TTokKind = enum ## enumeration of all tokens + tkInvalid, ## invalid token + tkEof, ## end of file reached + tkAny, ## . + tkAnyRune, ## _ + tkIdentifier, ## abc + tkStringLit, ## "abc" or 'abc' + tkCharSet, ## [^A-Z] + tkParLe, ## '(' + tkParRi, ## ')' + tkCurlyLe, ## '{' + tkCurlyRi, ## '}' + tkCurlyAt, ## '{@}' + tkArrow, ## '<-' + tkBar, ## '/' + tkStar, ## '*' + tkPlus, ## '+' + tkAmp, ## '&' + tkNot, ## '!' + tkOption, ## '?' + tkAt, ## '@' + tkBuiltin, ## \identifier + tkEscaped, ## \\ + tkBackref, ## '$' + tkDollar, ## '$' + tkHat ## '^' + + TToken {.final.} = object ## a token + kind: TTokKind ## the type of the token + modifier: TModifier + literal: string ## the parsed (string) literal + charset: set[char] ## if kind == tkCharSet + index: int ## if kind == tkBackref + + PegLexer {.inheritable.} = object ## the lexer object. + bufpos: int ## the current position within the buffer + buf: cstring ## the buffer itself + lineNumber: int ## the current line number + lineStart: int ## index of last line start in buffer + colOffset: int ## column to add + filename: string + +const + tokKindToStr: array[TTokKind, string] = [ + "invalid", "[EOF]", ".", "_", "identifier", "string literal", + "character set", "(", ")", "{", "}", "{@}", + "<-", "/", "*", "+", "&", "!", "?", + "@", "built-in", "escaped", "$", "$", "^" + ] + +proc handleCR(L: var PegLexer, pos: int): int = + assert(L.buf[pos] == '\c') + inc(L.lineNumber) + result = pos+1 + if L.buf[result] == '\L': inc(result) + L.lineStart = result + +proc handleLF(L: var PegLexer, pos: int): int = + assert(L.buf[pos] == '\L') + inc(L.lineNumber) + result = pos+1 + L.lineStart = result + +proc init(L: var PegLexer, input, filename: string, line = 1, col = 0) = + L.buf = input + L.bufpos = 0 + L.lineNumber = line + L.colOffset = col + L.lineStart = 0 + L.filename = filename + +proc getColumn(L: PegLexer): int {.inline.} = + result = abs(L.bufpos - L.lineStart) + L.colOffset + +proc getLine(L: PegLexer): int {.inline.} = + result = L.lineNumber + +proc errorStr(L: PegLexer, msg: string, line = -1, col = -1): string = + var line = if line < 0: getLine(L) else: line + var col = if col < 0: getColumn(L) else: col + result = "$1($2, $3) Error: $4" % [L.filename, $line, $col, msg] + +proc handleHexChar(c: var PegLexer, xi: var int) = + case c.buf[c.bufpos] + of '0'..'9': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('0')) + inc(c.bufpos) + of 'a'..'f': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('a') + 10) + inc(c.bufpos) + of 'A'..'F': + xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10) + inc(c.bufpos) + else: discard + +proc getEscapedChar(c: var PegLexer, tok: var TToken) = + inc(c.bufpos) + case c.buf[c.bufpos] + of 'r', 'R', 'c', 'C': + add(tok.literal, '\c') + inc(c.bufpos) + of 'l', 'L': + add(tok.literal, '\L') + inc(c.bufpos) + of 'f', 'F': + add(tok.literal, '\f') + inc(c.bufpos) + of 'e', 'E': + add(tok.literal, '\e') + inc(c.bufpos) + of 'a', 'A': + add(tok.literal, '\a') + inc(c.bufpos) + of 'b', 'B': + add(tok.literal, '\b') + inc(c.bufpos) + of 'v', 'V': + add(tok.literal, '\v') + inc(c.bufpos) + of 't', 'T': + add(tok.literal, '\t') + inc(c.bufpos) + of 'x', 'X': + inc(c.bufpos) + var xi = 0 + handleHexChar(c, xi) + handleHexChar(c, xi) + if xi == 0: tok.kind = tkInvalid + else: add(tok.literal, chr(xi)) + of '0'..'9': + var val = ord(c.buf[c.bufpos]) - ord('0') + inc(c.bufpos) + var i = 1 + while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}): + val = val * 10 + ord(c.buf[c.bufpos]) - ord('0') + inc(c.bufpos) + inc(i) + if val > 0 and val <= 255: add(tok.literal, chr(val)) + else: tok.kind = tkInvalid + of '\0'..'\31': + tok.kind = tkInvalid + elif c.buf[c.bufpos] in strutils.Letters: + tok.kind = tkInvalid + else: + add(tok.literal, c.buf[c.bufpos]) + inc(c.bufpos) + +proc skip(c: var PegLexer) = + var pos = c.bufpos + var buf = c.buf + while true: + case buf[pos] + of ' ', '\t': + inc(pos) + of '#': + while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos) + of '\c': + pos = handleCR(c, pos) + buf = c.buf + of '\L': + pos = handleLF(c, pos) + buf = c.buf + else: + break # EndOfFile also leaves the loop + c.bufpos = pos + +proc getString(c: var PegLexer, tok: var TToken) = + tok.kind = tkStringLit + var pos = c.bufpos + 1 + var buf = c.buf + var quote = buf[pos-1] + while true: + case buf[pos] + of '\\': + c.bufpos = pos + getEscapedChar(c, tok) + pos = c.bufpos + of '\c', '\L', '\0': + tok.kind = tkInvalid + break + elif buf[pos] == quote: + inc(pos) + break + else: + add(tok.literal, buf[pos]) + inc(pos) + c.bufpos = pos + +proc getDollar(c: var PegLexer, tok: var TToken) = + var pos = c.bufpos + 1 + var buf = c.buf + if buf[pos] in {'0'..'9'}: + tok.kind = tkBackref + tok.index = 0 + while buf[pos] in {'0'..'9'}: + tok.index = tok.index * 10 + ord(buf[pos]) - ord('0') + inc(pos) + else: + tok.kind = tkDollar + c.bufpos = pos + +proc getCharSet(c: var PegLexer, tok: var TToken) = + tok.kind = tkCharSet + tok.charset = {} + var pos = c.bufpos + 1 + var buf = c.buf + var caret = false + if buf[pos] == '^': + inc(pos) + caret = true + while true: + var ch: char + case buf[pos] + of ']': + inc(pos) + break + of '\\': + c.bufpos = pos + getEscapedChar(c, tok) + pos = c.bufpos + ch = tok.literal[tok.literal.len-1] + of '\C', '\L', '\0': + tok.kind = tkInvalid + break + else: + ch = buf[pos] + inc(pos) + incl(tok.charset, ch) + if buf[pos] == '-': + if buf[pos+1] == ']': + incl(tok.charset, '-') + inc(pos) + else: + inc(pos) + var ch2: char + case buf[pos] + of '\\': + c.bufpos = pos + getEscapedChar(c, tok) + pos = c.bufpos + ch2 = tok.literal[tok.literal.len-1] + of '\C', '\L', '\0': + tok.kind = tkInvalid + break + else: + ch2 = buf[pos] + inc(pos) + for i in ord(ch)+1 .. ord(ch2): + incl(tok.charset, chr(i)) + c.bufpos = pos + if caret: tok.charset = {'\1'..'\xFF'} - tok.charset + +proc getSymbol(c: var PegLexer, tok: var TToken) = + var pos = c.bufpos + var buf = c.buf + while true: + add(tok.literal, buf[pos]) + inc(pos) + if buf[pos] notin strutils.IdentChars: break + c.bufpos = pos + tok.kind = tkIdentifier + +proc getBuiltin(c: var PegLexer, tok: var TToken) = + if c.buf[c.bufpos+1] in strutils.Letters: + inc(c.bufpos) + getSymbol(c, tok) + tok.kind = tkBuiltin + else: + tok.kind = tkEscaped + getEscapedChar(c, tok) # may set tok.kind to tkInvalid + +proc getTok(c: var PegLexer, tok: var TToken) = + tok.kind = tkInvalid + tok.modifier = modNone + setLen(tok.literal, 0) + skip(c) + case c.buf[c.bufpos] + of '{': + inc(c.bufpos) + if c.buf[c.bufpos] == '@' and c.buf[c.bufpos+1] == '}': + tok.kind = tkCurlyAt + inc(c.bufpos, 2) + add(tok.literal, "{@}") + else: + tok.kind = tkCurlyLe + add(tok.literal, '{') + of '}': + tok.kind = tkCurlyRi + inc(c.bufpos) + add(tok.literal, '}') + of '[': + getCharSet(c, tok) + of '(': + tok.kind = tkParLe + inc(c.bufpos) + add(tok.literal, '(') + of ')': + tok.kind = tkParRi + inc(c.bufpos) + add(tok.literal, ')') + of '.': + tok.kind = tkAny + inc(c.bufpos) + add(tok.literal, '.') + of '_': + tok.kind = tkAnyRune + inc(c.bufpos) + add(tok.literal, '_') + of '\\': + getBuiltin(c, tok) + of '\'', '"': getString(c, tok) + of '$': getDollar(c, tok) + of '\0': + tok.kind = tkEof + tok.literal = "[EOF]" + of 'a'..'z', 'A'..'Z', '\128'..'\255': + getSymbol(c, tok) + if c.buf[c.bufpos] in {'\'', '"'} or + c.buf[c.bufpos] == '$' and c.buf[c.bufpos+1] in {'0'..'9'}: + case tok.literal + of "i": tok.modifier = modIgnoreCase + of "y": tok.modifier = modIgnoreStyle + of "v": tok.modifier = modVerbatim + else: discard + setLen(tok.literal, 0) + if c.buf[c.bufpos] == '$': + getDollar(c, tok) + else: + getString(c, tok) + if tok.modifier == modNone: tok.kind = tkInvalid + of '+': + tok.kind = tkPlus + inc(c.bufpos) + add(tok.literal, '+') + of '*': + tok.kind = tkStar + inc(c.bufpos) + add(tok.literal, '+') + of '<': + if c.buf[c.bufpos+1] == '-': + inc(c.bufpos, 2) + tok.kind = tkArrow + add(tok.literal, "<-") + else: + add(tok.literal, '<') + of '/': + tok.kind = tkBar + inc(c.bufpos) + add(tok.literal, '/') + of '?': + tok.kind = tkOption + inc(c.bufpos) + add(tok.literal, '?') + of '!': + tok.kind = tkNot + inc(c.bufpos) + add(tok.literal, '!') + of '&': + tok.kind = tkAmp + inc(c.bufpos) + add(tok.literal, '!') + of '@': + tok.kind = tkAt + inc(c.bufpos) + add(tok.literal, '@') + if c.buf[c.bufpos] == '@': + tok.kind = tkCurlyAt + inc(c.bufpos) + add(tok.literal, '@') + of '^': + tok.kind = tkHat + inc(c.bufpos) + add(tok.literal, '^') + else: + add(tok.literal, c.buf[c.bufpos]) + inc(c.bufpos) + +proc arrowIsNextTok(c: PegLexer): bool = + # the only look ahead we need + var pos = c.bufpos + while c.buf[pos] in {'\t', ' '}: inc(pos) + result = c.buf[pos] == '<' and c.buf[pos+1] == '-' + +# ----------------------------- parser ---------------------------------------- + +type + EInvalidPeg* = object of ValueError ## raised if an invalid + ## PEG has been detected + PegParser = object of PegLexer ## the PEG parser object + tok: TToken + nonterms: seq[PNonTerminal] + modifier: TModifier + captures: int + identIsVerbatim: bool + skip: TPeg + +proc pegError(p: PegParser, msg: string, line = -1, col = -1) = + var e: ref EInvalidPeg + new(e) + e.msg = errorStr(p, msg, line, col) + raise e + +proc getTok(p: var PegParser) = + getTok(p, p.tok) + if p.tok.kind == tkInvalid: pegError(p, "invalid token") + +proc eat(p: var PegParser, kind: TTokKind) = + if p.tok.kind == kind: getTok(p) + else: pegError(p, tokKindToStr[kind] & " expected") + +proc parseExpr(p: var PegParser): TPeg + +proc getNonTerminal(p: var PegParser, name: string): PNonTerminal = + for i in 0..high(p.nonterms): + result = p.nonterms[i] + if cmpIgnoreStyle(result.name, name) == 0: return + # forward reference: + result = newNonTerminal(name, getLine(p), getColumn(p)) + add(p.nonterms, result) + +proc modifiedTerm(s: string, m: TModifier): TPeg = + case m + of modNone, modVerbatim: result = term(s) + of modIgnoreCase: result = termIgnoreCase(s) + of modIgnoreStyle: result = termIgnoreStyle(s) + +proc modifiedBackref(s: int, m: TModifier): TPeg = + case m + of modNone, modVerbatim: result = backref(s) + of modIgnoreCase: result = backrefIgnoreCase(s) + of modIgnoreStyle: result = backrefIgnoreStyle(s) + +proc builtin(p: var PegParser): TPeg = + # do not use "y", "skip" or "i" as these would be ambiguous + case p.tok.literal + of "n": result = newLine() + of "d": result = charSet({'0'..'9'}) + of "D": result = charSet({'\1'..'\xff'} - {'0'..'9'}) + of "s": result = charSet({' ', '\9'..'\13'}) + of "S": result = charSet({'\1'..'\xff'} - {' ', '\9'..'\13'}) + of "w": result = charSet({'a'..'z', 'A'..'Z', '_', '0'..'9'}) + of "W": result = charSet({'\1'..'\xff'} - {'a'..'z','A'..'Z','_','0'..'9'}) + of "a": result = charSet({'a'..'z', 'A'..'Z'}) + of "A": result = charSet({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'}) + of "ident": result = pegs.ident + of "letter": result = unicodeLetter() + of "upper": result = unicodeUpper() + of "lower": result = unicodeLower() + of "title": result = unicodeTitle() + of "white": result = unicodeWhitespace() + else: pegError(p, "unknown built-in: " & p.tok.literal) + +proc token(terminal: TPeg, p: PegParser): TPeg = + if p.skip.kind == pkEmpty: result = terminal + else: result = sequence(p.skip, terminal) + +proc primary(p: var PegParser): TPeg = + case p.tok.kind + of tkAmp: + getTok(p) + return &primary(p) + of tkNot: + getTok(p) + return !primary(p) + of tkAt: + getTok(p) + return !*primary(p) + of tkCurlyAt: + getTok(p) + return !*\primary(p).token(p) + else: discard + case p.tok.kind + of tkIdentifier: + if p.identIsVerbatim: + var m = p.tok.modifier + if m == modNone: m = p.modifier + result = modifiedTerm(p.tok.literal, m).token(p) + getTok(p) + elif not arrowIsNextTok(p): + var nt = getNonTerminal(p, p.tok.literal) + incl(nt.flags, ntUsed) + result = nonterminal(nt).token(p) + getTok(p) + else: + pegError(p, "expression expected, but found: " & p.tok.literal) + of tkStringLit: + var m = p.tok.modifier + if m == modNone: m = p.modifier + result = modifiedTerm(p.tok.literal, m).token(p) + getTok(p) + of tkCharSet: + if '\0' in p.tok.charset: + pegError(p, "binary zero ('\\0') not allowed in character class") + result = charSet(p.tok.charset).token(p) + getTok(p) + of tkParLe: + getTok(p) + result = parseExpr(p) + eat(p, tkParRi) + of tkCurlyLe: + getTok(p) + result = capture(parseExpr(p)).token(p) + eat(p, tkCurlyRi) + inc(p.captures) + of tkAny: + result = any().token(p) + getTok(p) + of tkAnyRune: + result = anyRune().token(p) + getTok(p) + of tkBuiltin: + result = builtin(p).token(p) + getTok(p) + of tkEscaped: + result = term(p.tok.literal[0]).token(p) + getTok(p) + of tkDollar: + result = endAnchor() + getTok(p) + of tkHat: + result = startAnchor() + getTok(p) + of tkBackref: + var m = p.tok.modifier + if m == modNone: m = p.modifier + result = modifiedBackref(p.tok.index, m).token(p) + if p.tok.index < 0 or p.tok.index > p.captures: + pegError(p, "invalid back reference index: " & $p.tok.index) + getTok(p) + else: + pegError(p, "expression expected, but found: " & p.tok.literal) + getTok(p) # we must consume a token here to prevent endless loops! + while true: + case p.tok.kind + of tkOption: + result = ?result + getTok(p) + of tkStar: + result = *result + getTok(p) + of tkPlus: + result = +result + getTok(p) + else: break + +proc seqExpr(p: var PegParser): TPeg = + result = primary(p) + while true: + case p.tok.kind + of tkAmp, tkNot, tkAt, tkStringLit, tkCharSet, tkParLe, tkCurlyLe, + tkAny, tkAnyRune, tkBuiltin, tkEscaped, tkDollar, tkBackref, + tkHat, tkCurlyAt: + result = sequence(result, primary(p)) + of tkIdentifier: + if not arrowIsNextTok(p): + result = sequence(result, primary(p)) + else: break + else: break + +proc parseExpr(p: var PegParser): TPeg = + result = seqExpr(p) + while p.tok.kind == tkBar: + getTok(p) + result = result / seqExpr(p) + +proc parseRule(p: var PegParser): PNonTerminal = + if p.tok.kind == tkIdentifier and arrowIsNextTok(p): + result = getNonTerminal(p, p.tok.literal) + if ntDeclared in result.flags: + pegError(p, "attempt to redefine: " & result.name) + result.line = getLine(p) + result.col = getColumn(p) + getTok(p) + eat(p, tkArrow) + result.rule = parseExpr(p) + incl(result.flags, ntDeclared) # NOW inlining may be attempted + else: + pegError(p, "rule expected, but found: " & p.tok.literal) + +proc rawParse(p: var PegParser): TPeg = + ## parses a rule or a PEG expression + while p.tok.kind == tkBuiltin: + case p.tok.literal + of "i": + p.modifier = modIgnoreCase + getTok(p) + of "y": + p.modifier = modIgnoreStyle + getTok(p) + of "skip": + getTok(p) + p.skip = ?primary(p) + else: break + if p.tok.kind == tkIdentifier and arrowIsNextTok(p): + result = parseRule(p).rule + while p.tok.kind != tkEof: + discard parseRule(p) + else: + p.identIsVerbatim = true + result = parseExpr(p) + if p.tok.kind != tkEof: + pegError(p, "EOF expected, but found: " & p.tok.literal) + for i in 0..high(p.nonterms): + var nt = p.nonterms[i] + if ntDeclared notin nt.flags: + pegError(p, "undeclared identifier: " & nt.name, nt.line, nt.col) + elif ntUsed notin nt.flags and i > 0: + pegError(p, "unused rule: " & nt.name, nt.line, nt.col) + +proc parsePeg*(pattern: string, filename = "pattern", line = 1, col = 0): TPeg = + ## constructs a Peg object from `pattern`. `filename`, `line`, `col` are + ## used for error messages, but they only provide start offsets. `parsePeg` + ## keeps track of line and column numbers within `pattern`. + var p: PegParser + init(PegLexer(p), pattern, filename, line, col) + p.tok.kind = tkInvalid + p.tok.modifier = modNone + p.tok.literal = "" + p.tok.charset = {} + p.nonterms = @[] + p.identIsVerbatim = false + getTok(p) + result = rawParse(p) + +proc peg*(pattern: string): TPeg = + ## constructs a Peg object from the `pattern`. The short name has been + ## chosen to encourage its use as a raw string modifier:: + ## + ## peg"{\ident} \s* '=' \s* {.*}" + result = parsePeg(pattern, "pattern") + +proc escapePeg*(s: string): string = + ## escapes `s` so that it is matched verbatim when used as a peg. + result = "" + var inQuote = false + for c in items(s): + case c + of '\0'..'\31', '\'', '"', '\\': + if inQuote: + result.add('\'') + inQuote = false + result.add("\\x") + result.add(toHex(ord(c), 2)) + else: + if not inQuote: + result.add('\'') + inQuote = true + result.add(c) + if inQuote: result.add('\'') + +when isMainModule: + assert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27" + assert match("(a b c)", peg"'(' @ ')'") + assert match("W_HI_Le", peg"\y 'while'") + assert(not match("W_HI_L", peg"\y 'while'")) + assert(not match("W_HI_Le", peg"\y v'while'")) + assert match("W_HI_Le", peg"y'while'") + + assert($ +digits == $peg"\d+") + assert "0158787".match(peg"\d+") + assert "ABC 0232".match(peg"\w+\s+\d+") + assert "ABC".match(peg"\d+ / \w+") + + for word in split("00232this02939is39an22example111", peg"\d+"): + writeln(stdout, word) + + assert matchLen("key", ident) == 3 + + var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident) + assert matchLen("key1= cal9", pattern) == 11 + + var ws = newNonTerminal("ws", 1, 1) + ws.rule = *whitespace + + var expr = newNonTerminal("expr", 1, 1) + expr.rule = sequence(capture(ident), *sequence( + nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr))) + + var c: Captures + var s = "a+b + c +d+e+f" + assert rawMatch(s, expr.rule, 0, c) == len(s) + var a = "" + for i in 0..c.ml-1: + a.add(substr(s, c.matches[i][0], c.matches[i][1])) + assert a == "abcdef" + #echo expr.rule + + #const filename = "lib/devel/peg/grammar.txt" + #var grammar = parsePeg(newFileStream(filename, fmRead), filename) + #echo "a <- [abc]*?".match(grammar) + assert find("_____abc_______", term("abc"), 2) == 5 + assert match("_______ana", peg"A <- 'ana' / . A") + assert match("abcs%%%", peg"A <- ..A / .A / '%'") + + var matches: array[0..MaxSubpatterns-1, string] + if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}": + assert matches[0] == "abc" + else: + assert false + + var g2 = peg"""S <- A B / C D + A <- 'a'+ + B <- 'b'+ + C <- 'c'+ + D <- 'd'+ + """ + assert($g2 == "((A B) / (C D))") + assert match("cccccdddddd", g2) + assert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") == + "var1<-keykey; var2<-key2key2") + assert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") == + "$1<-$2$2; $1<-$2$2") + assert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}") + + if "aaaaaa" =~ peg"'aa' !. / ({'a'})+": + assert matches[0] == "a" + else: + assert false + + if match("abcdefg", peg"c {d} ef {g}", matches, 2): + assert matches[0] == "d" + assert matches[1] == "g" + else: + assert false + + for x in findAll("abcdef", peg".", 3): + echo x + + for x in findAll("abcdef", peg"^{.}", 3): + assert x == "d" + + if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')": + assert matches[0] == "f" + assert matches[1] == "a, b" + else: + assert false + + assert match("eine übersicht und außerdem", peg"(\letter \white*)+") + # ß is not a lower cased letter?! + assert match("eine übersicht und auerdem", peg"(\lower \white*)+") + assert match("EINE ÃœBERSICHT UND AUSSERDEM", peg"(\upper \white*)+") + assert(not match("456678", peg"(\letter)+")) + + assert("var1 = key; var2 = key2".replacef( + peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") == + "var1<-keykey;var2<-key2key2") + + assert match("prefix/start", peg"^start$", 7) + diff --git a/lib/pure/poly.nim b/lib/pure/poly.nim index 45e528604..286e5a8fd 100644 --- a/lib/pure/poly.nim +++ b/lib/pure/poly.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Robert Persson # # See the file "copying.txt", included in this @@ -12,17 +12,18 @@ import strutils import numeric type - TPoly* = object - cofs:seq[float] + Poly* = object + cofs:seq[float] - -proc degree*(p:TPoly):int= +{.deprecated: [TPoly: Poly].} + +proc degree*(p:Poly):int= ## Returns the degree of the polynomial, ## that is the number of coefficients-1 return p.cofs.len-1 -proc eval*(p:TPoly,x:float):float= +proc eval*(p:Poly,x:float):float= ## Evaluates a polynomial function value for `x` ## quickly using Horners method var n=p.degree @@ -32,7 +33,7 @@ proc eval*(p:TPoly,x:float):float= result = result*x+p.cofs[n] dec n -proc `[]` *(p:TPoly;idx:int):float= +proc `[]` *(p:Poly;idx:int):float= ## Gets a coefficient of the polynomial. ## p[2] will returns the quadric term, p[3] the cubic etc. ## Out of bounds index will return 0.0. @@ -40,7 +41,7 @@ proc `[]` *(p:TPoly;idx:int):float= return 0.0 return p.cofs[idx] -proc `[]=` *(p:var TPoly;idx:int,v:float)= +proc `[]=` *(p:var Poly;idx:int,v:float)= ## Sets an coefficient of the polynomial by index. ## p[2] set the quadric term, p[3] the cubic etc. ## If index is out of range for the coefficients, @@ -56,14 +57,14 @@ proc `[]=` *(p:var TPoly;idx:int,v:float)= p.cofs[idx]=v -iterator items*(p:TPoly):float= +iterator items*(p:Poly):float= ## Iterates through the corfficients of the polynomial. var i=p.degree while i>=0: yield p[i] dec i -proc clean*(p:var TPoly;zerotol=0.0)= +proc clean*(p:var Poly;zerotol=0.0)= ## Removes leading zero coefficients of the polynomial. ## An optional tolerance can be given for what's considered zero. var n=p.degree @@ -76,7 +77,7 @@ proc clean*(p:var TPoly;zerotol=0.0)= if relen: p.cofs.setLen(n+1) -proc `$` *(p:TPoly):string = +proc `$` *(p:Poly):string = ## Gets a somewhat reasonable string representation of the polynomial ## The format should be compatible with most online function plotters, ## for example directly in google search @@ -104,13 +105,13 @@ proc `$` *(p:TPoly):string = result="0" -proc derivative*(p:TPoly):TPoly= +proc derivative*(p: Poly): Poly= ## Returns a new polynomial, which is the derivative of `p` newSeq[float](result.cofs,p.degree) for idx in 0..high(result.cofs): result.cofs[idx]=p.cofs[idx+1]*float(idx+1) -proc diff*(p:TPoly,x:float):float= +proc diff*(p:Poly,x:float):float= ## Evaluates the differentiation of a polynomial with ## respect to `x` quickly using a modifed Horners method var n=p.degree @@ -120,7 +121,7 @@ proc diff*(p:TPoly,x:float):float= result = result*x+p[n]*float(n) dec n -proc integral*(p:TPoly):TPoly= +proc integral*(p:Poly):Poly= ## Returns a new polynomial which is the indefinite ## integral of `p`. The constant term is set to 0.0 newSeq(result.cofs,p.cofs.len+1) @@ -129,7 +130,7 @@ proc integral*(p:TPoly):TPoly= result.cofs[i]=p.cofs[i-1]/float(i) -proc integrate*(p:TPoly;xmin,xmax:float):float= +proc integrate*(p:Poly;xmin,xmax:float):float= ## Computes the definite integral of `p` between `xmin` and `xmax` ## quickly using a modified version of Horners method var @@ -147,7 +148,7 @@ proc integrate*(p:TPoly;xmin,xmax:float):float= result=s2*xmax-s1*xmin -proc initPoly*(cofs:varargs[float]):TPoly= +proc initPoly*(cofs:varargs[float]):Poly= ## Initializes a polynomial with given coefficients. ## The most significant coefficient is first, so to create x^2-2x+3: ## intiPoly(1.0,-2.0,3.0) @@ -163,7 +164,7 @@ proc initPoly*(cofs:varargs[float]):TPoly= result.clean #remove leading zero terms -proc divMod*(p,d:TPoly;q,r:var TPoly)= +proc divMod*(p,d:Poly;q,r:var Poly)= ## Divides `p` with `d`, and stores the quotinent in `q` and ## the remainder in `d` var @@ -191,7 +192,7 @@ proc divMod*(p,d:TPoly;q,r:var TPoly)= r.clean # drop zero coefficients in remainder -proc `+` *(p1:TPoly,p2:TPoly):TPoly= +proc `+` *(p1:Poly,p2:Poly):Poly= ## Adds two polynomials var n=max(p1.cofs.len,p2.cofs.len) newSeq(result.cofs,n) @@ -201,7 +202,7 @@ proc `+` *(p1:TPoly,p2:TPoly):TPoly= result.clean # drop zero coefficients in remainder -proc `*` *(p1:TPoly,p2:TPoly):TPoly= +proc `*` *(p1:Poly,p2:Poly):Poly= ## Multiplies the polynomial `p1` with `p2` var d1=p1.degree @@ -218,24 +219,24 @@ proc `*` *(p1:TPoly,p2:TPoly):TPoly= result.clean -proc `*` *(p:TPoly,f:float):TPoly= +proc `*` *(p:Poly,f:float):Poly= ## Multiplies the polynomial `p` with a real number newSeq(result.cofs,p.cofs.len) for i in 0..high(p.cofs): result[i]=p.cofs[i]*f result.clean -proc `*` *(f:float,p:TPoly):TPoly= +proc `*` *(f:float,p:Poly):Poly= ## Multiplies a real number with a polynomial return p*f -proc `-`*(p:TPoly):TPoly= +proc `-`*(p:Poly):Poly= ## Negates a polynomial result=p for i in countup(0,<result.cofs.len): result.cofs[i]= -result.cofs[i] -proc `-` *(p1:TPoly,p2:TPoly):TPoly= +proc `-` *(p1:Poly,p2:Poly):Poly= ## Subtract `p1` with `p2` var n=max(p1.cofs.len,p2.cofs.len) newSeq(result.cofs,n) @@ -245,26 +246,26 @@ proc `-` *(p1:TPoly,p2:TPoly):TPoly= result.clean # drop zero coefficients in remainder -proc `/`*(p:TPoly,f:float):TPoly= +proc `/`*(p:Poly,f:float):Poly= ## Divides polynomial `p` with a real number `f` newSeq(result.cofs,p.cofs.len) for i in 0..high(p.cofs): result[i]=p.cofs[i]/f result.clean -proc `/` *(p,q:TPoly):TPoly= +proc `/` *(p,q:Poly):Poly= ## Divides polynomial `p` with polynomial `q` - var dummy:TPoly + var dummy:Poly p.divMod(q,result,dummy) -proc `mod` *(p,q:TPoly):TPoly= +proc `mod` *(p,q:Poly):Poly= ## Computes the polynomial modulo operation, ## that is the remainder of `p`/`q` - var dummy:TPoly + var dummy:Poly p.divMod(q,dummy,result) -proc normalize*(p:var TPoly)= +proc normalize*(p:var Poly)= ## Multiplies the polynomial inplace by a term so that ## the leading term is 1.0. ## This might lead to an unstable polynomial @@ -281,9 +282,9 @@ proc solveQuadric*(a,b,c:float;zerotol=0.0):seq[float]= p=b/(2.0*a) - if p==inf or p==neginf: #linear equation.. + if p==Inf or p==NegInf: #linear equation.. var linrt= -c/b - if linrt==inf or linrt==neginf: #constant only + if linrt==Inf or linrt==NegInf: #constant only return @[] return @[linrt] @@ -299,7 +300,7 @@ proc solveQuadric*(a,b,c:float;zerotol=0.0):seq[float]= var sr=sqrt(d) result= @[-sr-p,sr-p] -proc getRangeForRoots(p:TPoly):tuple[xmin,xmax:float]= +proc getRangeForRoots(p:Poly):tuple[xmin,xmax:float]= ## helper function for `roots` function ## quickly computes a range, guaranteed to contain ## all the real roots of the polynomial @@ -310,16 +311,16 @@ proc getRangeForRoots(p:TPoly):tuple[xmin,xmax:float]= var bound1,bound2:float for i in countup(0,deg): - var c=abs(p.cofs[i]/d) - bound1=max(bound1,c+1.0) - bound2=bound2+c - + var c=abs(p.cofs[i]/d) + bound1=max(bound1,c+1.0) + bound2=bound2+c + bound2=max(1.0,bound2) result.xmax=min(bound1,bound2) result.xmin= -result.xmax -proc addRoot(p:TPoly,res:var seq[float],xp0,xp1,tol,zerotol,mergetol:float,maxiter:int)= +proc addRoot(p:Poly,res:var seq[float],xp0,xp1,tol,zerotol,mergetol:float,maxiter:int)= ## helper function for `roots` function ## try to do a numeric search for a single root in range xp0-xp1, ## adding it to `res` (allocating `res` if nil) @@ -335,7 +336,7 @@ proc addRoot(p:TPoly,res:var seq[float],xp0,xp1,tol,zerotol,mergetol:float,maxit res.add(br.rootx) -proc roots*(p:TPoly,tol=1.0e-9,zerotol=1.0e-6,mergetol=1.0e-12,maxiter=1000):seq[float]= +proc roots*(p:Poly,tol=1.0e-9,zerotol=1.0e-6,mergetol=1.0e-12,maxiter=1000):seq[float]= ## Computes the real roots of the polynomial `p` ## `tol` is the tolerance used to break searching for each root when reached. ## `zerotol` is the tolerance, which is 'close enough' to zero to be considered a root @@ -348,7 +349,7 @@ proc roots*(p:TPoly,tol=1.0e-9,zerotol=1.0e-6,mergetol=1.0e-12,maxiter=1000):seq return @[] elif p.degree==1: #linear var linrt= -p.cofs[0]/p.cofs[1] - if linrt==inf or linrt==neginf: + if linrt==Inf or linrt==NegInf: return @[] #constant only => no roots return @[linrt] elif p.degree==2: diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim index fea09dfa2..5756ca23d 100644 --- a/lib/pure/rawsockets.nim +++ b/lib/pure/rawsockets.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # # See the file "copying.txt", included in this @@ -14,7 +14,7 @@ import unsigned, os -when hostos == "solaris": +when hostOS == "solaris": {.passl: "-lsocket -lnsl".} const useWinVersion = defined(Windows) or defined(nimdoc) @@ -28,7 +28,7 @@ else: export fcntl, F_GETFL, O_NONBLOCK, F_SETFL, EAGAIN, EWOULDBLOCK, MSG_NOSIGNAL, EINTR, EINPROGRESS, ECONNRESET, EPIPE, ENETRESET -export TSocketHandle, TSockaddr_in, TAddrinfo, INADDR_ANY, TSockAddr, TSockLen, +export SocketHandle, Sockaddr_in, Addrinfo, INADDR_ANY, SockAddr, SockLen, inet_ntoa, recv, `==`, connect, send, accept, recvfrom, sendto export @@ -40,22 +40,22 @@ export MSG_PEEK type - TPort* = distinct uint16 ## port type + Port* = distinct uint16 ## port type - TDomain* = enum ## domain, which specifies the protocol family of the + Domain* = enum ## domain, which specifies the protocol family of the ## created socket. Other domains than those that are listed ## here are unsupported. AF_UNIX, ## for local socket (using a file). Unsupported on Windows. AF_INET = 2, ## for network protocol IPv4 or AF_INET6 = 23 ## for network protocol IPv6. - TType* = enum ## second argument to `socket` proc + SockType* = enum ## second argument to `socket` proc SOCK_STREAM = 1, ## reliable stream-oriented service or Stream Sockets SOCK_DGRAM = 2, ## datagram service or Datagram Sockets SOCK_RAW = 3, ## raw protocols atop the network layer. SOCK_SEQPACKET = 5 ## reliable sequenced packet service - TProtocol* = enum ## third argument to `socket` proc + Protocol* = enum ## third argument to `socket` proc IPPROTO_TCP = 6, ## Transmission control protocol. IPPROTO_UDP = 17, ## User datagram protocol. IPPROTO_IP, ## Internet protocol. Unsupported on Windows. @@ -63,19 +63,22 @@ type IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows. IPPROTO_ICMP ## Control message protocol. Unsupported on Windows. - TServent* {.pure, final.} = object ## information about a service + Servent* = object ## information about a service name*: string aliases*: seq[string] - port*: TPort + port*: Port proto*: string - Thostent* {.pure, final.} = object ## information about a given host + Hostent* = object ## information about a given host name*: string aliases*: seq[string] - addrtype*: TDomain + addrtype*: Domain length*: int addrList*: seq[string] +{.deprecated: [TPort: Port, TDomain: Domain, TType: SockType, + TProtocol: Protocol, TServent: Servent, THostent: Hostent].} + when useWinVersion: let osInvalidSocket* = winlean.INVALID_SOCKET @@ -86,37 +89,37 @@ when useWinVersion: FIONBIO* = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or (102 shl 8) or 126 - proc ioctlsocket*(s: TSocketHandle, cmd: clong, + proc ioctlsocket*(s: SocketHandle, cmd: clong, argptr: ptr clong): cint {. stdcall, importc: "ioctlsocket", dynlib: "ws2_32.dll".} else: let osInvalidSocket* = posix.INVALID_SOCKET -proc `==`*(a, b: TPort): bool {.borrow.} +proc `==`*(a, b: Port): bool {.borrow.} ## ``==`` for ports. -proc `$`*(p: TPort): string {.borrow.} +proc `$`*(p: Port): string {.borrow.} ## returns the port number as a string -proc toInt*(domain: TDomain): cint +proc toInt*(domain: Domain): cint ## Converts the TDomain enum to a platform-dependent ``cint``. -proc toInt*(typ: TType): cint +proc toInt*(typ: SockType): cint ## Converts the TType enum to a platform-dependent ``cint``. -proc toInt*(p: TProtocol): cint +proc toInt*(p: Protocol): cint ## Converts the TProtocol enum to a platform-dependent ``cint``. when not useWinVersion: - proc toInt(domain: TDomain): cint = + proc toInt(domain: Domain): cint = case domain of AF_UNIX: result = posix.AF_UNIX of AF_INET: result = posix.AF_INET of AF_INET6: result = posix.AF_INET6 else: discard - proc toInt(typ: TType): cint = + proc toInt(typ: SockType): cint = case typ of SOCK_STREAM: result = posix.SOCK_STREAM of SOCK_DGRAM: result = posix.SOCK_DGRAM @@ -124,7 +127,7 @@ when not useWinVersion: of SOCK_RAW: result = posix.SOCK_RAW else: discard - proc toInt(p: TProtocol): cint = + proc toInt(p: Protocol): cint = case p of IPPROTO_TCP: result = posix.IPPROTO_TCP of IPPROTO_UDP: result = posix.IPPROTO_UDP @@ -135,34 +138,41 @@ when not useWinVersion: else: discard else: - proc toInt(domain: TDomain): cint = + proc toInt(domain: Domain): cint = result = toU16(ord(domain)) - proc toInt(typ: TType): cint = + proc toInt(typ: SockType): cint = result = cint(ord(typ)) - proc toInt(p: TProtocol): cint = + proc toInt(p: Protocol): cint = result = cint(ord(p)) -proc newRawSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, - protocol: TProtocol = IPPROTO_TCP): TSocketHandle = +proc newRawSocket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP): SocketHandle = ## Creates a new socket; returns `InvalidSocket` if an error occurs. socket(toInt(domain), toInt(typ), toInt(protocol)) -proc close*(socket: TSocketHandle) = +proc newRawSocket*(domain: cint, typ: cint, protocol: cint): SocketHandle = + ## Creates a new socket; returns `InvalidSocket` if an error occurs. + ## + ## Use this overload if one of the enums specified above does + ## not contain what you need. + socket(domain, typ, protocol) + +proc close*(socket: SocketHandle) = ## closes a socket. when useWinVersion: - discard winlean.closeSocket(socket) + discard winlean.closesocket(socket) else: discard posix.close(socket) # TODO: These values should not be discarded. An EOS should be raised. # http://stackoverflow.com/questions/12463473/what-happens-if-you-call-close-on-a-bsd-socket-multiple-times -proc bindAddr*(socket: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint = +proc bindAddr*(socket: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint = result = bindSocket(socket, name, namelen) -proc listen*(socket: TSocketHandle, backlog = SOMAXCONN): cint {.tags: [FReadIO].} = +proc listen*(socket: SocketHandle, backlog = SOMAXCONN): cint {.tags: [ReadIOEffect].} = ## Marks ``socket`` as accepting connections. ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. @@ -171,24 +181,24 @@ proc listen*(socket: TSocketHandle, backlog = SOMAXCONN): cint {.tags: [FReadIO] else: result = posix.listen(socket, cint(backlog)) -proc getAddrInfo*(address: string, port: TPort, af: TDomain = AF_INET, typ: TType = SOCK_STREAM, - prot: TProtocol = IPPROTO_TCP): ptr TAddrInfo = +proc getAddrInfo*(address: string, port: Port, af: Domain = AF_INET, typ: SockType = SOCK_STREAM, + prot: Protocol = IPPROTO_TCP): ptr AddrInfo = ## ## ## **Warning**: The resulting ``ptr TAddrInfo`` must be freed using ``dealloc``! - var hints: TAddrInfo + var hints: AddrInfo result = nil hints.ai_family = toInt(af) hints.ai_socktype = toInt(typ) hints.ai_protocol = toInt(prot) - var gaiResult = getAddrInfo(address, $port, addr(hints), result) + var gaiResult = getaddrinfo(address, $port, addr(hints), result) if gaiResult != 0'i32: when useWinVersion: - osError(osLastError()) + raiseOSError(osLastError()) else: - raise newException(EOS, $gai_strerror(gaiResult)) + raise newException(OSError, $gai_strerror(gaiResult)) -proc dealloc*(ai: ptr TAddrInfo) = +proc dealloc*(ai: ptr AddrInfo) = freeaddrinfo(ai) proc ntohl*(x: int32): int32 = @@ -220,7 +230,7 @@ proc htons*(x: int16): int16 = ## order, this is a no-op; otherwise, it performs a 2-byte swap operation. result = rawsockets.ntohs(x) -proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} = +proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = ## Searches the database from the beginning and finds the first entry for ## which the service name specified by ``name`` matches the s_name member ## and the protocol name specified by ``proto`` matches the s_proto member. @@ -230,13 +240,13 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} = var s = winlean.getservbyname(name, proto) else: var s = posix.getservbyname(name, proto) - if s == nil: raise newException(EOS, "Service not found.") + if s == nil: raise newException(OSError, "Service not found.") result.name = $s.s_name result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = TPort(s.s_port) + result.port = Port(s.s_port) result.proto = $s.s_proto -proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} = +proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = ## Searches the database from the beginning and finds the first entry for ## which the port specified by ``port`` matches the s_port member and the ## protocol name specified by ``proto`` matches the s_proto member. @@ -246,125 +256,125 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} = var s = winlean.getservbyport(ze(int16(port)).cint, proto) else: var s = posix.getservbyport(ze(int16(port)).cint, proto) - if s == nil: raise newException(EOS, "Service not found.") + if s == nil: raise newException(OSError, "Service not found.") result.name = $s.s_name result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = TPort(s.s_port) + result.port = Port(s.s_port) result.proto = $s.s_proto -proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} = +proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = ## This function will lookup the hostname of an IP Address. - var myaddr: TInAddr + var myaddr: InAddr myaddr.s_addr = inet_addr(ip) when useWinVersion: var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint, cint(rawsockets.AF_INET)) - if s == nil: osError(osLastError()) + if s == nil: raiseOSError(osLastError()) else: - var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSocklen, + var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, cint(posix.AF_INET)) if s == nil: - raise newException(EOS, $hstrerror(h_errno)) + raise newException(OSError, $hstrerror(h_errno)) result.name = $s.h_name result.aliases = cstringArrayToSeq(s.h_aliases) - when useWinVersion: - result.addrtype = TDomain(s.h_addrtype) + when useWinVersion: + result.addrtype = Domain(s.h_addrtype) else: if s.h_addrtype == posix.AF_INET: result.addrtype = AF_INET elif s.h_addrtype == posix.AF_INET6: result.addrtype = AF_INET6 else: - raise newException(EOS, "unknown h_addrtype") + raise newException(OSError, "unknown h_addrtype") result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) -proc getHostByName*(name: string): Thostent {.tags: [FReadIO].} = +proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = ## This function will lookup the IP address of a hostname. when useWinVersion: var s = winlean.gethostbyname(name) else: var s = posix.gethostbyname(name) - if s == nil: osError(osLastError()) + if s == nil: raiseOSError(osLastError()) result.name = $s.h_name result.aliases = cstringArrayToSeq(s.h_aliases) - when useWinVersion: - result.addrtype = TDomain(s.h_addrtype) + when useWinVersion: + result.addrtype = Domain(s.h_addrtype) else: if s.h_addrtype == posix.AF_INET: result.addrtype = AF_INET elif s.h_addrtype == posix.AF_INET6: result.addrtype = AF_INET6 else: - raise newException(EOS, "unknown h_addrtype") + raise newException(OSError, "unknown h_addrtype") result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) -proc getSockName*(socket: TSocketHandle): TPort = +proc getSockName*(socket: SocketHandle): Port = ## returns the socket's associated port number. - var name: Tsockaddr_in + var name: Sockaddr_in when useWinVersion: name.sin_family = int16(ord(AF_INET)) else: name.sin_family = posix.AF_INET #name.sin_port = htons(cint16(port)) #name.sin_addr.s_addr = htonl(INADDR_ANY) - var namelen = sizeof(name).TSocklen - if getsockname(socket, cast[ptr TSockAddr](addr(name)), + var namelen = sizeof(name).SockLen + if getsockname(socket, cast[ptr SockAddr](addr(name)), addr(namelen)) == -1'i32: - osError(osLastError()) - result = TPort(rawsockets.ntohs(name.sin_port)) + raiseOSError(osLastError()) + result = Port(rawsockets.ntohs(name.sin_port)) -proc getSockOptInt*(socket: TSocketHandle, level, optname: int): int {. - tags: [FReadIO].} = +proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {. + tags: [ReadIOEffect].} = ## getsockopt for integer options. var res: cint - var size = sizeof(res).TSocklen + var size = sizeof(res).SockLen if getsockopt(socket, cint(level), cint(optname), addr(res), addr(size)) < 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) result = int(res) -proc setSockOptInt*(socket: TSocketHandle, level, optname, optval: int) {. - tags: [FWriteIO].} = +proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {. + tags: [WriteIOEffect].} = ## setsockopt for integer options. var value = cint(optval) if setsockopt(socket, cint(level), cint(optname), addr(value), - sizeof(value).TSocklen) < 0'i32: - osError(osLastError()) + sizeof(value).SockLen) < 0'i32: + raiseOSError(osLastError()) -proc setBlocking*(s: TSocketHandle, blocking: bool) = +proc setBlocking*(s: SocketHandle, blocking: bool) = ## Sets blocking mode on socket. ## ## Raises EOS on error. when useWinVersion: var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking if ioctlsocket(s, FIONBIO, addr(mode)) == -1: - osError(osLastError()) + raiseOSError(osLastError()) else: # BSD sockets var x: int = fcntl(s, F_GETFL, 0) if x == -1: - osError(osLastError()) + raiseOSError(osLastError()) else: var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK if fcntl(s, F_SETFL, mode) == -1: - osError(osLastError()) + raiseOSError(osLastError()) -proc timeValFromMilliseconds(timeout = 500): Ttimeval = +proc timeValFromMilliseconds(timeout = 500): Timeval = if timeout != -1: var seconds = timeout div 1000 result.tv_sec = seconds.int32 result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 -proc createFdSet(fd: var TFdSet, s: seq[TSocketHandle], m: var int) = +proc createFdSet(fd: var TFdSet, s: seq[SocketHandle], m: var int) = FD_ZERO(fd) for i in items(s): m = max(m, int(i)) - FD_SET(i, fd) + fdSet(i, fd) -proc pruneSocketSet(s: var seq[TSocketHandle], fd: var TFdSet) = +proc pruneSocketSet(s: var seq[SocketHandle], fd: var TFdSet) = var i = 0 var L = s.len while i < L: @@ -375,7 +385,7 @@ proc pruneSocketSet(s: var seq[TSocketHandle], fd: var TFdSet) = inc(i) setLen(s, L) -proc select*(readfds: var seq[TSocketHandle], timeout = 500): int = +proc select*(readfds: var seq[SocketHandle], timeout = 500): int = ## Traditional select function. This function will return the number of ## sockets that are ready to be read from, written to, or which have errors. ## If there are none; 0 is returned. @@ -383,7 +393,7 @@ proc select*(readfds: var seq[TSocketHandle], timeout = 500): int = ## ## A socket is removed from the specific ``seq`` when it has data waiting to ## be read/written to or has errors (``exceptfds``). - var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout) + var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) var rd: TFdSet var m = 0 @@ -396,8 +406,8 @@ proc select*(readfds: var seq[TSocketHandle], timeout = 500): int = pruneSocketSet(readfds, (rd)) -proc selectWrite*(writefds: var seq[TSocketHandle], - timeout = 500): int {.tags: [FReadIO].} = +proc selectWrite*(writefds: var seq[SocketHandle], + timeout = 500): int {.tags: [ReadIOEffect].} = ## When a socket in ``writefds`` is ready to be written to then a non-zero ## value will be returned specifying the count of the sockets which can be ## written to. The sockets which can be written to will also be removed @@ -405,7 +415,7 @@ proc selectWrite*(writefds: var seq[TSocketHandle], ## ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for ## an unlimited time. - var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout) + var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) var wr: TFdSet var m = 0 @@ -419,5 +429,5 @@ proc selectWrite*(writefds: var seq[TSocketHandle], pruneSocketSet(writefds, (wr)) when defined(Windows): - var wsa: TWSADATA - if WSAStartup(0x0101'i16, addr wsa) != 0: osError(osLastError()) + var wsa: WSAData + if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError()) diff --git a/lib/pure/redis.nim b/lib/pure/redis.nim index 959f5c6ef..52d81b3a4 100644 --- a/lib/pure/redis.nim +++ b/lib/pure/redis.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Dominik Picheta # # See the file "copying.txt", included in this @@ -20,135 +20,139 @@ const redisNil* = "\0\0" type - PPipeline = ref object + Pipeline = ref object enabled: bool buffer: string expected: int ## number of replies expected if pipelined type - TSendMode = enum + SendMode = enum normal, pipelined, multiple type - TRedis* {.pure, final.} = object - socket: TSocket + Redis* = object + socket: Socket connected: bool - pipeline: PPipeline + pipeline: Pipeline - TRedisStatus* = string - TRedisInteger* = biggestInt - TRedisString* = string ## Bulk reply - TRedisList* = seq[TRedisString] ## Multi-bulk reply + RedisStatus* = string + RedisInteger* = BiggestInt + RedisString* = string ## Bulk reply + RedisList* = seq[RedisString] ## Multi-bulk reply - EInvalidReply* = object of ESynch ## Invalid reply from redis - ERedis* = object of ESynch ## Error in redis + ReplyError* = object of IOError ## Invalid reply from redis + RedisError* = object of IOError ## Error in redis -proc newPipeline(): PPipeline = +{.deprecated: [TSendMode: SendMode, TRedis: Redis, TRedisStatus: RedisStatus, + TRedisInteger: RedisInteger, TRedisString: RedisString, + TRedisList: RedisList, EInvalidReply: ReplyError, ERedis: RedisError].} + +proc newPipeline(): Pipeline = new(result) result.buffer = "" result.enabled = false result.expected = 0 -proc open*(host = "localhost", port = 6379.TPort): TRedis = +proc open*(host = "localhost", port = 6379.Port): Redis = ## Opens a connection to the redis server. result.socket = socket(buffered = false) - if result.socket == InvalidSocket: - OSError(OSLastError()) + if result.socket == invalidSocket: + raiseOSError(osLastError()) result.socket.connect(host, port) result.pipeline = newPipeline() proc raiseInvalidReply(expected, got: char) = - raise newException(EInvalidReply, + raise newException(ReplyError, "Expected '$1' at the beginning of a status reply got '$2'" % [$expected, $got]) -proc raiseNoOK(status: string, pipelineEnabled:bool) = +proc raiseNoOK(status: string, pipelineEnabled: bool) = if pipelineEnabled and not (status == "QUEUED" or status == "PIPELINED"): - raise newException(EInvalidReply, "Expected \"QUEUED\" or \"PIPELINED\" got \"$1\"" % status) + raise newException(ReplyError, "Expected \"QUEUED\" or \"PIPELINED\" got \"$1\"" % status) elif not pipelineEnabled and status != "OK": - raise newException(EInvalidReply, "Expected \"OK\" got \"$1\"" % status) + raise newException(ReplyError, "Expected \"OK\" got \"$1\"" % status) -template readSocket(r: TRedis, dummyVal:expr): stmt = - var line {.inject.} :TaintedString = "" +template readSocket(r: Redis, dummyVal:expr): stmt = + var line {.inject.}: TaintedString = "" if r.pipeline.enabled: return dummyVal else: readLine(r.socket, line) -proc parseStatus(r: TRedis, line: string = ""): TRedisStatus = +proc parseStatus(r: Redis, line: string = ""): RedisStatus = if r.pipeline.enabled: return "PIPELINED" if line == "": - raise newException(ERedis, "Server closed connection prematurely") + raise newException(RedisError, "Server closed connection prematurely") if line[0] == '-': - raise newException(ERedis, strip(line)) + raise newException(RedisError, strip(line)) if line[0] != '+': raiseInvalidReply('+', line[0]) return line.substr(1) # Strip '+' -proc readStatus(r:TRedis): TRedisStatus = +proc readStatus(r:Redis): RedisStatus = r.readSocket("PIPELINED") return r.parseStatus(line) -proc parseInteger(r: TRedis, line: string = ""): TRedisInteger = +proc parseInteger(r: Redis, line: string = ""): RedisInteger = if r.pipeline.enabled: return -1 #if line == "+QUEUED": # inside of multi # return -1 if line == "": - raise newException(ERedis, "Server closed connection prematurely") + raise newException(RedisError, "Server closed connection prematurely") if line[0] == '-': - raise newException(ERedis, strip(line)) + raise newException(RedisError, strip(line)) if line[0] != ':': raiseInvalidReply(':', line[0]) # Strip ':' if parseBiggestInt(line, result, 1) == 0: - raise newException(EInvalidReply, "Unable to parse integer.") + raise newException(ReplyError, "Unable to parse integer.") -proc readInteger(r: TRedis): TRedisInteger = +proc readInteger(r: Redis): RedisInteger = r.readSocket(-1) return r.parseInteger(line) -proc recv(sock: TSocket, size: int): TaintedString = +proc recv(sock: Socket, size: int): TaintedString = result = newString(size).TaintedString if sock.recv(cstring(result), size) != size: - raise newException(EInvalidReply, "recv failed") + raise newException(ReplyError, "recv failed") -proc parseSingleString(r: TRedis, line:string, allowMBNil = False): TRedisString = +proc parseSingleString(r: Redis, line:string, allowMBNil = false): RedisString = if r.pipeline.enabled: return "" # Error. if line[0] == '-': - raise newException(ERedis, strip(line)) + raise newException(RedisError, strip(line)) # Some commands return a /bulk/ value or a /multi-bulk/ nil. Odd. if allowMBNil: if line == "*-1": - return RedisNil + return redisNil if line[0] != '$': raiseInvalidReply('$', line[0]) var numBytes = parseInt(line.substr(1)) if numBytes == -1: - return RedisNil + return redisNil var s = r.socket.recv(numBytes+2) result = strip(s.string) -proc readSingleString(r: TRedis): TRedisString = +proc readSingleString(r: Redis): RedisString = r.readSocket("") return r.parseSingleString(line) -proc readNext(r: TRedis): TRedisList +proc readNext(r: Redis): RedisList -proc parseArrayLines(r: TRedis, countLine:string): TRedisList = +proc parseArrayLines(r: Redis, countLine:string): RedisList = if countLine.string[0] != '*': raiseInvalidReply('*', countLine.string[0]) @@ -162,24 +166,24 @@ proc parseArrayLines(r: TRedis, countLine:string): TRedisList = for item in parsed: result.add(item) -proc readArrayLines(r: TRedis): TRedisList = +proc readArrayLines(r: Redis): RedisList = r.readSocket(nil) return r.parseArrayLines(line) -proc parseBulkString(r: TRedis, allowMBNil = False, line:string = ""): TRedisString = +proc parseBulkString(r: Redis, allowMBNil = false, line:string = ""): RedisString = if r.pipeline.enabled: return "" return r.parseSingleString(line, allowMBNil) -proc readBulkString(r: TRedis, allowMBNil = false): TRedisString = +proc readBulkString(r: Redis, allowMBNil = false): RedisString = r.readSocket("") return r.parseBulkString(allowMBNil, line) -proc readArray(r: TRedis): TRedisList = +proc readArray(r: Redis): RedisList = r.readSocket(@[]) return r.parseArrayLines(line) -proc readNext(r: TRedis): TRedisList = +proc readNext(r: Redis): RedisList = r.readSocket(@[]) var res = case line[0] @@ -188,12 +192,12 @@ proc readNext(r: TRedis): TRedisList = of '$': @[r.parseBulkString(true,line)] of '*': r.parseArrayLines(line) else: - raise newException(EInvalidReply, "readNext failed on line: " & line) + raise newException(ReplyError, "readNext failed on line: " & line) nil r.pipeline.expected -= 1 return res -proc flushPipeline*(r: TRedis, wasMulti = false): TRedisList = +proc flushPipeline*(r: Redis, wasMulti = false): RedisList = ## Send buffered commands, clear buffer, return results if r.pipeline.buffer.len > 0: r.socket.send(r.pipeline.buffer) @@ -212,7 +216,7 @@ proc flushPipeline*(r: TRedis, wasMulti = false): TRedisList = r.pipeline.expected = 0 -proc startPipelining*(r: TRedis) = +proc startPipelining*(r: Redis) = ## Enable command pipelining (reduces network roundtrips). ## Note that when enabled, you must call flushPipeline to actually send commands, except ## for multi/exec() which enable and flush the pipeline automatically. @@ -221,7 +225,7 @@ proc startPipelining*(r: TRedis) = r.pipeline.expected = 0 r.pipeline.enabled = true -proc sendCommand(r: TRedis, cmd: string, args: varargs[string]) = +proc sendCommand(r: Redis, cmd: string, args: varargs[string]) = var request = "*" & $(1 + args.len()) & "\c\L" request.add("$" & $cmd.len() & "\c\L") request.add(cmd & "\c\L") @@ -235,7 +239,7 @@ proc sendCommand(r: TRedis, cmd: string, args: varargs[string]) = else: r.socket.send(request) -proc sendCommand(r: TRedis, cmd: string, arg1: string, +proc sendCommand(r: Redis, cmd: string, arg1: string, args: varargs[string]) = var request = "*" & $(2 + args.len()) & "\c\L" request.add("$" & $cmd.len() & "\c\L") @@ -254,68 +258,68 @@ proc sendCommand(r: TRedis, cmd: string, arg1: string, # Keys -proc del*(r: TRedis, keys: varargs[string]): TRedisInteger = +proc del*(r: Redis, keys: varargs[string]): RedisInteger = ## Delete a key or multiple keys r.sendCommand("DEL", keys) return r.readInteger() -proc exists*(r: TRedis, key: string): bool = +proc exists*(r: Redis, key: string): bool = ## Determine if a key exists r.sendCommand("EXISTS", key) return r.readInteger() == 1 -proc expire*(r: TRedis, key: string, seconds: int): bool = +proc expire*(r: Redis, key: string, seconds: int): bool = ## Set a key's time to live in seconds. Returns `false` if the key could ## not be found or the timeout could not be set. r.sendCommand("EXPIRE", key, $seconds) return r.readInteger() == 1 -proc expireAt*(r: TRedis, key: string, timestamp: int): bool = +proc expireAt*(r: Redis, key: string, timestamp: int): bool = ## Set the expiration for a key as a UNIX timestamp. Returns `false` ## if the key could not be found or the timeout could not be set. r.sendCommand("EXPIREAT", key, $timestamp) return r.readInteger() == 1 -proc keys*(r: TRedis, pattern: string): TRedisList = +proc keys*(r: Redis, pattern: string): RedisList = ## Find all keys matching the given pattern r.sendCommand("KEYS", pattern) return r.readArray() -proc move*(r: TRedis, key: string, db: int): bool = +proc move*(r: Redis, key: string, db: int): bool = ## Move a key to another database. Returns `true` on a successful move. r.sendCommand("MOVE", key, $db) return r.readInteger() == 1 -proc persist*(r: TRedis, key: string): bool = +proc persist*(r: Redis, key: string): bool = ## Remove the expiration from a key. ## Returns `true` when the timeout was removed. r.sendCommand("PERSIST", key) return r.readInteger() == 1 -proc randomKey*(r: TRedis): TRedisString = +proc randomKey*(r: Redis): RedisString = ## Return a random key from the keyspace r.sendCommand("RANDOMKEY") return r.readBulkString() -proc rename*(r: TRedis, key, newkey: string): TRedisStatus = +proc rename*(r: Redis, key, newkey: string): RedisStatus = ## Rename a key. ## ## **WARNING:** Overwrites `newkey` if it exists! r.sendCommand("RENAME", key, newkey) raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc renameNX*(r: TRedis, key, newkey: string): bool = +proc renameNX*(r: Redis, key, newkey: string): bool = ## Same as ``rename`` but doesn't continue if `newkey` exists. ## Returns `true` if key was renamed. r.sendCommand("RENAMENX", key, newkey) return r.readInteger() == 1 -proc ttl*(r: TRedis, key: string): TRedisInteger = +proc ttl*(r: Redis, key: string): RedisInteger = ## Get the time to live for a key r.sendCommand("TTL", key) return r.readInteger() -proc keyType*(r: TRedis, key: string): TRedisStatus = +proc keyType*(r: Redis, key: string): RedisStatus = ## Determine the type stored at key r.sendCommand("TYPE", key) return r.readStatus() @@ -323,131 +327,131 @@ proc keyType*(r: TRedis, key: string): TRedisStatus = # Strings -proc append*(r: TRedis, key, value: string): TRedisInteger = +proc append*(r: Redis, key, value: string): RedisInteger = ## Append a value to a key r.sendCommand("APPEND", key, value) return r.readInteger() -proc decr*(r: TRedis, key: string): TRedisInteger = +proc decr*(r: Redis, key: string): RedisInteger = ## Decrement the integer value of a key by one r.sendCommand("DECR", key) return r.readInteger() -proc decrBy*(r: TRedis, key: string, decrement: int): TRedisInteger = +proc decrBy*(r: Redis, key: string, decrement: int): RedisInteger = ## Decrement the integer value of a key by the given number r.sendCommand("DECRBY", key, $decrement) return r.readInteger() -proc get*(r: TRedis, key: string): TRedisString = +proc get*(r: Redis, key: string): RedisString = ## Get the value of a key. Returns `redisNil` when `key` doesn't exist. r.sendCommand("GET", key) return r.readBulkString() -proc getBit*(r: TRedis, key: string, offset: int): TRedisInteger = +proc getBit*(r: Redis, key: string, offset: int): RedisInteger = ## Returns the bit value at offset in the string value stored at key r.sendCommand("GETBIT", key, $offset) return r.readInteger() -proc getRange*(r: TRedis, key: string, start, stop: int): TRedisString = +proc getRange*(r: Redis, key: string, start, stop: int): RedisString = ## Get a substring of the string stored at a key r.sendCommand("GETRANGE", key, $start, $stop) return r.readBulkString() -proc getSet*(r: TRedis, key: string, value: string): TRedisString = +proc getSet*(r: Redis, key: string, value: string): RedisString = ## Set the string value of a key and return its old value. Returns `redisNil` ## when key doesn't exist. r.sendCommand("GETSET", key, value) return r.readBulkString() -proc incr*(r: TRedis, key: string): TRedisInteger = +proc incr*(r: Redis, key: string): RedisInteger = ## Increment the integer value of a key by one. r.sendCommand("INCR", key) return r.readInteger() -proc incrBy*(r: TRedis, key: string, increment: int): TRedisInteger = +proc incrBy*(r: Redis, key: string, increment: int): RedisInteger = ## Increment the integer value of a key by the given number r.sendCommand("INCRBY", key, $increment) return r.readInteger() -proc setk*(r: TRedis, key, value: string) = +proc setk*(r: Redis, key, value: string) = ## Set the string value of a key. ## ## NOTE: This function had to be renamed due to a clash with the `set` type. r.sendCommand("SET", key, value) raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc setNX*(r: TRedis, key, value: string): bool = +proc setNX*(r: Redis, key, value: string): bool = ## Set the value of a key, only if the key does not exist. Returns `true` ## if the key was set. r.sendCommand("SETNX", key, value) return r.readInteger() == 1 -proc setBit*(r: TRedis, key: string, offset: int, - value: string): TRedisInteger = +proc setBit*(r: Redis, key: string, offset: int, + value: string): RedisInteger = ## Sets or clears the bit at offset in the string value stored at key r.sendCommand("SETBIT", key, $offset, value) return r.readInteger() -proc setEx*(r: TRedis, key: string, seconds: int, value: string): TRedisStatus = +proc setEx*(r: Redis, key: string, seconds: int, value: string): RedisStatus = ## Set the value and expiration of a key r.sendCommand("SETEX", key, $seconds, value) raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc setRange*(r: TRedis, key: string, offset: int, - value: string): TRedisInteger = +proc setRange*(r: Redis, key: string, offset: int, + value: string): RedisInteger = ## Overwrite part of a string at key starting at the specified offset r.sendCommand("SETRANGE", key, $offset, value) return r.readInteger() -proc strlen*(r: TRedis, key: string): TRedisInteger = +proc strlen*(r: Redis, key: string): RedisInteger = ## Get the length of the value stored in a key. Returns 0 when key doesn't ## exist. r.sendCommand("STRLEN", key) return r.readInteger() # Hashes -proc hDel*(r: TRedis, key, field: string): bool = +proc hDel*(r: Redis, key, field: string): bool = ## Delete a hash field at `key`. Returns `true` if the field was removed. r.sendCommand("HDEL", key, field) return r.readInteger() == 1 -proc hExists*(r: TRedis, key, field: string): bool = +proc hExists*(r: Redis, key, field: string): bool = ## Determine if a hash field exists. r.sendCommand("HEXISTS", key, field) return r.readInteger() == 1 -proc hGet*(r: TRedis, key, field: string): TRedisString = +proc hGet*(r: Redis, key, field: string): RedisString = ## Get the value of a hash field r.sendCommand("HGET", key, field) return r.readBulkString() -proc hGetAll*(r: TRedis, key: string): TRedisList = +proc hGetAll*(r: Redis, key: string): RedisList = ## Get all the fields and values in a hash r.sendCommand("HGETALL", key) return r.readArray() -proc hIncrBy*(r: TRedis, key, field: string, incr: int): TRedisInteger = +proc hIncrBy*(r: Redis, key, field: string, incr: int): RedisInteger = ## Increment the integer value of a hash field by the given number r.sendCommand("HINCRBY", key, field, $incr) return r.readInteger() -proc hKeys*(r: TRedis, key: string): TRedisList = +proc hKeys*(r: Redis, key: string): RedisList = ## Get all the fields in a hash r.sendCommand("HKEYS", key) return r.readArray() -proc hLen*(r: TRedis, key: string): TRedisInteger = +proc hLen*(r: Redis, key: string): RedisInteger = ## Get the number of fields in a hash r.sendCommand("HLEN", key) return r.readInteger() -proc hMGet*(r: TRedis, key: string, fields: varargs[string]): TRedisList = +proc hMGet*(r: Redis, key: string, fields: varargs[string]): RedisList = ## Get the values of all the given hash fields r.sendCommand("HMGET", key, fields) return r.readArray() -proc hMSet*(r: TRedis, key: string, - fieldValues: openarray[tuple[field, value: string]]) = +proc hMSet*(r: Redis, key: string, + fieldValues: openArray[tuple[field, value: string]]) = ## Set multiple hash fields to multiple values var args = @[key] for field, value in items(fieldValues): @@ -456,24 +460,24 @@ proc hMSet*(r: TRedis, key: string, r.sendCommand("HMSET", args) raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc hSet*(r: TRedis, key, field, value: string): TRedisInteger = +proc hSet*(r: Redis, key, field, value: string): RedisInteger = ## Set the string value of a hash field r.sendCommand("HSET", key, field, value) return r.readInteger() -proc hSetNX*(r: TRedis, key, field, value: string): TRedisInteger = +proc hSetNX*(r: Redis, key, field, value: string): RedisInteger = ## Set the value of a hash field, only if the field does **not** exist r.sendCommand("HSETNX", key, field, value) return r.readInteger() -proc hVals*(r: TRedis, key: string): TRedisList = +proc hVals*(r: Redis, key: string): RedisList = ## Get all the values in a hash r.sendCommand("HVALS", key) return r.readArray() # Lists -proc bLPop*(r: TRedis, keys: varargs[string], timeout: int): TRedisList = +proc bLPop*(r: Redis, keys: varargs[string], timeout: int): RedisList = ## Remove and get the *first* element in a list, or block until ## one is available var args: seq[string] = @[] @@ -482,7 +486,7 @@ proc bLPop*(r: TRedis, keys: varargs[string], timeout: int): TRedisList = r.sendCommand("BLPOP", args) return r.readArray() -proc bRPop*(r: TRedis, keys: varargs[string], timeout: int): TRedisList = +proc bRPop*(r: Redis, keys: varargs[string], timeout: int): RedisList = ## Remove and get the *last* element in a list, or block until one ## is available. var args: seq[string] = @[] @@ -491,8 +495,8 @@ proc bRPop*(r: TRedis, keys: varargs[string], timeout: int): TRedisList = r.sendCommand("BRPOP", args) return r.readArray() -proc bRPopLPush*(r: TRedis, source, destination: string, - timeout: int): TRedisString = +proc bRPopLPush*(r: Redis, source, destination: string, + timeout: int): RedisString = ## Pop a value from a list, push it to another list and return it; or ## block until one is available. ## @@ -500,32 +504,32 @@ proc bRPopLPush*(r: TRedis, source, destination: string, r.sendCommand("BRPOPLPUSH", source, destination, $timeout) return r.readBulkString(true) # Multi-Bulk nil allowed. -proc lIndex*(r: TRedis, key: string, index: int): TRedisString = +proc lIndex*(r: Redis, key: string, index: int): RedisString = ## Get an element from a list by its index r.sendCommand("LINDEX", key, $index) return r.readBulkString() -proc lInsert*(r: TRedis, key: string, before: bool, pivot, value: string): - TRedisInteger = +proc lInsert*(r: Redis, key: string, before: bool, pivot, value: string): + RedisInteger = ## Insert an element before or after another element in a list var pos = if before: "BEFORE" else: "AFTER" r.sendCommand("LINSERT", key, pos, pivot, value) return r.readInteger() -proc lLen*(r: TRedis, key: string): TRedisInteger = +proc lLen*(r: Redis, key: string): RedisInteger = ## Get the length of a list r.sendCommand("LLEN", key) return r.readInteger() -proc lPop*(r: TRedis, key: string): TRedisString = +proc lPop*(r: Redis, key: string): RedisString = ## Remove and get the first element in a list r.sendCommand("LPOP", key) return r.readBulkString() -proc lPush*(r: TRedis, key, value: string, create: bool = True): TRedisInteger = +proc lPush*(r: Redis, key, value: string, create: bool = true): RedisInteger = ## Prepend a value to a list. Returns the length of the list after the push. ## The ``create`` param specifies whether a list should be created if it - ## doesn't exist at ``key``. More specifically if ``create`` is True, `LPUSH` + ## doesn't exist at ``key``. More specifically if ``create`` is true, `LPUSH` ## will be used, otherwise `LPUSHX`. if create: r.sendCommand("LPUSH", key, value) @@ -533,42 +537,42 @@ proc lPush*(r: TRedis, key, value: string, create: bool = True): TRedisInteger = r.sendCommand("LPUSHX", key, value) return r.readInteger() -proc lRange*(r: TRedis, key: string, start, stop: int): TRedisList = +proc lRange*(r: Redis, key: string, start, stop: int): RedisList = ## Get a range of elements from a list. Returns `nil` when `key` ## doesn't exist. r.sendCommand("LRANGE", key, $start, $stop) return r.readArray() -proc lRem*(r: TRedis, key: string, value: string, count: int = 0): TRedisInteger = +proc lRem*(r: Redis, key: string, value: string, count: int = 0): RedisInteger = ## Remove elements from a list. Returns the number of elements that have been ## removed. r.sendCommand("LREM", key, $count, value) return r.readInteger() -proc lSet*(r: TRedis, key: string, index: int, value: string) = +proc lSet*(r: Redis, key: string, index: int, value: string) = ## Set the value of an element in a list by its index r.sendCommand("LSET", key, $index, value) raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc lTrim*(r: TRedis, key: string, start, stop: int) = +proc lTrim*(r: Redis, key: string, start, stop: int) = ## Trim a list to the specified range r.sendCommand("LTRIM", key, $start, $stop) raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc rPop*(r: TRedis, key: string): TRedisString = +proc rPop*(r: Redis, key: string): RedisString = ## Remove and get the last element in a list r.sendCommand("RPOP", key) return r.readBulkString() -proc rPopLPush*(r: TRedis, source, destination: string): TRedisString = +proc rPopLPush*(r: Redis, source, destination: string): RedisString = ## Remove the last element in a list, append it to another list and return it r.sendCommand("RPOPLPUSH", source, destination) return r.readBulkString() -proc rPush*(r: TRedis, key, value: string, create: bool = True): TRedisInteger = +proc rPush*(r: Redis, key, value: string, create: bool = true): RedisInteger = ## Append a value to a list. Returns the length of the list after the push. ## The ``create`` param specifies whether a list should be created if it - ## doesn't exist at ``key``. More specifically if ``create`` is True, `RPUSH` + ## doesn't exist at ``key``. More specifically if ``create`` is true, `RPUSH` ## will be used, otherwise `RPUSHX`. if create: r.sendCommand("RPUSH", key, value) @@ -578,106 +582,106 @@ proc rPush*(r: TRedis, key, value: string, create: bool = True): TRedisInteger = # Sets -proc sadd*(r: TRedis, key: string, member: string): TRedisInteger = +proc sadd*(r: Redis, key: string, member: string): RedisInteger = ## Add a member to a set r.sendCommand("SADD", key, member) return r.readInteger() -proc scard*(r: TRedis, key: string): TRedisInteger = +proc scard*(r: Redis, key: string): RedisInteger = ## Get the number of members in a set r.sendCommand("SCARD", key) return r.readInteger() -proc sdiff*(r: TRedis, keys: varargs[string]): TRedisList = +proc sdiff*(r: Redis, keys: varargs[string]): RedisList = ## Subtract multiple sets r.sendCommand("SDIFF", keys) return r.readArray() -proc sdiffstore*(r: TRedis, destination: string, - keys: varargs[string]): TRedisInteger = +proc sdiffstore*(r: Redis, destination: string, + keys: varargs[string]): RedisInteger = ## Subtract multiple sets and store the resulting set in a key r.sendCommand("SDIFFSTORE", destination, keys) return r.readInteger() -proc sinter*(r: TRedis, keys: varargs[string]): TRedisList = +proc sinter*(r: Redis, keys: varargs[string]): RedisList = ## Intersect multiple sets r.sendCommand("SINTER", keys) return r.readArray() -proc sinterstore*(r: TRedis, destination: string, - keys: varargs[string]): TRedisInteger = +proc sinterstore*(r: Redis, destination: string, + keys: varargs[string]): RedisInteger = ## Intersect multiple sets and store the resulting set in a key r.sendCommand("SINTERSTORE", destination, keys) return r.readInteger() -proc sismember*(r: TRedis, key: string, member: string): TRedisInteger = +proc sismember*(r: Redis, key: string, member: string): RedisInteger = ## Determine if a given value is a member of a set r.sendCommand("SISMEMBER", key, member) return r.readInteger() -proc smembers*(r: TRedis, key: string): TRedisList = +proc smembers*(r: Redis, key: string): RedisList = ## Get all the members in a set r.sendCommand("SMEMBERS", key) return r.readArray() -proc smove*(r: TRedis, source: string, destination: string, - member: string): TRedisInteger = +proc smove*(r: Redis, source: string, destination: string, + member: string): RedisInteger = ## Move a member from one set to another r.sendCommand("SMOVE", source, destination, member) return r.readInteger() -proc spop*(r: TRedis, key: string): TRedisString = +proc spop*(r: Redis, key: string): RedisString = ## Remove and return a random member from a set r.sendCommand("SPOP", key) return r.readBulkString() -proc srandmember*(r: TRedis, key: string): TRedisString = +proc srandmember*(r: Redis, key: string): RedisString = ## Get a random member from a set r.sendCommand("SRANDMEMBER", key) return r.readBulkString() -proc srem*(r: TRedis, key: string, member: string): TRedisInteger = +proc srem*(r: Redis, key: string, member: string): RedisInteger = ## Remove a member from a set r.sendCommand("SREM", key, member) return r.readInteger() -proc sunion*(r: TRedis, keys: varargs[string]): TRedisList = +proc sunion*(r: Redis, keys: varargs[string]): RedisList = ## Add multiple sets r.sendCommand("SUNION", keys) return r.readArray() -proc sunionstore*(r: TRedis, destination: string, - key: varargs[string]): TRedisInteger = +proc sunionstore*(r: Redis, destination: string, + key: varargs[string]): RedisInteger = ## Add multiple sets and store the resulting set in a key r.sendCommand("SUNIONSTORE", destination, key) return r.readInteger() # Sorted sets -proc zadd*(r: TRedis, key: string, score: int, member: string): TRedisInteger = +proc zadd*(r: Redis, key: string, score: int, member: string): RedisInteger = ## Add a member to a sorted set, or update its score if it already exists r.sendCommand("ZADD", key, $score, member) return r.readInteger() -proc zcard*(r: TRedis, key: string): TRedisInteger = +proc zcard*(r: Redis, key: string): RedisInteger = ## Get the number of members in a sorted set r.sendCommand("ZCARD", key) return r.readInteger() -proc zcount*(r: TRedis, key: string, min: string, max: string): TRedisInteger = +proc zcount*(r: Redis, key: string, min: string, max: string): RedisInteger = ## Count the members in a sorted set with scores within the given values r.sendCommand("ZCOUNT", key, min, max) return r.readInteger() -proc zincrby*(r: TRedis, key: string, increment: string, - member: string): TRedisString = +proc zincrby*(r: Redis, key: string, increment: string, + member: string): RedisString = ## Increment the score of a member in a sorted set r.sendCommand("ZINCRBY", key, increment, member) return r.readBulkString() -proc zinterstore*(r: TRedis, destination: string, numkeys: string, - keys: openarray[string], weights: openarray[string] = [], - aggregate: string = ""): TRedisInteger = +proc zinterstore*(r: Redis, destination: string, numkeys: string, + keys: openArray[string], weights: openArray[string] = [], + aggregate: string = ""): RedisInteger = ## Intersect multiple sorted sets and store the resulting sorted set in ## a new key var args = @[destination, numkeys] @@ -694,8 +698,8 @@ proc zinterstore*(r: TRedis, destination: string, numkeys: string, return r.readInteger() -proc zrange*(r: TRedis, key: string, start: string, stop: string, - withScores: bool): TRedisList = +proc zrange*(r: Redis, key: string, start: string, stop: string, + withScores: bool): RedisList = ## Return a range of members in a sorted set, by index if not withScores: r.sendCommand("ZRANGE", key, start, stop) @@ -703,9 +707,9 @@ proc zrange*(r: TRedis, key: string, start: string, stop: string, r.sendCommand("ZRANGE", "WITHSCORES", key, start, stop) return r.readArray() -proc zrangebyscore*(r: TRedis, key: string, min: string, max: string, - withScore: bool = false, limit: bool = False, - limitOffset: int = 0, limitCount: int = 0): TRedisList = +proc zrangebyscore*(r: Redis, key: string, min: string, max: string, + withScore: bool = false, limit: bool = false, + limitOffset: int = 0, limitCount: int = 0): RedisList = ## Return a range of members in a sorted set, by score var args = @[key, min, max] @@ -718,30 +722,30 @@ proc zrangebyscore*(r: TRedis, key: string, min: string, max: string, r.sendCommand("ZRANGEBYSCORE", args) return r.readArray() -proc zrank*(r: TRedis, key: string, member: string): TRedisString = +proc zrank*(r: Redis, key: string, member: string): RedisString = ## Determine the index of a member in a sorted set r.sendCommand("ZRANK", key, member) return r.readBulkString() -proc zrem*(r: TRedis, key: string, member: string): TRedisInteger = +proc zrem*(r: Redis, key: string, member: string): RedisInteger = ## Remove a member from a sorted set r.sendCommand("ZREM", key, member) return r.readInteger() -proc zremrangebyrank*(r: TRedis, key: string, start: string, - stop: string): TRedisInteger = +proc zremrangebyrank*(r: Redis, key: string, start: string, + stop: string): RedisInteger = ## Remove all members in a sorted set within the given indexes r.sendCommand("ZREMRANGEBYRANK", key, start, stop) return r.readInteger() -proc zremrangebyscore*(r: TRedis, key: string, min: string, - max: string): TRedisInteger = +proc zremrangebyscore*(r: Redis, key: string, min: string, + max: string): RedisInteger = ## Remove all members in a sorted set within the given scores r.sendCommand("ZREMRANGEBYSCORE", key, min, max) return r.readInteger() -proc zrevrange*(r: TRedis, key: string, start: string, stop: string, - withScore: bool): TRedisList = +proc zrevrange*(r: Redis, key: string, start: string, stop: string, + withScore: bool): RedisList = ## Return a range of members in a sorted set, by index, ## with scores ordered from high to low if withScore: @@ -749,9 +753,9 @@ proc zrevrange*(r: TRedis, key: string, start: string, stop: string, else: r.sendCommand("ZREVRANGE", key, start, stop) return r.readArray() -proc zrevrangebyscore*(r: TRedis, key: string, min: string, max: string, - withScore: bool = false, limit: bool = False, - limitOffset: int = 0, limitCount: int = 0): TRedisList = +proc zrevrangebyscore*(r: Redis, key: string, min: string, max: string, + withScore: bool = false, limit: bool = false, + limitOffset: int = 0, limitCount: int = 0): RedisList = ## Return a range of members in a sorted set, by score, with ## scores ordered from high to low var args = @[key, min, max] @@ -765,20 +769,20 @@ proc zrevrangebyscore*(r: TRedis, key: string, min: string, max: string, r.sendCommand("ZREVRANGEBYSCORE", args) return r.readArray() -proc zrevrank*(r: TRedis, key: string, member: string): TRedisString = +proc zrevrank*(r: Redis, key: string, member: string): RedisString = ## Determine the index of a member in a sorted set, with ## scores ordered from high to low r.sendCommand("ZREVRANK", key, member) return r.readBulkString() -proc zscore*(r: TRedis, key: string, member: string): TRedisString = +proc zscore*(r: Redis, key: string, member: string): RedisString = ## Get the score associated with the given member in a sorted set r.sendCommand("ZSCORE", key, member) return r.readBulkString() -proc zunionstore*(r: TRedis, destination: string, numkeys: string, - keys: openarray[string], weights: openarray[string] = [], - aggregate: string = ""): TRedisInteger = +proc zunionstore*(r: Redis, destination: string, numkeys: string, + keys: openArray[string], weights: openArray[string] = [], + aggregate: string = ""): RedisInteger = ## Add multiple sorted sets and store the resulting sorted set in a new key var args = @[destination, numkeys] for i in items(keys): args.add(i) @@ -828,12 +832,12 @@ proc unsubscribe*(r: TRedis, [channel: openarray[string], : string): ???? = # Transactions -proc discardMulti*(r: TRedis) = +proc discardMulti*(r: Redis) = ## Discard all commands issued after MULTI r.sendCommand("DISCARD") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc exec*(r: TRedis): TRedisList = +proc exec*(r: Redis): RedisList = ## Execute all commands issued after MULTI r.sendCommand("EXEC") r.pipeline.enabled = false @@ -842,106 +846,106 @@ proc exec*(r: TRedis): TRedisList = return r.flushPipeline(true) -proc multi*(r: TRedis) = +proc multi*(r: Redis) = ## Mark the start of a transaction block r.startPipelining() r.sendCommand("MULTI") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc unwatch*(r: TRedis) = +proc unwatch*(r: Redis) = ## Forget about all watched keys r.sendCommand("UNWATCH") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc watch*(r: TRedis, key: varargs[string]) = +proc watch*(r: Redis, key: varargs[string]) = ## Watch the given keys to determine execution of the MULTI/EXEC block r.sendCommand("WATCH", key) raiseNoOK(r.readStatus(), r.pipeline.enabled) # Connection -proc auth*(r: TRedis, password: string) = +proc auth*(r: Redis, password: string) = ## Authenticate to the server r.sendCommand("AUTH", password) raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc echoServ*(r: TRedis, message: string): TRedisString = +proc echoServ*(r: Redis, message: string): RedisString = ## Echo the given string r.sendCommand("ECHO", message) return r.readBulkString() -proc ping*(r: TRedis): TRedisStatus = +proc ping*(r: Redis): RedisStatus = ## Ping the server r.sendCommand("PING") return r.readStatus() -proc quit*(r: TRedis) = +proc quit*(r: Redis) = ## Close the connection r.sendCommand("QUIT") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc select*(r: TRedis, index: int): TRedisStatus = +proc select*(r: Redis, index: int): RedisStatus = ## Change the selected database for the current connection r.sendCommand("SELECT", $index) return r.readStatus() # Server -proc bgrewriteaof*(r: TRedis) = +proc bgrewriteaof*(r: Redis) = ## Asynchronously rewrite the append-only file r.sendCommand("BGREWRITEAOF") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc bgsave*(r: TRedis) = +proc bgsave*(r: Redis) = ## Asynchronously save the dataset to disk r.sendCommand("BGSAVE") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc configGet*(r: TRedis, parameter: string): TRedisList = +proc configGet*(r: Redis, parameter: string): RedisList = ## Get the value of a configuration parameter r.sendCommand("CONFIG", "GET", parameter) return r.readArray() -proc configSet*(r: TRedis, parameter: string, value: string) = +proc configSet*(r: Redis, parameter: string, value: string) = ## Set a configuration parameter to the given value r.sendCommand("CONFIG", "SET", parameter, value) raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc configResetStat*(r: TRedis) = +proc configResetStat*(r: Redis) = ## Reset the stats returned by INFO r.sendCommand("CONFIG", "RESETSTAT") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc dbsize*(r: TRedis): TRedisInteger = +proc dbsize*(r: Redis): RedisInteger = ## Return the number of keys in the selected database r.sendCommand("DBSIZE") return r.readInteger() -proc debugObject*(r: TRedis, key: string): TRedisStatus = +proc debugObject*(r: Redis, key: string): RedisStatus = ## Get debugging information about a key r.sendCommand("DEBUG", "OBJECT", key) return r.readStatus() -proc debugSegfault*(r: TRedis) = +proc debugSegfault*(r: Redis) = ## Make the server crash r.sendCommand("DEBUG", "SEGFAULT") -proc flushall*(r: TRedis): TRedisStatus = +proc flushall*(r: Redis): RedisStatus = ## Remove all keys from all databases r.sendCommand("FLUSHALL") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc flushdb*(r: TRedis): TRedisStatus = +proc flushdb*(r: Redis): RedisStatus = ## Remove all keys from the current database r.sendCommand("FLUSHDB") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc info*(r: TRedis): TRedisString = +proc info*(r: Redis): RedisString = ## Get information and statistics about the server r.sendCommand("INFO") return r.readBulkString() -proc lastsave*(r: TRedis): TRedisInteger = +proc lastsave*(r: Redis): RedisInteger = ## Get the UNIX time stamp of the last successful save to disk r.sendCommand("LASTSAVE") return r.readInteger() @@ -953,24 +957,24 @@ proc monitor*(r: TRedis) = raiseNoOK(r.readStatus(), r.pipeline.enabled) """ -proc save*(r: TRedis) = +proc save*(r: Redis) = ## Synchronously save the dataset to disk r.sendCommand("SAVE") raiseNoOK(r.readStatus(), r.pipeline.enabled) -proc shutdown*(r: TRedis) = +proc shutdown*(r: Redis) = ## Synchronously save the dataset to disk and then shut down the server r.sendCommand("SHUTDOWN") var s = "".TaintedString r.socket.readLine(s) - if s.string.len != 0: raise newException(ERedis, s.string) + if s.string.len != 0: raise newException(RedisError, s.string) -proc slaveof*(r: TRedis, host: string, port: string) = +proc slaveof*(r: Redis, host: string, port: string) = ## Make the server a slave of another instance, or promote it as master r.sendCommand("SLAVEOF", host, port) raiseNoOK(r.readStatus(), r.pipeline.enabled) -iterator hPairs*(r: TRedis, key: string): tuple[key, value: string] = +iterator hPairs*(r: Redis, key: string): tuple[key, value: string] = ## Iterator for keys and values in a hash. var contents = r.hGetAll(key) @@ -982,7 +986,7 @@ iterator hPairs*(r: TRedis, key: string): tuple[key, value: string] = yield (k, i) k = "" -proc someTests(r: TRedis, how: TSendMode):seq[string] = +proc someTests(r: Redis, how: SendMode):seq[string] = var list:seq[string] = @[] if how == pipelined: @@ -1003,10 +1007,10 @@ proc someTests(r: TRedis, how: TSendMode):seq[string] = for r in res: list.add(r) list.add(r.get("invalid_key")) - list.add($(r.lpush("mylist","itema"))) - list.add($(r.lpush("mylist","itemb"))) - r.ltrim("mylist",0,1) - var p = r.lrange("mylist", 0, -1) + list.add($(r.lPush("mylist","itema"))) + list.add($(r.lPush("mylist","itemb"))) + r.lTrim("mylist",0,1) + var p = r.lRange("mylist", 0, -1) for i in items(p): if not isNil(i): diff --git a/lib/pure/romans.nim b/lib/pure/romans.nim index dee3226d8..79fb75526 100644 --- a/lib/pure/romans.nim +++ b/lib/pure/romans.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2011 Philippe Lhoste # # See the file "copying.txt", included in this diff --git a/lib/pure/ropes.nim b/lib/pure/ropes.nim index eb3792bce..995dff2aa 100644 --- a/lib/pure/ropes.nim +++ b/lib/pure/ropes.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this @@ -10,7 +10,7 @@ ## This module contains support for a `rope`:idx: data type. ## Ropes can represent very long strings efficiently; especially concatenation ## is done in O(1) instead of O(n). They are essentially concatenation -## trees that are only flattened when converting to a native Nimrod +## trees that are only flattened when converting to a native Nim ## string. The empty string is represented by ``nil``. Ropes are immutable and ## subtrees can be shared without copying. ## Leaves can be cached for better memory efficiency at the cost of @@ -30,13 +30,15 @@ var cacheEnabled = false type - PRope* = ref TRope ## empty rope is represented by nil - TRope {.acyclic, final, pure.} = object - left, right: PRope + Rope* = ref RopeObj ## empty rope is represented by nil + RopeObj {.acyclic.} = object + left, right: Rope length: int data: string # != nil if a leaf -proc isConc(r: PRope): bool {.inline.} = return isNil(r.data) +{.deprecated: [PRope: Rope].} + +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 @@ -46,25 +48,25 @@ proc isConc(r: PRope): bool {.inline.} = return isNil(r.data) # performance. But for the caching tree we use the leaf's left and right # pointers. -proc len*(a: PRope): int {.rtl, extern: "nro$1".} = +proc len*(a: Rope): int {.rtl, extern: "nro$1".} = ## the rope's length if a == nil: result = 0 else: result = a.length -proc newRope(): PRope = new(result) -proc newRope(data: string): PRope = +proc newRope(): Rope = new(result) +proc newRope(data: string): Rope = new(result) result.length = len(data) result.data = data var - cache {.threadvar.}: PRope # the root of the cache tree - N {.threadvar.}: PRope # dummy rope needed for splay algorithm + cache {.threadvar.}: Rope # the root of the cache tree + N {.threadvar.}: Rope # dummy rope needed for splay algorithm when countCacheMisses: var misses, hits: int -proc splay(s: string, tree: PRope, cmpres: var int): PRope = +proc splay(s: string, tree: Rope, cmpres: var int): Rope = var c: int var t = tree N.left = nil @@ -102,7 +104,7 @@ proc splay(s: string, tree: PRope, cmpres: var int): PRope = t.right = N.left result = t -proc insertInCache(s: string, tree: PRope): PRope = +proc insertInCache(s: string, tree: Rope): Rope = var t = tree if t == nil: result = newRope(s) @@ -128,7 +130,7 @@ proc insertInCache(s: string, tree: PRope): PRope = result.left = t t.right = nil -proc rope*(s: string): PRope {.rtl, extern: "nro$1Str".} = +proc rope*(s: string): Rope {.rtl, extern: "nro$1Str".} = ## Converts a string to a rope. if s.len == 0: result = nil @@ -138,11 +140,11 @@ proc rope*(s: string): PRope {.rtl, extern: "nro$1Str".} = else: result = newRope(s) -proc rope*(i: BiggestInt): PRope {.rtl, extern: "nro$1BiggestInt".} = +proc rope*(i: BiggestInt): Rope {.rtl, extern: "nro$1BiggestInt".} = ## Converts an int to a rope. result = rope($i) -proc rope*(f: BiggestFloat): PRope {.rtl, extern: "nro$1BiggestFloat".} = +proc rope*(f: BiggestFloat): Rope {.rtl, extern: "nro$1BiggestFloat".} = ## Converts a float to a rope. result = rope($f) @@ -156,7 +158,7 @@ proc disableCache*() {.rtl, extern: "nro$1".} = cache = nil cacheEnabled = false -proc `&`*(a, b: PRope): PRope {.rtl, extern: "nroConcRopeRope".} = +proc `&`*(a, b: Rope): Rope {.rtl, extern: "nroConcRopeRope".} = ## the concatenation operator for ropes. if a == nil: result = b @@ -176,27 +178,27 @@ proc `&`*(a, b: PRope): PRope {.rtl, extern: "nroConcRopeRope".} = result.left = a result.right = b -proc `&`*(a: PRope, b: string): PRope {.rtl, extern: "nroConcRopeStr".} = +proc `&`*(a: Rope, b: string): Rope {.rtl, extern: "nroConcRopeStr".} = ## the concatenation operator for ropes. result = a & rope(b) -proc `&`*(a: string, b: PRope): PRope {.rtl, extern: "nroConcStrRope".} = +proc `&`*(a: string, b: Rope): Rope {.rtl, extern: "nroConcStrRope".} = ## the concatenation operator for ropes. result = rope(a) & b -proc `&`*(a: openarray[PRope]): PRope {.rtl, extern: "nroConcOpenArray".} = +proc `&`*(a: openArray[Rope]): Rope {.rtl, extern: "nroConcOpenArray".} = ## the concatenation operator for an openarray of ropes. for i in countup(0, high(a)): result = result & a[i] -proc add*(a: var PRope, b: PRope) {.rtl, extern: "nro$1Rope".} = +proc add*(a: var Rope, b: Rope) {.rtl, extern: "nro$1Rope".} = ## adds `b` to the rope `a`. a = a & b -proc add*(a: var PRope, b: string) {.rtl, extern: "nro$1Str".} = +proc add*(a: var Rope, b: string) {.rtl, extern: "nro$1Str".} = ## adds `b` to the rope `a`. a = a & b -proc `[]`*(r: PRope, i: int): char {.rtl, extern: "nroCharAt".} = +proc `[]`*(r: Rope, i: int): char {.rtl, extern: "nroCharAt".} = ## returns the character at position `i` in the rope `r`. This is quite ## expensive! Worst-case: O(n). If ``i >= r.len``, ``\0`` is returned. var x = r @@ -213,7 +215,7 @@ proc `[]`*(r: PRope, i: int): char {.rtl, extern: "nroCharAt".} = x = x.right dec(j, x.len) -iterator leaves*(r: PRope): string = +iterator leaves*(r: Rope): string = ## iterates over any leaf string in the rope `r`. if r != nil: var stack = @[r] @@ -226,16 +228,16 @@ iterator leaves*(r: PRope): string = assert(it.data != nil) yield it.data -iterator items*(r: PRope): char = +iterator items*(r: Rope): char = ## iterates over any character in the rope `r`. for s in leaves(r): for c in items(s): yield c -proc write*(f: TFile, r: PRope) {.rtl, extern: "nro$1".} = +proc write*(f: File, r: Rope) {.rtl, extern: "nro$1".} = ## writes a rope to a file. for s in leaves(r): write(f, s) -proc `$`*(r: PRope): string {.rtl, extern: "nroToString".}= +proc `$`*(r: Rope): string {.rtl, extern: "nroToString".}= ## converts a rope back to a string. result = newString(r.len) setLen(result, 0) @@ -245,11 +247,11 @@ when false: # Format string caching seems reasonable: All leaves can be shared and format # string parsing has to be done only once. A compiled format string is stored # as a rope. A negative length is used for the index into the args array. - proc compiledArg(idx: int): PRope = + proc compiledArg(idx: int): Rope = new(result) result.length = -idx - proc compileFrmt(frmt: string): PRope = + proc compileFrmt(frmt: string): Rope = var i = 0 var length = len(frmt) result = nil @@ -289,7 +291,7 @@ when false: if i - 1 >= start: add(result, substr(frmt, start, i-1)) -proc `%`*(frmt: string, args: openarray[PRope]): PRope {. +proc `%`*(frmt: string, args: openArray[Rope]): Rope {. rtl, extern: "nroFormat".} = ## `%` substitution operator for ropes. Does not support the ``$identifier`` ## nor ``${identifier}`` notations. @@ -322,9 +324,9 @@ proc `%`*(frmt: string, args: openarray[PRope]): PRope {. j = j * 10 + ord(frmt[i]) - ord('0') inc(i) if frmt[i] == '}': inc(i) - else: raise newException(EInvalidValue, "invalid format string") + else: raise newException(ValueError, "invalid format string") add(result, args[j-1]) - else: raise newException(EInvalidValue, "invalid format string") + else: raise newException(ValueError, "invalid format string") var start = i while i < length: if frmt[i] != '$': inc(i) @@ -332,15 +334,15 @@ proc `%`*(frmt: string, args: openarray[PRope]): PRope {. if i - 1 >= start: add(result, substr(frmt, start, i - 1)) -proc addf*(c: var PRope, frmt: string, args: openarray[PRope]) {. +proc addf*(c: var Rope, frmt: string, args: openArray[Rope]) {. rtl, extern: "nro$1".} = ## shortcut for ``add(c, frmt % args)``. add(c, frmt % args) -proc equalsFile*(r: PRope, f: TFile): bool {.rtl, extern: "nro$1File".} = +proc equalsFile*(r: Rope, f: File): bool {.rtl, extern: "nro$1File".} = ## returns true if the contents of the file `f` equal `r`. var bufSize = 1024 # reasonable start value - var buf = alloc(BufSize) + var buf = alloc(bufSize) for s in leaves(r): if s.len > bufSize: bufSize = max(bufSize * 2, s.len) @@ -352,10 +354,10 @@ proc equalsFile*(r: PRope, f: TFile): bool {.rtl, extern: "nro$1File".} = result = readBuffer(f, buf, 1) == 0 # really at the end of file? dealloc(buf) -proc equalsFile*(r: PRope, f: string): bool {.rtl, extern: "nro$1Str".} = +proc equalsFile*(r: Rope, f: string): bool {.rtl, extern: "nro$1Str".} = ## returns true if the contents of the file `f` equal `r`. If `f` does not ## exist, false is returned. - var bin: TFile + var bin: File result = open(bin, f) if result: result = equalsFile(r, bin) diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim index 45f837833..58b37833a 100644 --- a/lib/pure/scgi.nim +++ b/lib/pure/scgi.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf, Dominik Picheta # # See the file "copying.txt", included in this @@ -9,13 +9,13 @@ ## This module implements helper procs for SCGI applications. Example: ## -## .. code-block:: Nimrod +## .. code-block:: Nim ## ## import strtabs, sockets, scgi ## ## var counter = 0 -## proc handleRequest(client: TSocket, input: string, -## headers: PStringTable): bool {.procvar.} = +## proc handleRequest(client: Socket, input: string, +## headers: StringTableRef): bool {.procvar.} = ## inc(counter) ## client.writeStatusOkTextContent() ## client.send("Hello for the $#th time." % $counter & "\c\L") @@ -31,11 +31,11 @@ include "system/inclrtl" import sockets, strutils, os, strtabs, asyncio type - EScgi* = object of EIO ## the exception that is raised, if a SCGI error occurs + ScgiError* = object of IOError ## the exception that is raised, if a SCGI error occurs -proc scgiError*(msg: string) {.noreturn.} = - ## raises an EScgi exception with message `msg`. - var e: ref EScgi +proc raiseScgiError*(msg: string) {.noreturn.} = + ## raises an ScgiError exception with message `msg`. + var e: ref ScgiError new(e) e.msg = msg raise e @@ -45,7 +45,7 @@ proc parseWord(inp: string, outp: var string, start: int): int = while inp[result] != '\0': inc(result) outp = substr(inp, start, result-1) -proc parseHeaders(s: string, L: int): PStringTable = +proc parseHeaders(s: string, L: int): StringTableRef = result = newStringTable() var i = 0 while i < L: @@ -54,73 +54,77 @@ proc parseHeaders(s: string, L: int): PStringTable = i = parseWord(s, val, i)+1 result[key] = val if s[i] == ',': inc(i) - else: scgiError("',' after netstring expected") + else: raiseScgiError("',' after netstring expected") -proc recvChar(s: TSocket): char = +proc recvChar(s: Socket): char = var c: char if recv(s, addr(c), sizeof(c)) == sizeof(c): result = c type - TScgiState* = object of TObject ## SCGI state object - server: TSocket + ScgiState* = object of RootObj ## SCGI state object + server: Socket bufLen: int - client*: TSocket ## the client socket to send data to - headers*: PStringTable ## the parsed headers + client*: Socket ## the client socket to send data to + headers*: StringTableRef ## the parsed headers input*: string ## the input buffer # Async - TClientMode = enum + ClientMode = enum ClientReadChar, ClientReadHeaders, ClientReadContent - PAsyncClient = ref object - c: PAsyncSocket - mode: TClientMode + AsyncClient = ref object + c: AsyncSocket + mode: ClientMode dataLen: int - headers: PStringTable ## the parsed headers + headers: StringTableRef ## the parsed headers input: string ## the input buffer - TAsyncScgiState = object - handleRequest: proc (client: PAsyncSocket, - input: string, headers: PStringTable) {.closure,gcsafe.} - asyncServer: PAsyncSocket - disp: PDispatcher - PAsyncScgiState* = ref TAsyncScgiState - -proc recvBuffer(s: var TScgiState, L: int) = + AsyncScgiStateObj = object + handleRequest: proc (client: AsyncSocket, + input: string, + headers: StringTableRef) {.closure, gcsafe.} + asyncServer: AsyncSocket + disp: Dispatcher + AsyncScgiState* = ref AsyncScgiStateObj + +{.deprecated: [EScgi: ScgiError, TScgiState: ScgiState, + PAsyncScgiState: AsyncScgiState, scgiError: raiseScgiError].} + +proc recvBuffer(s: var ScgiState, L: int) = if L > s.bufLen: s.bufLen = L s.input = newString(L) if L > 0 and recv(s.client, cstring(s.input), L) != L: - scgiError("could not read all data") + raiseScgiError("could not read all data") setLen(s.input, L) -proc open*(s: var TScgiState, port = TPort(4000), address = "127.0.0.1", - reuseAddr = False) = +proc open*(s: var ScgiState, port = Port(4000), address = "127.0.0.1", + reuseAddr = false) = ## opens a connection. s.bufLen = 4000 - s.input = newString(s.buflen) # will be reused + s.input = newString(s.bufLen) # will be reused s.server = socket() - if s.server == InvalidSocket: osError(osLastError()) + if s.server == invalidSocket: raiseOSError(osLastError()) new(s.client) # Initialise s.client for `next` - if s.server == InvalidSocket: scgiError("could not open socket") + if s.server == invalidSocket: raiseScgiError("could not open socket") #s.server.connect(connectionName, port) if reuseAddr: - s.server.setSockOpt(OptReuseAddr, True) + s.server.setSockOpt(OptReuseAddr, true) bindAddr(s.server, port, address) listen(s.server) -proc close*(s: var TScgiState) = +proc close*(s: var ScgiState) = ## closes the connection. s.server.close() -proc next*(s: var TScgistate, timeout: int = -1): bool = +proc next*(s: var ScgiState, timeout: int = -1): bool = ## proceed to the first/next request. Waits ``timeout`` miliseconds for a ## request, if ``timeout`` is `-1` then this function will never time out. - ## Returns `True` if a new request has been processed. + ## Returns `true` if a new request has been processed. var rsocks = @[s.server] if select(rsocks, timeout) == 1 and rsocks.len == 1: new(s.client) @@ -131,18 +135,18 @@ proc next*(s: var TScgistate, timeout: int = -1): bool = if d == '\0': s.client.close() return false - if d notin strutils.digits: - if d != ':': scgiError("':' after length expected") + if d notin strutils.Digits: + if d != ':': raiseScgiError("':' after length expected") break L = L * 10 + ord(d) - ord('0') recvBuffer(s, L+1) s.headers = parseHeaders(s.input, L) - if s.headers["SCGI"] != "1": scgiError("SCGI Version 1 expected") + if s.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected") L = parseInt(s.headers["CONTENT_LENGTH"]) recvBuffer(s, L) - return True + return true -proc writeStatusOkTextContent*(c: TSocket, contentType = "text/html") = +proc writeStatusOkTextContent*(c: Socket, contentType = "text/html") = ## sends the following string to the socket `c`:: ## ## Status: 200 OK\r\LContent-Type: text/html\r\L\r\L @@ -151,11 +155,11 @@ proc writeStatusOkTextContent*(c: TSocket, contentType = "text/html") = c.send("Status: 200 OK\r\L" & "Content-Type: $1\r\L\r\L" % contentType) -proc run*(handleRequest: proc (client: TSocket, input: string, - headers: PStringTable): bool {.nimcall,gcsafe.}, - port = TPort(4000)) = +proc run*(handleRequest: proc (client: Socket, input: string, + headers: StringTableRef): bool {.nimcall,gcsafe.}, + port = Port(4000)) = ## encapsulates the SCGI object and main loop. - var s: TScgiState + var s: ScgiState s.open(port) var stop = false while not stop: @@ -166,11 +170,11 @@ proc run*(handleRequest: proc (client: TSocket, input: string, # -- AsyncIO start -proc recvBufferAsync(client: PAsyncClient, L: int): TReadLineResult = +proc recvBufferAsync(client: AsyncClient, L: int): ReadLineResult = result = ReadPartialLine var data = "" if L < 1: - scgiError("Cannot read negative or zero length: " & $L) + raiseScgiError("Cannot read negative or zero length: " & $L) let ret = recvAsync(client.c, data, L) if ret == 0 and data == "": client.c.close() @@ -181,16 +185,16 @@ proc recvBufferAsync(client: PAsyncClient, L: int): TReadLineResult = if ret == L: return ReadFullLine -proc checkCloseSocket(client: PAsyncClient) = +proc checkCloseSocket(client: AsyncClient) = if not client.c.isClosed: if client.c.isSendDataBuffered: - client.c.setHandleWrite do (s: PAsyncSocket): + client.c.setHandleWrite do (s: AsyncSocket): if not s.isClosed and not s.isSendDataBuffered: s.close() s.delHandleWrite() else: client.c.close() -proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) = +proc handleClientRead(client: AsyncClient, s: AsyncScgiState) = case client.mode of ClientReadChar: while true: @@ -202,8 +206,8 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) = return if ret == -1: return # No more data available - if d[0] notin strutils.digits: - if d[0] != ':': scgiError("':' after length expected") + if d[0] notin strutils.Digits: + if d[0] != ':': raiseScgiError("':' after length expected") break client.dataLen = client.dataLen * 10 + ord(d[0]) - ord('0') client.mode = ClientReadHeaders @@ -213,7 +217,7 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) = case ret of ReadFullLine: client.headers = parseHeaders(client.input, client.input.len-1) - if client.headers["SCGI"] != "1": scgiError("SCGI Version 1 expected") + if client.headers["SCGI"] != "1": raiseScgiError("SCGI Version 1 expected") client.input = "" # For next part let contentLen = parseInt(client.headers["CONTENT_LENGTH"]) @@ -236,50 +240,50 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) = s.handleRequest(client.c, client.input, client.headers) checkCloseSocket(client) -proc handleAccept(sock: PAsyncSocket, s: PAsyncScgiState) = - var client: PAsyncSocket +proc handleAccept(sock: AsyncSocket, s: AsyncScgiState) = + var client: AsyncSocket new(client) accept(s.asyncServer, client) - var asyncClient = PAsyncClient(c: client, mode: ClientReadChar, dataLen: 0, + var asyncClient = AsyncClient(c: client, mode: ClientReadChar, dataLen: 0, headers: newStringTable(), input: "") client.handleRead = - proc (sock: PAsyncSocket) = + proc (sock: AsyncSocket) = handleClientRead(asyncClient, s) s.disp.register(client) -proc open*(handleRequest: proc (client: PAsyncSocket, - input: string, headers: PStringTable) {. +proc open*(handleRequest: proc (client: AsyncSocket, + input: string, headers: StringTableRef) {. closure, gcsafe.}, - port = TPort(4000), address = "127.0.0.1", - reuseAddr = false): PAsyncScgiState = - ## Creates an ``PAsyncScgiState`` object which serves as a SCGI server. + port = Port(4000), address = "127.0.0.1", + reuseAddr = false): AsyncScgiState = + ## Creates an ``AsyncScgiState`` object which serves as a SCGI server. ## ## After the execution of ``handleRequest`` the client socket will be closed ## automatically unless it has already been closed. - var cres: PAsyncScgiState + var cres: AsyncScgiState new(cres) - cres.asyncServer = AsyncSocket() - cres.asyncServer.handleAccept = proc (s: PAsyncSocket) = handleAccept(s, cres) + cres.asyncServer = asyncSocket() + cres.asyncServer.handleAccept = proc (s: AsyncSocket) = handleAccept(s, cres) if reuseAddr: - cres.asyncServer.setSockOpt(OptReuseAddr, True) + cres.asyncServer.setSockOpt(OptReuseAddr, true) bindAddr(cres.asyncServer, port, address) listen(cres.asyncServer) cres.handleRequest = handleRequest result = cres -proc register*(d: PDispatcher, s: PAsyncScgiState): PDelegate {.discardable.} = +proc register*(d: Dispatcher, s: AsyncScgiState): Delegate {.discardable.} = ## Registers ``s`` with dispatcher ``d``. result = d.register(s.asyncServer) s.disp = d -proc close*(s: PAsyncScgiState) = - ## Closes the ``PAsyncScgiState``. +proc close*(s: AsyncScgiState) = + ## Closes the ``AsyncScgiState``. s.asyncServer.close() when false: var counter = 0 - proc handleRequest(client: TSocket, input: string, - headers: PStringTable): bool {.procvar.} = + proc handleRequest(client: Socket, input: string, + headers: StringTableRef): bool {.procvar.} = inc(counter) client.writeStatusOkTextContent() client.send("Hello for the $#th time." % $counter & "\c\L") diff --git a/lib/pure/selectors.nim b/lib/pure/selectors.nim index bd53c2dbf..1c988c609 100644 --- a/lib/pure/selectors.nim +++ b/lib/pure/selectors.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # # See the file "copying.txt", included in this @@ -18,57 +18,57 @@ elif defined(windows): else: import posix -proc hash*(x: TSocketHandle): THash {.borrow.} -proc `$`*(x: TSocketHandle): string {.borrow.} +proc hash*(x: SocketHandle): THash {.borrow.} +proc `$`*(x: SocketHandle): string {.borrow.} type - TEvent* = enum + Event* = enum EvRead, EvWrite - PSelectorKey* = ref object - fd*: TSocketHandle - events*: set[TEvent] ## The events which ``fd`` listens for. - data*: PObject ## User object. + SelectorKey* = ref object + fd*: SocketHandle + events*: set[Event] ## The events which ``fd`` listens for. + data*: RootRef ## User object. - TReadyInfo* = tuple[key: PSelectorKey, events: set[TEvent]] + ReadyInfo* = tuple[key: SelectorKey, events: set[Event]] when defined(nimdoc): type - PSelector* = ref object + Selector* = ref object ## An object which holds file descripters to be checked for read/write ## status. - fds: TTable[TSocketHandle, PSelectorKey] + fds: Table[SocketHandle, SelectorKey] - proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent], - data: PObject): PSelectorKey {.discardable.} = + 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``. - proc update*(s: PSelector, fd: TSocketHandle, - events: set[TEvent]): PSelectorKey {.discardable.} = + proc update*(s: Selector, fd: SocketHandle, + events: set[Event]): SelectorKey {.discardable.} = ## Updates the events which ``fd`` wants notifications for. - proc select*(s: PSelector, timeout: int): seq[TReadyInfo] = + 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 contains*(s: PSelector, fd: TSocketHandle): bool = + proc contains*(s: Selector, fd: SocketHandle): bool = ## Determines whether selector contains a file descriptor. - proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey = + proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey = ## Retrieves the selector key for ``fd``. elif defined(linux): type - PSelector* = ref object + Selector* = ref object epollFD: cint events: array[64, epoll_event] - fds: TTable[TSocketHandle, PSelectorKey] + fds: Table[SocketHandle, SelectorKey] - proc createEventStruct(events: set[TEvent], fd: TSocketHandle): epoll_event = + proc createEventStruct(events: set[Event], fd: SocketHandle): epoll_event = if EvRead in events: result.events = EPOLLIN if EvWrite in events: @@ -76,22 +76,22 @@ elif defined(linux): result.events = result.events or EPOLLRDHUP result.data.fd = fd.cint - proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent], - data: PObject): PSelectorKey {.discardable.} = + 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: - OSError(OSLastError()) + raiseOSError(osLastError()) - var key = PSelectorKey(fd: fd, events: events, data: data) + var key = SelectorKey(fd: fd, events: events, data: data) s.fds[fd] = key result = key - proc update*(s: PSelector, fd: TSocketHandle, - events: set[TEvent]): PSelectorKey {.discardable.} = + 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 == {}: @@ -101,7 +101,7 @@ elif defined(linux): # because its got fds which are waiting for no events and # are therefore constantly ready. (leading to 100% CPU usage). if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0: - OSError(OSLastError()) + raiseOSError(osLastError()) s.fds[fd].events = events else: var event = createEventStruct(events, fd) @@ -109,36 +109,36 @@ elif defined(linux): # This fd is idle. It's not a member of this epoll instance and must # be re-registered. if epoll_ctl(s.epollFD, EPOLL_CTL_ADD, fd, addr(event)) != 0: - OSError(OSLastError()) + raiseOSError(osLastError()) else: if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0: - OSError(OSLastError()) + raiseOSError(osLastError()) s.fds[fd].events = events result = s.fds[fd] - proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} = + proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} = if epoll_ctl(s.epollFD, EPOLL_CTL_DEL, fd, nil) != 0: - let err = OSLastError() + let err = osLastError() if err.cint notin {ENOENT, EBADF}: # TODO: Why do we sometimes get an EBADF? Is this normal? - OSError(err) + raiseOSError(err) result = s.fds[fd] s.fds.del(fd) - proc close*(s: PSelector) = - if s.epollFD.close() != 0: OSError(OSLastError()) + proc close*(s: Selector) = + if s.epollFD.close() != 0: raiseOSError(osLastError()) dealloc(addr s.events) # TODO: Test this - proc epollHasFd(s: PSelector, fd: TSocketHandle): bool = + proc epollHasFd(s: Selector, fd: SocketHandle): bool = result = true var event = createEventStruct(s.fds[fd].events, fd) if epoll_ctl(s.epollFD, EPOLL_CTL_MOD, fd, addr(event)) != 0: let err = osLastError() if err.cint in {ENOENT, EBADF}: return false - OSError(OSLastError()) + raiseOSError(osLastError()) - proc select*(s: PSelector, timeout: int): seq[TReadyInfo] = + 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 @@ -146,12 +146,12 @@ elif defined(linux): ## on the ``fd``. result = @[] let evNum = epoll_wait(s.epollFD, addr s.events[0], 64.cint, timeout.cint) - if evNum < 0: OSError(OSLastError()) + if evNum < 0: raiseOSError(osLastError()) if evNum == 0: return @[] for i in 0 .. <evNum: - let fd = s.events[i].data.fd.TSocketHandle + let fd = s.events[i].data.fd.SocketHandle - var evSet: set[TEvent] = {} + var evSet: set[Event] = {} if (s.events[i].events and EPOLLIN) != 0: evSet = evSet + {EvRead} if (s.events[i].events and EPOLLOUT) != 0: evSet = evSet + {EvWrite} let selectorKey = s.fds[fd] @@ -160,15 +160,15 @@ elif defined(linux): #echo("Epoll: ", result[i].key.fd, " ", result[i].events, " ", result[i].key.events) - proc newSelector*(): PSelector = + proc newSelector*(): Selector = new result result.epollFD = epoll_create(64) #result.events = cast[array[64, epoll_event]](alloc0(sizeof(epoll_event)*64)) - result.fds = initTable[TSocketHandle, PSelectorKey]() + result.fds = initTable[SocketHandle, SelectorKey]() if result.epollFD < 0: - OSError(OSLastError()) + raiseOSError(osLastError()) - proc contains*(s: PSelector, fd: TSocketHandle): bool = + proc contains*(s: Selector, fd: SocketHandle): bool = ## Determines whether selector contains a file descriptor. if s.fds.hasKey(fd): # Ensure the underlying epoll instance still contains this fd. @@ -179,46 +179,46 @@ elif defined(linux): else: return false - proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey = + proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey = ## Retrieves the selector key for ``fd``. return s.fds[fd] elif not defined(nimdoc): # TODO: kqueue for bsd/mac os x. type - PSelector* = ref object - fds: TTable[TSocketHandle, PSelectorKey] + Selector* = ref object + fds: Table[SocketHandle, SelectorKey] - proc register*(s: PSelector, fd: TSocketHandle, events: set[TEvent], - data: PObject): PSelectorKey {.discardable.} = + proc register*(s: Selector, fd: SocketHandle, events: set[Event], + data: RootRef): SelectorKey {.discardable.} = if s.fds.hasKey(fd): - raise newException(EInvalidValue, "File descriptor already exists.") - var sk = PSelectorKey(fd: fd, events: events, data: data) + raise newException(ValueError, "File descriptor already exists.") + var sk = SelectorKey(fd: fd, events: events, data: data) s.fds[fd] = sk result = sk - proc update*(s: PSelector, fd: TSocketHandle, - events: set[TEvent]): PSelectorKey {.discardable.} = + 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(EInvalidValue, "File descriptor not found.") + raise newException(ValueError, "File descriptor not found.") s.fds[fd].events = events result = s.fds[fd] - proc unregister*(s: PSelector, fd: TSocketHandle): PSelectorKey {.discardable.} = + proc unregister*(s: Selector, fd: SocketHandle): SelectorKey {.discardable.} = result = s.fds[fd] s.fds.del(fd) - proc close*(s: PSelector) = nil + proc close*(s: Selector) = discard - proc timeValFromMilliseconds(timeout: int): TTimeVal = + proc timeValFromMilliseconds(timeout: int): TimeVal = if timeout != -1: var seconds = timeout div 1000 result.tv_sec = seconds.int32 result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 - proc createFdSet(rd, wr: var TFdSet, fds: TTable[TSocketHandle, PSelectorKey], + proc createFdSet(rd, wr: var TFdSet, fds: Table[SocketHandle, SelectorKey], m: var int) = FD_ZERO(rd); FD_ZERO(wr) for k, v in pairs(fds): @@ -229,20 +229,20 @@ elif not defined(nimdoc): m = max(m, int(k)) FD_SET(k, wr) - proc getReadyFDs(rd, wr: var TFdSet, fds: TTable[TSocketHandle, PSelectorKey]): - seq[TReadyInfo] = + proc getReadyFDs(rd, wr: var TFdSet, fds: Table[SocketHandle, SelectorKey]): + seq[ReadyInfo] = result = @[] for k, v in pairs(fds): - var events: set[TEvent] = {} + var events: set[Event] = {} if FD_ISSET(k, rd) != 0'i32: events = events + {EvRead} if FD_ISSET(k, wr) != 0'i32: events = events + {EvWrite} result.add((v, events)) - proc select(fds: TTable[TSocketHandle, PSelectorKey], timeout = 500): - seq[TReadyInfo] = - var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout) + proc select(fds: Table[SocketHandle, SelectorKey], timeout = 500): + seq[ReadyInfo] = + var tv {.noInit.}: TimeVal = timeValFromMilliseconds(timeout) var rd, wr: TFdSet var m = 0 @@ -255,26 +255,26 @@ elif not defined(nimdoc): retCode = int(select(cint(m+1), addr(rd), addr(wr), nil, nil)) if retCode < 0: - OSError(OSLastError()) + raiseOSError(osLastError()) elif retCode == 0: return @[] else: return getReadyFDs(rd, wr, fds) - proc select*(s: PSelector, timeout: int): seq[TReadyInfo] = + proc select*(s: Selector, timeout: int): seq[ReadyInfo] = result = select(s.fds, timeout) - proc newSelector*(): PSelector = + proc newSelector*(): Selector = new result - result.fds = initTable[TSocketHandle, PSelectorKey]() + result.fds = initTable[SocketHandle, SelectorKey]() - proc contains*(s: PSelector, fd: TSocketHandle): bool = + proc contains*(s: Selector, fd: SocketHandle): bool = return s.fds.hasKey(fd) - proc `[]`*(s: PSelector, fd: TSocketHandle): PSelectorKey = + proc `[]`*(s: Selector, fd: SocketHandle): SelectorKey = return s.fds[fd] -proc contains*(s: PSelector, key: PSelectorKey): bool = +proc contains*(s: Selector, key: SelectorKey): bool = ## Determines whether selector contains this selector key. More accurate ## than checking if the file descriptor is in the selector because it ## ensures that the keys are equal. File descriptors may not always be @@ -282,20 +282,24 @@ proc contains*(s: PSelector, key: PSelectorKey): bool = ## the new one may have the same value. return key.fd in s and s.fds[key.fd] == key +{.deprecated: [TEvent: Event, PSelectorKey: SelectorKey, + TReadyInfo: ReadyInfo, PSelector: Selector].} + + when isMainModule and not defined(nimdoc): # Select() import sockets type - PSockWrapper = ref object of PObject - sock: TSocket + SockWrapper = ref object of RootObj + sock: Socket var sock = socket() - if sock == sockets.InvalidSocket: osError(osLastError()) + if sock == sockets.InvalidSocket: raiseOSError(osLastError()) #sock.setBlocking(false) - sock.connect("irc.freenode.net", TPort(6667)) + sock.connect("irc.freenode.net", Port(6667)) var selector = newSelector() - var data = PSockWrapper(sock: sock) + var data = SockWrapper(sock: sock) let key = selector.register(sock.getFD, {EvWrite}, data) var i = 0 while true: diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 88afeb589..e088e0bd9 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Dominik Picheta # # See the file "copying.txt", included in this @@ -16,11 +16,11 @@ ## Example gmail use: ## ## -## .. code-block:: Nimrod -## var msg = createMessage("Hello from Nimrod's SMTP", +## .. code-block:: Nim +## var msg = createMessage("Hello from Nim's SMTP", ## "Hello!.\n Is this awesome or what?", ## @["foo@gmail.com"]) -## var smtp = connect("smtp.gmail.com", 465, True, True) +## var smtp = connect("smtp.gmail.com", 465, true, true) ## smtp.auth("username", "password") ## smtp.sendmail("username@gmail.com", @["foo@gmail.com"], $msg) ## @@ -28,22 +28,32 @@ ## For SSL support this module relies on OpenSSL. If you want to ## enable SSL, compile with ``-d:ssl``. -import sockets, strutils, strtabs, base64, os +import net, strutils, strtabs, base64, os +import asyncnet, asyncdispatch type - TSMTP* {.final.} = object - sock: TSocket - debug: Bool + Smtp* = object + sock: Socket + debug: bool - TMessage* {.final.} = object + Message* = object msgTo: seq[string] msgCc: seq[string] msgSubject: string - msgOtherHeaders: PStringTable + msgOtherHeaders: StringTableRef msgBody: string - EInvalidReply* = object of EIO - + ReplyError* = object of IOError + + AsyncSmtp* = ref object + sock: AsyncSocket + address: string + port: Port + useSsl: bool + debug: bool + +{.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].} + proc debugSend(smtp: TSMTP, cmd: string) = if smtp.debug: echo("C:" & cmd) @@ -68,19 +78,25 @@ proc checkReply(smtp: var TSMTP, reply: string) = const compiledWithSsl = defined(ssl) -proc connect*(address: string, port = 25, - ssl = false, debug = false): TSMTP = +when not defined(ssl): + type PSSLContext = ref object + let defaultSSLContext: PSSLContext = nil +else: + let defaultSSLContext = newContext(verifyMode = CVerifyNone) + +proc connect*(address: string, port = Port(25), + ssl = false, debug = false, + sslContext = defaultSSLContext): TSMTP = ## Establishes a connection with a SMTP server. ## May fail with EInvalidReply or with a socket error. - result.sock = socket() + result.sock = newSocket() if ssl: when compiledWithSsl: - let ctx = newContext(verifyMode = CVerifyNone) - ctx.wrapSocket(result.sock) + sslContext.wrapSocket(result.sock) else: raise newException(ESystem, "SMTP module compiled without SSL support") - result.sock.connect(address, TPort(port)) + result.sock.connect(address, port) result.debug = debug result.checkReply("220") @@ -160,6 +176,82 @@ proc `$`*(msg: TMessage): string = result.add("\c\L") result.add(msg.msgBody) +proc newAsyncSmtp*(address: string, port: Port, useSsl = false, + sslContext = defaultSslContext): AsyncSmtp = + ## Creates a new ``AsyncSmtp`` instance. + new result + result.address = address + result.port = port + result.useSsl = useSsl + + result.sock = newAsyncSocket() + if useSsl: + when compiledWithSsl: + sslContext.wrapSocket(result.sock) + else: + raise newException(ESystem, + "SMTP module compiled without SSL support") + +proc quitExcpt(smtp: AsyncSmtp, msg: string): PFuture[void] = + var retFuture = newFuture[void]() + var sendFut = smtp.sock.send("QUIT") + sendFut.callback = + proc () = + # TODO: Fix this in async procs. + raise newException(ReplyError, msg) + return retFuture + +proc checkReply(smtp: AsyncSmtp, reply: string) {.async.} = + var line = await smtp.sock.recvLine() + if not line.string.startswith(reply): + await quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string) + +proc connect*(smtp: AsyncSmtp) {.async.} = + ## Establishes a connection with a SMTP server. + ## May fail with EInvalidReply or with a socket error. + await smtp.sock.connect(smtp.address, smtp.port) + + await smtp.checkReply("220") + await smtp.sock.send("HELO " & smtp.address & "\c\L") + await smtp.checkReply("250") + +proc auth*(smtp: AsyncSmtp, username, password: string) {.async.} = + ## Sends an AUTH command to the server to login as the `username` + ## using `password`. + ## May fail with EInvalidReply. + + await smtp.sock.send("AUTH LOGIN\c\L") + await smtp.checkReply("334") # TODO: Check whether it's asking for the "Username:" + # i.e "334 VXNlcm5hbWU6" + await smtp.sock.send(encode(username) & "\c\L") + await smtp.checkReply("334") # TODO: Same as above, only "Password:" (I think?) + + await smtp.sock.send(encode(password) & "\c\L") + await smtp.checkReply("235") # Check whether the authentification was successful. + +proc sendMail*(smtp: AsyncSmtp, fromAddr: string, + toAddrs: seq[string], msg: string) {.async.} = + ## Sends ``msg`` from ``fromAddr`` to the addresses specified in ``toAddrs``. + ## Messages may be formed using ``createMessage`` by converting the + ## TMessage into a string. + + await smtp.sock.send("MAIL FROM:<" & fromAddr & ">\c\L") + await smtp.checkReply("250") + for address in items(toAddrs): + await smtp.sock.send("RCPT TO:<" & smtp.address & ">\c\L") + await smtp.checkReply("250") + + # Send the message + await smtp.sock.send("DATA " & "\c\L") + await smtp.checkReply("354") + await smtp.sock.send(msg & "\c\L") + await smtp.sock.send(".\c\L") + await smtp.checkReply("250") + +proc close*(smtp: AsyncSmtp) {.async.} = + ## Disconnects from the SMTP server and closes the socket. + await smtp.sock.send("QUIT\c\L") + smtp.sock.close() when isMainModule: #var msg = createMessage("Test subject!", @@ -170,15 +262,16 @@ when isMainModule: #smtp.sendmail("root@localhost", @["dominik@localhost"], $msg) #echo(decode("a17sm3701420wbe.12")) - var msg = createMessage("Hello from Nimrod's SMTP!", - "Hello!!!!.\n Is this awesome or what?", - @["someone@yahoo.com", "someone@gmail.com"]) - echo(msg) - - var smtp = connect("smtp.gmail.com", 465, True, True) - smtp.auth("someone", "password") - smtp.sendmail("someone@gmail.com", - @["someone@yahoo.com", "someone@gmail.com"], $msg) - smtp.close() - + proc main() {.async.} = + var client = newAsyncSmtp("smtp.gmail.com", Port(465), true) + await client.connect() + await client.auth("johndoe", "foo") + var msg = createMessage("Hello from Nim's SMTP!", + "Hello!!!!.\n Is this awesome or what?", + @["blah@gmail.com"]) + echo(msg) + await client.sendMail("blah@gmail.com", @["blah@gmail.com"], $msg) + await client.close() + + waitFor main() diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index 7b8b3d557..6975f07c0 100644 --- a/lib/pure/sockets.nim +++ b/lib/pure/sockets.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf, Dominik Picheta # # See the file "copying.txt", included in this @@ -14,8 +14,8 @@ ## the ``socket`` function to `false`. Be aware that some functions may not yet ## support buffered sockets (mainly the recvFrom function). ## -## Most procedures raise EOS on error, but some may return ``-1`` or a boolean -## ``false``. +## Most procedures raise OSError on error, but some may return ``-1`` or a +## boolean ``false``. ## ## SSL is supported through the OpenSSL library. This support can be activated ## by compiling with the ``-d:ssl`` switch. When an SSL socket is used it will @@ -47,25 +47,29 @@ else: when defined(ssl): type - ESSL* = object of ESynch + SSLError* = object of Exception - TSSLCVerifyMode* = enum + SSLCVerifyMode* = enum CVerifyNone, CVerifyPeer - TSSLProtVersion* = enum + SSLProtVersion* = enum protSSLv2, protSSLv3, protTLSv1, protSSLv23 - PSSLContext* = distinct PSSLCTX + SSLContext* = distinct PSSLCTX - TSSLAcceptResult* = enum + SSLAcceptResult* = enum AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess + {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode, + TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext, + TSSLAcceptResult: SSLAcceptResult].} + const BufferSize*: int = 4000 ## size of a buffered socket's buffer type TSocketImpl = object ## socket type - fd: TSocketHandle + fd: SocketHandle case isBuffered: bool # determines whether this socket is buffered. of true: buffer: array[0..BufferSize, char] @@ -76,31 +80,31 @@ type case isSsl: bool of true: sslHandle: PSSL - sslContext: PSSLContext + sslContext: SSLContext sslNoHandshake: bool # True if needs handshake. sslHasPeekChar: bool sslPeekChar: char of false: nil nonblocking: bool - TSocket* = ref TSocketImpl + Socket* = ref TSocketImpl - TPort* = distinct uint16 ## port type + Port* = distinct uint16 ## port type - TDomain* = enum ## domain, which specifies the protocol family of the + Domain* = enum ## domain, which specifies the protocol family of the ## created socket. Other domains than those that are listed ## here are unsupported. AF_UNIX, ## for local socket (using a file). Unsupported on Windows. AF_INET = 2, ## for network protocol IPv4 or AF_INET6 = 23 ## for network protocol IPv6. - TType* = enum ## second argument to `socket` proc + SockType* = enum ## second argument to `socket` proc SOCK_STREAM = 1, ## reliable stream-oriented service or Stream Sockets SOCK_DGRAM = 2, ## datagram service or Datagram Sockets SOCK_RAW = 3, ## raw protocols atop the network layer. SOCK_SEQPACKET = 5 ## reliable sequenced packet service - TProtocol* = enum ## third argument to `socket` proc + Protocol* = enum ## third argument to `socket` proc IPPROTO_TCP = 6, ## Transmission control protocol. IPPROTO_UDP = 17, ## User datagram protocol. IPPROTO_IP, ## Internet protocol. Unsupported on Windows. @@ -108,33 +112,40 @@ type IPPROTO_RAW, ## Raw IP Packets Protocol. Unsupported on Windows. IPPROTO_ICMP ## Control message protocol. Unsupported on Windows. - TServent* {.pure, final.} = object ## information about a service + Servent* = object ## information about a service name*: string aliases*: seq[string] - port*: TPort + port*: Port proto*: string - Thostent* {.pure, final.} = object ## information about a given host + Hostent* = object ## information about a given host name*: string aliases*: seq[string] - addrtype*: TDomain + addrtype*: Domain length*: int addrList*: seq[string] - TSOBool* = enum ## Boolean socket options. + SOBool* = enum ## Boolean socket options. OptAcceptConn, OptBroadcast, OptDebug, OptDontRoute, OptKeepAlive, OptOOBInline, OptReuseAddr - TRecvLineResult* = enum ## result for recvLineAsync + RecvLineResult* = enum ## result for recvLineAsync RecvFullLine, RecvPartialLine, RecvDisconnected, RecvFail - TReadLineResult* = enum ## result for readLineAsync + ReadLineResult* = enum ## result for readLineAsync ReadFullLine, ReadPartialLine, ReadDisconnected, ReadNone - ETimeout* = object of ESynch + TimeoutError* = object of Exception + +{.deprecated: [TSocket: Socket, TType: SockType, TPort: Port, TDomain: Domain, + TProtocol: Protocol, TServent: Servent, THostent: Hostent, + TSOBool: SOBool, TRecvLineResult: RecvLineResult, + TReadLineResult: ReadLineResult, ETimeout: TimeoutError].} -let - invalidSocket*: TSocket = nil ## invalid socket +when defined(booting): + let invalidSocket*: Socket = nil ## invalid socket +else: + const invalidSocket*: Socket = nil ## invalid socket when defined(windows): let @@ -143,7 +154,7 @@ else: let osInvalidSocket = posix.INVALID_SOCKET -proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket = +proc newTSocket(fd: SocketHandle, isBuff: bool): Socket = if fd == osInvalidSocket: return nil new(result) @@ -153,10 +164,10 @@ proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket = result.currPos = 0 result.nonblocking = false -proc `==`*(a, b: TPort): bool {.borrow.} +proc `==`*(a, b: Port): bool {.borrow.} ## ``==`` for ports. -proc `$`*(p: TPort): string {.borrow.} +proc `$`*(p: Port): string {.borrow.} ## returns the port number as a string proc ntohl*(x: int32): int32 = @@ -189,14 +200,14 @@ proc htons*(x: int16): int16 = result = sockets.ntohs(x) when defined(Posix): - proc toInt(domain: TDomain): cint = + proc toInt(domain: Domain): cint = case domain of AF_UNIX: result = posix.AF_UNIX of AF_INET: result = posix.AF_INET of AF_INET6: result = posix.AF_INET6 else: discard - proc toInt(typ: TType): cint = + proc toInt(typ: SockType): cint = case typ of SOCK_STREAM: result = posix.SOCK_STREAM of SOCK_DGRAM: result = posix.SOCK_DGRAM @@ -204,7 +215,7 @@ when defined(Posix): of SOCK_RAW: result = posix.SOCK_RAW else: discard - proc toInt(p: TProtocol): cint = + proc toInt(p: Protocol): cint = case p of IPPROTO_TCP: result = posix.IPPROTO_TCP of IPPROTO_UDP: result = posix.IPPROTO_UDP @@ -215,17 +226,17 @@ when defined(Posix): else: discard else: - proc toInt(domain: TDomain): cint = + proc toInt(domain: Domain): cint = result = toU16(ord(domain)) - proc toInt(typ: TType): cint = + proc toInt(typ: SockType): cint = result = cint(ord(typ)) - proc toInt(p: TProtocol): cint = + proc toInt(p: Protocol): cint = result = cint(ord(p)) -proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, - protocol: TProtocol = IPPROTO_TCP, buffered = true): TSocket = +proc socket*(domain: Domain = AF_INET, typ: SockType = SOCK_STREAM, + protocol: Protocol = IPPROTO_TCP, buffered = true): Socket = ## Creates a new socket; returns `InvalidSocket` if an error occurs. # TODO: Perhaps this should just raise EOS when an error occurs. @@ -241,14 +252,14 @@ when defined(ssl): ErrLoadBioStrings() OpenSSL_add_all_algorithms() - proc SSLError(s = "") = + proc raiseSSLError(s = "") = if s != "": raise newException(ESSL, s) let err = ErrPeekLastError() if err == 0: raise newException(ESSL, "No error reported.") if err == -1: - OSError(OSLastError()) + raiseOSError(osLastError()) var errStr = ErrErrorString(err, nil) raise newException(ESSL, $errStr) @@ -262,18 +273,18 @@ when defined(ssl): if certFile != "": var ret = SSLCTXUseCertificateChainFile(ctx, certFile) if ret != 1: - SSLError() + raiseSslError() # TODO: Password? www.rtfm.com/openssl-examples/part1.pdf if keyFile != "": if SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) != 1: - SSLError() + raiseSslError() if SSL_CTX_check_private_key(ctx) != 1: - SSLError("Verification of private key file failed.") + raiseSslError("Verification of private key file failed.") - proc newContext*(protVersion = ProtSSLv23, verifyMode = CVerifyPeer, + proc newContext*(protVersion = protSSLv23, verifyMode = CVerifyPeer, certFile = "", keyFile = ""): PSSLContext = ## Creates an SSL context. ## @@ -298,21 +309,21 @@ when defined(ssl): when not defined(linux) and not defined(OpenBSD): newCTX = SSL_CTX_new(SSLv2_method()) else: - SSLError() + raiseSslError() of protSSLv3: newCTX = SSL_CTX_new(SSLv3_method()) of protTLSv1: newCTX = SSL_CTX_new(TLSv1_method()) if newCTX.SSLCTXSetCipherList("ALL") != 1: - SSLError() + raiseSslError() case verifyMode of CVerifyPeer: newCTX.SSLCTXSetVerify(SSLVerifyPeer, nil) of CVerifyNone: newCTX.SSLCTXSetVerify(SSLVerifyNone, nil) if newCTX == nil: - SSLError() + raiseSslError() discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY) newCTX.loadCertificates(certFile, keyFile) @@ -331,12 +342,12 @@ when defined(ssl): socket.sslNoHandshake = false socket.sslHasPeekChar = false if socket.sslHandle == nil: - SSLError() + raiseSslError() if SSLSetFd(socket.sslHandle, socket.fd) != 1: - SSLError() + raiseSslError() -proc socketError*(socket: TSocket, err: int = -1, async = false) = +proc raiseSocketError*(socket: Socket, err: int = -1, async = false) = ## Raises proper errors based on return values of ``recv`` functions. ## ## If ``async`` is ``True`` no error will be thrown in the case when the @@ -349,20 +360,20 @@ proc socketError*(socket: TSocket, err: int = -1, async = false) = var ret = SSLGetError(socket.sslHandle, err.cint) case ret of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: if async: return - else: SSLError("Not enough data on socket.") + else: raiseSslError("Not enough data on socket.") of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ: if async: return - else: SSLError("Not enough data on socket.") + else: raiseSslError("Not enough data on socket.") of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSslError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() - else: SSLError("Unknown Error") + raiseSslError() + else: raiseSslError("Unknown Error") if err == -1 and not (when defined(ssl): socket.isSSL else: false): let lastError = osLastError() @@ -370,21 +381,21 @@ proc socketError*(socket: TSocket, err: int = -1, async = false) = when defined(windows): if lastError.int32 == WSAEWOULDBLOCK: return - else: osError(lastError) + else: raiseOSError(lastError) else: if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK: return - else: osError(lastError) - else: osError(lastError) + else: raiseOSError(lastError) + else: raiseOSError(lastError) -proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} = +proc listen*(socket: Socket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} = ## Marks ``socket`` as accepting connections. ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. - if listen(socket.fd, cint(backlog)) < 0'i32: osError(osLastError()) + if listen(socket.fd, cint(backlog)) < 0'i32: raiseOSError(osLastError()) proc invalidIp4(s: string) {.noreturn, noinline.} = - raise newException(EInvalidValue, "invalid ip4 address: " & s) + raise newException(ValueError, "invalid ip4 address: " & s) proc parseIp4*(s: string): BiggestInt = ## parses an IP version 4 in dotted decimal form like "a.b.c.d". @@ -420,58 +431,58 @@ template gaiNim(a, p, h, list: expr): stmt = var gaiResult = getaddrinfo(a, $p, addr(h), list) if gaiResult != 0'i32: when defined(windows): - osError(osLastError()) + raiseOSError(osLastError()) else: - raise newException(EOS, $gai_strerror(gaiResult)) + raise newException(OSError, $gai_strerror(gaiResult)) -proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {. - tags: [FReadIO].} = +proc bindAddr*(socket: Socket, port = Port(0), address = "") {. + tags: [ReadIOEffect].} = ## binds an address/port number to a socket. ## Use address string in dotted decimal form like "a.b.c.d" ## or leave "" for any address. if address == "": - var name: Tsockaddr_in + var name: Sockaddr_in when defined(Windows): name.sin_family = int16(ord(AF_INET)) else: name.sin_family = posix.AF_INET name.sin_port = sockets.htons(int16(port)) name.sin_addr.s_addr = sockets.htonl(INADDR_ANY) - if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)), - sizeof(name).TSocklen) < 0'i32: - osError(osLastError()) + if bindSocket(socket.fd, cast[ptr SockAddr](addr(name)), + sizeof(name).SockLen) < 0'i32: + raiseOSError(osLastError()) else: - var hints: Taddrinfo - var aiList: ptr Taddrinfo = nil + var hints: AddrInfo + var aiList: ptr AddrInfo = nil hints.ai_family = toInt(AF_INET) hints.ai_socktype = toInt(SOCK_STREAM) hints.ai_protocol = toInt(IPPROTO_TCP) gaiNim(address, port, hints, aiList) - if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrlen.TSocklen) < 0'i32: - osError(osLastError()) + if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32: + raiseOSError(osLastError()) -proc getSockName*(socket: TSocket): TPort = +proc getSockName*(socket: Socket): Port = ## returns the socket's associated port number. - var name: Tsockaddr_in + var name: Sockaddr_in when defined(Windows): name.sin_family = int16(ord(AF_INET)) else: name.sin_family = posix.AF_INET #name.sin_port = htons(cint16(port)) #name.sin_addr.s_addr = htonl(INADDR_ANY) - var namelen = sizeof(name).TSocklen - if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)), + var namelen = sizeof(name).SockLen + if getsockname(socket.fd, cast[ptr SockAddr](addr(name)), addr(namelen)) == -1'i32: - osError(osLastError()) - result = TPort(sockets.ntohs(name.sin_port)) + raiseOSError(osLastError()) + result = Port(sockets.ntohs(name.sin_port)) template acceptAddrPlain(noClientRet, successRet: expr, sslImplementation: stmt): stmt {.immediate.} = assert(client != nil) - var sockAddress: Tsockaddr_in - var addrLen = sizeof(sockAddress).TSocklen - var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)), + var sockAddress: Sockaddr_in + var addrLen = sizeof(sockAddress).SockLen + var sock = accept(server.fd, cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) if sock == osInvalidSocket: @@ -484,7 +495,7 @@ template acceptAddrPlain(noClientRet, successRet: expr, return else: return noClientRet - else: osError(err) + else: raiseOSError(err) else: if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK: client = invalidSocket @@ -493,7 +504,7 @@ template acceptAddrPlain(noClientRet, successRet: expr, return else: return noClientRet - else: osError(err) + else: raiseOSError(err) else: client.fd = sock client.isBuffered = server.isBuffered @@ -505,8 +516,8 @@ template acceptAddrPlain(noClientRet, successRet: expr, else: return successRet -proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) {. - tags: [FReadIO].} = +proc acceptAddr*(server: Socket, client: var Socket, address: var string) {. + tags: [ReadIOEffect].} = ## 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. @@ -535,18 +546,18 @@ proc acceptAddr*(server: TSocket, client: var TSocket, address: var string) {. if err != SSL_ERROR_WANT_ACCEPT: case err of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: - SSLError("acceptAddrSSL should be used for non-blocking SSL sockets.") + raiseSslError("acceptAddrSSL should be used for non-blocking SSL sockets.") of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSslError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() + raiseSslError() else: - SSLError("Unknown error") + raiseSslError("Unknown error") -proc setBlocking*(s: TSocket, blocking: bool) {.tags: [], gcsafe.} +proc setBlocking*(s: Socket, blocking: bool) {.tags: [], gcsafe.} ## Sets blocking mode on socket when defined(ssl): @@ -581,17 +592,17 @@ when defined(ssl): if err != SSL_ERROR_WANT_ACCEPT: case err of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: client.sslNoHandshake = true return AcceptNoHandshake of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSslError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() + raiseSslError() else: - SSLError("Unknown error") + raiseSslError("Unknown error") client.sslNoHandshake = false if client.isSSL and client.sslNoHandshake: @@ -601,7 +612,7 @@ when defined(ssl): acceptAddrPlain(AcceptNoClient, AcceptSuccess): doHandshake() -proc accept*(server: TSocket, client: var TSocket) {.tags: [FReadIO].} = +proc accept*(server: Socket, client: var Socket) {.tags: [ReadIOEffect].} = ## Equivalent to ``acceptAddr`` but doesn't return the address, only the ## socket. ## @@ -611,24 +622,24 @@ proc accept*(server: TSocket, client: var TSocket) {.tags: [FReadIO].} = var addrDummy = "" acceptAddr(server, client, addrDummy) -proc acceptAddr*(server: TSocket): tuple[client: TSocket, address: string] {. - deprecated, tags: [FReadIO].} = +proc acceptAddr*(server: Socket): tuple[client: Socket, address: string] {. + deprecated, tags: [ReadIOEffect].} = ## Slightly different version of ``acceptAddr``. ## ## **Deprecated since version 0.9.0:** Please use the function above. - var client: TSocket + var client: Socket new(client) var address = "" acceptAddr(server, client, address) return (client, address) -proc accept*(server: TSocket): TSocket {.deprecated, tags: [FReadIO].} = +proc accept*(server: Socket): Socket {.deprecated, tags: [ReadIOEffect].} = ## **Deprecated since version 0.9.0:** Please use the function above. new(result) var address = "" acceptAddr(server, result, address) -proc close*(socket: TSocket) = +proc close*(socket: Socket) = ## closes a socket. when defined(windows): discard winlean.closesocket(socket.fd) @@ -640,7 +651,7 @@ proc close*(socket: TSocket) = if socket.isSSL: discard SSLShutdown(socket.sslHandle) -proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} = +proc getServByName*(name, proto: string): Servent {.tags: [ReadIOEffect].} = ## Searches the database from the beginning and finds the first entry for ## which the service name specified by ``name`` matches the s_name member ## and the protocol name specified by ``proto`` matches the s_proto member. @@ -650,13 +661,13 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} = var s = winlean.getservbyname(name, proto) else: var s = posix.getservbyname(name, proto) - if s == nil: raise newException(EOS, "Service not found.") + if s == nil: raise newException(OSError, "Service not found.") result.name = $s.s_name result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = TPort(s.s_port) + result.port = Port(s.s_port) result.proto = $s.s_proto -proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} = +proc getServByPort*(port: Port, proto: string): Servent {.tags: [ReadIOEffect].} = ## Searches the database from the beginning and finds the first entry for ## which the port specified by ``port`` matches the s_port member and the ## protocol name specified by ``proto`` matches the s_proto member. @@ -666,81 +677,81 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} = var s = winlean.getservbyport(ze(int16(port)).cint, proto) else: var s = posix.getservbyport(ze(int16(port)).cint, proto) - if s == nil: raise newException(EOS, "Service not found.") + if s == nil: raise newException(OSError, "Service not found.") result.name = $s.s_name result.aliases = cstringArrayToSeq(s.s_aliases) - result.port = TPort(s.s_port) + result.port = Port(s.s_port) result.proto = $s.s_proto -proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} = +proc getHostByAddr*(ip: string): Hostent {.tags: [ReadIOEffect].} = ## This function will lookup the hostname of an IP Address. - var myaddr: TInAddr + var myaddr: InAddr myaddr.s_addr = inet_addr(ip) when defined(windows): var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint, cint(sockets.AF_INET)) - if s == nil: osError(osLastError()) + if s == nil: raiseOSError(osLastError()) else: - var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSocklen, + var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).Socklen, cint(posix.AF_INET)) if s == nil: - raise newException(EOS, $hstrerror(h_errno)) + raise newException(OSError, $hstrerror(h_errno)) result.name = $s.h_name result.aliases = cstringArrayToSeq(s.h_aliases) when defined(windows): - result.addrtype = TDomain(s.h_addrtype) + result.addrtype = Domain(s.h_addrtype) else: if s.h_addrtype == posix.AF_INET: result.addrtype = AF_INET elif s.h_addrtype == posix.AF_INET6: result.addrtype = AF_INET6 else: - raise newException(EOS, "unknown h_addrtype") + raise newException(OSError, "unknown h_addrtype") result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) -proc getHostByName*(name: string): Thostent {.tags: [FReadIO].} = +proc getHostByName*(name: string): Hostent {.tags: [ReadIOEffect].} = ## This function will lookup the IP address of a hostname. when defined(Windows): var s = winlean.gethostbyname(name) else: var s = posix.gethostbyname(name) - if s == nil: osError(osLastError()) + if s == nil: raiseOSError(osLastError()) result.name = $s.h_name result.aliases = cstringArrayToSeq(s.h_aliases) when defined(windows): - result.addrtype = TDomain(s.h_addrtype) + result.addrtype = Domain(s.h_addrtype) else: if s.h_addrtype == posix.AF_INET: result.addrtype = AF_INET elif s.h_addrtype == posix.AF_INET6: result.addrtype = AF_INET6 else: - raise newException(EOS, "unknown h_addrtype") + raise newException(OSError, "unknown h_addrtype") result.addrList = cstringArrayToSeq(s.h_addr_list) result.length = int(s.h_length) -proc getSockOptInt*(socket: TSocket, level, optname: int): int {. - tags: [FReadIO].} = +proc getSockOptInt*(socket: Socket, level, optname: int): int {. + tags: [ReadIOEffect].} = ## getsockopt for integer options. var res: cint - var size = sizeof(res).TSocklen + var size = sizeof(res).SockLen if getsockopt(socket.fd, cint(level), cint(optname), addr(res), addr(size)) < 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) result = int(res) -proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {. - tags: [FWriteIO].} = +proc setSockOptInt*(socket: Socket, level, optname, optval: int) {. + tags: [WriteIOEffect].} = ## setsockopt for integer options. var value = cint(optval) if setsockopt(socket.fd, cint(level), cint(optname), addr(value), - sizeof(value).TSocklen) < 0'i32: - osError(osLastError()) + sizeof(value).SockLen) < 0'i32: + raiseOSError(osLastError()) -proc toCInt(opt: TSOBool): cint = +proc toCInt(opt: SOBool): cint = case opt of OptAcceptConn: SO_ACCEPTCONN of OptBroadcast: SO_BROADCAST @@ -750,51 +761,51 @@ proc toCInt(opt: TSOBool): cint = of OptOOBInline: SO_OOBINLINE of OptReuseAddr: SO_REUSEADDR -proc getSockOpt*(socket: TSocket, opt: TSOBool, level = SOL_SOCKET): bool {. - tags: [FReadIO].} = +proc getSockOpt*(socket: Socket, opt: SOBool, level = SOL_SOCKET): bool {. + tags: [ReadIOEffect].} = ## Retrieves option ``opt`` as a boolean value. var res: cint - var size = sizeof(res).TSocklen + var size = sizeof(res).SockLen if getsockopt(socket.fd, cint(level), toCInt(opt), addr(res), addr(size)) < 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) result = res != 0 -proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {. - tags: [FWriteIO].} = +proc setSockOpt*(socket: Socket, opt: SOBool, value: bool, level = SOL_SOCKET) {. + tags: [WriteIOEffect].} = ## Sets option ``opt`` to a boolean value specified by ``value``. var valuei = cint(if value: 1 else: 0) if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei), - sizeof(valuei).TSocklen) < 0'i32: - osError(osLastError()) + sizeof(valuei).SockLen) < 0'i32: + raiseOSError(osLastError()) -proc connect*(socket: TSocket, address: string, port = TPort(0), - af: TDomain = AF_INET) {.tags: [FReadIO].} = +proc connect*(socket: Socket, address: string, port = Port(0), + af: Domain = AF_INET) {.tags: [ReadIOEffect].} = ## Connects socket to ``address``:``port``. ``Address`` can be an IP address or a ## host name. If ``address`` is a host name, this function will try each IP ## of that host name. ``htons`` is already performed on ``port`` so you must ## not do it. ## ## If ``socket`` is an SSL socket a handshake will be automatically performed. - var hints: Taddrinfo - var aiList: ptr Taddrinfo = nil + var hints: AddrInfo + var aiList: ptr AddrInfo = nil hints.ai_family = toInt(af) hints.ai_socktype = toInt(SOCK_STREAM) hints.ai_protocol = toInt(IPPROTO_TCP) gaiNim(address, port, hints, aiList) # try all possibilities: var success = false - var lastError: TOSErrorCode + var lastError: OSErrorCode var it = aiList while it != nil: - if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen) == 0'i32: + if connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) == 0'i32: success = true break else: lastError = osLastError() it = it.ai_next freeaddrinfo(aiList) - if not success: osError(lastError) + if not success: raiseOSError(lastError) when defined(ssl): if socket.isSSL: @@ -803,16 +814,16 @@ proc connect*(socket: TSocket, address: string, port = TPort(0), let err = SSLGetError(socket.sslHandle, ret) case err of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: - SSLError("The operation did not complete. Perhaps you should use connectAsync?") + raiseSslError("The operation did not complete. Perhaps you should use connectAsync?") of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSslError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() + raiseSslError() else: - SSLError("Unknown error") + raiseSslError("Unknown error") when false: var s: TSockAddrIn @@ -829,8 +840,8 @@ proc connect*(socket: TSocket, address: string, port = TPort(0), if connect(socket.fd, cast[ptr TSockAddr](addr(s)), sizeof(s).cint) < 0'i32: OSError() -proc connectAsync*(socket: TSocket, name: string, port = TPort(0), - af: TDomain = AF_INET) {.tags: [FReadIO].} = +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 @@ -839,18 +850,18 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0), ## ## **Note**: For SSL sockets, the ``handshake`` procedure must be called ## whenever the socket successfully connects to a server. - var hints: Taddrinfo - var aiList: ptr Taddrinfo = nil + var hints: AddrInfo + var aiList: ptr AddrInfo = nil hints.ai_family = toInt(af) hints.ai_socktype = toInt(SOCK_STREAM) hints.ai_protocol = toInt(IPPROTO_TCP) gaiNim(name, port, hints, aiList) # try all possibilities: var success = false - var lastError: TOSErrorCode + var lastError: OSErrorCode var it = aiList while it != nil: - var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen) + var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.SockLen) if ret == 0'i32: success = true break @@ -869,7 +880,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0), it = it.ai_next freeaddrinfo(aiList) - if not success: osError(lastError) + if not success: raiseOSError(lastError) when defined(ssl): if socket.isSSL: socket.sslNoHandshake = true @@ -891,19 +902,19 @@ when defined(ssl): var errret = SSLGetError(socket.sslHandle, ret) case errret of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE: return false of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSslError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() + raiseSslError() else: - SSLError("Unknown Error") + raiseSslError("Unknown Error") socket.sslNoHandshake = false else: - SSLError("Socket is not an SSL socket.") + raiseSslError("Socket is not an SSL socket.") proc gotHandshake*(socket: TSocket): bool = ## Determines whether a handshake has occurred between a client (``socket``) @@ -913,21 +924,21 @@ when defined(ssl): if socket.isSSL: return not socket.sslNoHandshake else: - SSLError("Socket is not an SSL socket.") + raiseSslError("Socket is not an SSL socket.") -proc timeValFromMilliseconds(timeout = 500): Ttimeval = +proc timeValFromMilliseconds(timeout = 500): Timeval = if timeout != -1: var seconds = timeout div 1000 result.tv_sec = seconds.int32 result.tv_usec = ((timeout - seconds * 1000) * 1000).int32 -proc createFdSet(fd: var TFdSet, s: seq[TSocket], m: var int) = +proc createFdSet(fd: var TFdSet, s: seq[Socket], m: var int) = FD_ZERO(fd) for i in items(s): m = max(m, int(i.fd)) - FD_SET(i.fd, fd) + fdSet(i.fd, fd) -proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) = +proc pruneSocketSet(s: var seq[Socket], fd: var TFdSet) = var i = 0 var L = s.len while i < L: @@ -939,7 +950,7 @@ proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) = inc(i) setLen(s, L) -proc hasDataBuffered*(s: TSocket): bool = +proc hasDataBuffered*(s: Socket): bool = ## Determines whether a socket has data buffered. result = false if s.isBuffered: @@ -949,10 +960,10 @@ proc hasDataBuffered*(s: TSocket): bool = if s.isSSL and not result: result = s.sslHasPeekChar -proc checkBuffer(readfds: var seq[TSocket]): int = +proc checkBuffer(readfds: var seq[Socket]): int = ## Checks the buffer of each socket in ``readfds`` to see whether there is data. ## Removes the sockets from ``readfds`` and returns the count of removed sockets. - var res: seq[TSocket] = @[] + var res: seq[Socket] = @[] result = 0 for s in readfds: if hasDataBuffered(s): @@ -961,8 +972,8 @@ proc checkBuffer(readfds: var seq[TSocket]): int = if result > 0: readfds = res -proc select*(readfds, writefds, exceptfds: var seq[TSocket], - timeout = 500): int {.tags: [FReadIO].} = +proc select*(readfds, writefds, exceptfds: var seq[Socket], + timeout = 500): int {.tags: [ReadIOEffect].} = ## Traditional select function. This function will return the number of ## sockets that are ready to be read from, written to, or which have errors. ## If there are none; 0 is returned. @@ -975,7 +986,7 @@ proc select*(readfds, writefds, exceptfds: var seq[TSocket], if buffersFilled > 0: return buffersFilled - var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout) + var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) var rd, wr, ex: TFdSet var m = 0 @@ -992,13 +1003,13 @@ proc select*(readfds, writefds, exceptfds: var seq[TSocket], pruneSocketSet(writefds, (wr)) pruneSocketSet(exceptfds, (ex)) -proc select*(readfds, writefds: var seq[TSocket], - timeout = 500): int {.tags: [FReadIO].} = +proc select*(readfds, writefds: var seq[Socket], + timeout = 500): int {.tags: [ReadIOEffect].} = ## Variant of select with only a read and write list. let buffersFilled = checkBuffer(readfds) if buffersFilled > 0: return buffersFilled - var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout) + var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) var rd, wr: TFdSet var m = 0 @@ -1013,8 +1024,8 @@ proc select*(readfds, writefds: var seq[TSocket], pruneSocketSet(readfds, (rd)) pruneSocketSet(writefds, (wr)) -proc selectWrite*(writefds: var seq[TSocket], - timeout = 500): int {.tags: [FReadIO].} = +proc selectWrite*(writefds: var seq[Socket], + timeout = 500): int {.tags: [ReadIOEffect].} = ## When a socket in ``writefds`` is ready to be written to then a non-zero ## value will be returned specifying the count of the sockets which can be ## written to. The sockets which **cannot** be written to will also be removed @@ -1022,7 +1033,7 @@ proc selectWrite*(writefds: var seq[TSocket], ## ## ``timeout`` is specified in miliseconds and ``-1`` can be specified for ## an unlimited time. - var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout) + var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) var wr: TFdSet var m = 0 @@ -1035,12 +1046,12 @@ proc selectWrite*(writefds: var seq[TSocket], pruneSocketSet(writefds, (wr)) -proc select*(readfds: var seq[TSocket], timeout = 500): int = +proc select*(readfds: var seq[Socket], timeout = 500): int = ## variant of select with a read list only let buffersFilled = checkBuffer(readfds) if buffersFilled > 0: return buffersFilled - var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout) + var tv {.noInit.}: Timeval = timeValFromMilliseconds(timeout) var rd: TFdSet var m = 0 @@ -1053,7 +1064,7 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int = pruneSocketSet(readfds, (rd)) -proc readIntoBuf(socket: TSocket, flags: int32): int = +proc readIntoBuf(socket: Socket, flags: int32): int = result = 0 when defined(ssl): if socket.isSSL: @@ -1077,7 +1088,7 @@ template retRead(flags, readBytes: int) {.dirty.} = else: return res -proc recv*(socket: TSocket, data: pointer, size: int): int {.tags: [FReadIO].} = +proc recv*(socket: Socket, data: pointer, size: int): int {.tags: [ReadIOEffect].} = ## Receives data from a socket. ## ## **Note**: This is a low-level function, you may be interested in the higher @@ -1117,8 +1128,8 @@ proc recv*(socket: TSocket, data: pointer, size: int): int {.tags: [FReadIO].} = else: result = recv(socket.fd, data, size.cint, 0'i32) -proc waitFor(socket: TSocket, waited: var float, timeout, size: int, - funcName: string): int {.tags: [FTime].} = +proc waitFor(socket: Socket, waited: var float, timeout, size: int, + funcName: string): int {.tags: [TimeEffect].} = ## determines the amount of characters that can be read. Result will never ## be larger than ``size``. For unbuffered sockets this will be ``1``. ## For buffered sockets it can be as big as ``BufferSize``. @@ -1133,7 +1144,7 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int, result = min(result, size) else: if timeout - int(waited * 1000.0) < 1: - raise newException(ETimeout, "Call to '" & funcName & "' timed out.") + raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") when defined(ssl): if socket.isSSL: @@ -1147,13 +1158,13 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int, var s = @[socket] var startTime = epochTime() let selRet = select(s, timeout - int(waited * 1000.0)) - if selRet < 0: osError(osLastError()) + if selRet < 0: raiseOSError(osLastError()) if selRet != 1: - raise newException(ETimeout, "Call to '" & funcName & "' timed out.") + raise newException(TimeoutError, "Call to '" & funcName & "' timed out.") waited += (epochTime() - startTime) -proc recv*(socket: TSocket, data: pointer, size: int, timeout: int): int {. - tags: [FReadIO, FTime].} = +proc recv*(socket: Socket, data: pointer, size: int, timeout: int): int {. + tags: [ReadIOEffect, TimeEffect].} = ## overload with a ``timeout`` parameter in miliseconds. var waited = 0.0 # number of seconds already waited @@ -1169,7 +1180,7 @@ proc recv*(socket: TSocket, data: pointer, size: int, timeout: int): int {. result = read -proc recv*(socket: TSocket, data: var string, size: int, timeout = -1): int = +proc recv*(socket: Socket, data: var string, size: int, timeout = -1): int = ## Higher-level version of ``recv``. ## ## When 0 is returned the socket's connection has been closed. @@ -1185,10 +1196,10 @@ proc recv*(socket: TSocket, data: var string, size: int, timeout = -1): int = result = recv(socket, cstring(data), size, timeout) if result < 0: data.setLen(0) - socket.socketError(result) + socket.raiseSocketError(result) data.setLen(result) -proc recvAsync*(socket: TSocket, data: var string, size: int): int = +proc recvAsync*(socket: Socket, data: var string, size: int): int = ## Async version of ``recv``. ## ## When socket is non-blocking and no data is available on the socket, @@ -1199,11 +1210,11 @@ proc recvAsync*(socket: TSocket, data: var string, size: int): int = result = recv(socket, cstring(data), size) if result < 0: data.setLen(0) - socket.socketError(async = true) + socket.raiseSocketError(async = true) result = -1 data.setLen(result) -proc peekChar(socket: TSocket, c: var char): int {.tags: [FReadIO].} = +proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} = if socket.isBuffered: result = 1 if socket.bufLen == 0 or socket.currPos > socket.bufLen-1: @@ -1223,8 +1234,8 @@ proc peekChar(socket: TSocket, c: var char): int {.tags: [FReadIO].} = return result = recv(socket.fd, addr(c), 1, MSG_PEEK) -proc recvLine*(socket: TSocket, line: var TaintedString, timeout = -1): bool {. - tags: [FReadIO, FTime], deprecated.} = +proc recvLine*(socket: Socket, line: var TaintedString, timeout = -1): bool {. + tags: [ReadIOEffect, TimeEffect], deprecated.} = ## Receive a line of data from ``socket``. ## ## If a full line is received ``\r\L`` is not @@ -1270,8 +1281,8 @@ proc recvLine*(socket: TSocket, line: var TaintedString, timeout = -1): bool {. return true add(line.string, c) -proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {. - tags: [FReadIO, FTime].} = +proc readLine*(socket: Socket, line: var TaintedString, timeout = -1) {. + tags: [ReadIOEffect, TimeEffect].} = ## Reads a line of data from ``socket``. ## ## If a full line is read ``\r\L`` is not @@ -1296,14 +1307,14 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {. var c: char discard waitFor(socket, waited, timeout, 1, "readLine") var n = recv(socket, addr(c), 1) - if n < 0: socket.socketError() + if n < 0: socket.raiseSocketError() elif n == 0: return if c == '\r': discard waitFor(socket, waited, timeout, 1, "readLine") n = peekChar(socket, c) if n > 0 and c == '\L': discard recv(socket, addr(c), 1) - elif n <= 0: socket.socketError() + elif n <= 0: socket.raiseSocketError() addNLIfEmpty() return elif c == '\L': @@ -1311,8 +1322,8 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {. return add(line.string, c) -proc recvLineAsync*(socket: TSocket, - line: var TaintedString): TRecvLineResult {.tags: [FReadIO], deprecated.} = +proc recvLineAsync*(socket: Socket, + line: var TaintedString): RecvLineResult {.tags: [ReadIOEffect], deprecated.} = ## Similar to ``recvLine`` but designed for non-blocking sockets. ## ## The values of the returned enum should be pretty self explanatory: @@ -1343,8 +1354,8 @@ proc recvLineAsync*(socket: TSocket, elif c == '\L': return RecvFullLine add(line.string, c) -proc readLineAsync*(socket: TSocket, - line: var TaintedString): TReadLineResult {.tags: [FReadIO].} = +proc readLineAsync*(socket: Socket, + line: var TaintedString): ReadLineResult {.tags: [ReadIOEffect].} = ## Similar to ``recvLine`` but designed for non-blocking sockets. ## ## The values of the returned enum should be pretty self explanatory: @@ -1357,7 +1368,7 @@ proc readLineAsync*(socket: TSocket, setLen(line.string, 0) template errorOrNone = - socket.socketError(async = true) + socket.raiseSocketError(async = true) return ReadNone while true: @@ -1378,7 +1389,7 @@ proc readLineAsync*(socket: TSocket, elif c == '\L': return ReadFullLine add(line.string, c) -proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} = +proc recv*(socket: Socket): TaintedString {.tags: [ReadIOEffect], deprecated.} = ## receives all the available data from the socket. ## Socket errors will result in an ``EOS`` error. ## If socket is not a connectionless socket and socket is not connected @@ -1390,7 +1401,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} = var pos = 0 while true: var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1) - if bytesRead == -1: osError(osLastError()) + if bytesRead == -1: raiseOSError(osLastError()) setLen(result.string, pos + bytesRead) if bytesRead != bufSize-1: break # increase capacity: @@ -1402,7 +1413,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} = while true: var bytesRead = recv(socket, cstring(buf), bufSize-1) # Error - if bytesRead == -1: OSError(OSLastError()) + if bytesRead == -1: OSError(osLastError()) buf[bytesRead] = '\0' # might not be necessary setLen(buf, bytesRead) @@ -1410,8 +1421,8 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} = if bytesRead != bufSize-1: break {.push warning[deprecated]: off.} -proc recvTimeout*(socket: TSocket, timeout: int): TaintedString {. - tags: [FReadIO], deprecated.} = +proc recvTimeout*(socket: Socket, timeout: int): TaintedString {. + tags: [ReadIOEffect], deprecated.} = ## overloaded variant to support a ``timeout`` parameter, the ``timeout`` ## parameter specifies the amount of miliseconds to wait for data on the ## socket. @@ -1420,13 +1431,13 @@ proc recvTimeout*(socket: TSocket, timeout: int): TaintedString {. if socket.bufLen == 0: var s = @[socket] if s.select(timeout) != 1: - raise newException(ETimeout, "Call to recv() timed out.") + raise newException(TimeoutError, "Call to recv() timed out.") return socket.recv {.pop.} -proc recvAsync*(socket: TSocket, s: var TaintedString): bool {. - tags: [FReadIO], deprecated.} = +proc recvAsync*(socket: Socket, s: var TaintedString): bool {. + tags: [ReadIOEffect], deprecated.} = ## receives all the data from a non-blocking socket. If socket is non-blocking ## and there are no messages available, `False` will be returned. ## Other socket errors will result in an ``EOS`` error. @@ -1447,27 +1458,27 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {. var ret = SSLGetError(socket.sslHandle, bytesRead.cint) case ret of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: - SSLError("Unexpected error occured.") # This should just not happen. + raiseSslError("Unexpected error occured.") # This should just not happen. of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ: return false of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSslError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() - else: SSLError("Unknown Error") + raiseSslError() + else: raiseSslError("Unknown Error") if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false): let err = osLastError() when defined(windows): if err.int32 == WSAEWOULDBLOCK: return false - else: osError(err) + else: raiseOSError(err) else: if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK: return false - else: osError(err) + else: raiseOSError(err) setLen(s.string, pos + bytesRead) if bytesRead != bufSize-1: break @@ -1476,9 +1487,9 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {. inc(pos, bytesRead) result = true -proc recvFrom*(socket: TSocket, data: var string, length: int, - address: var string, port: var TPort, flags = 0'i32): int {. - tags: [FReadIO].} = +proc recvFrom*(socket: Socket, data: var string, length: int, + address: var string, port: var Port, flags = 0'i32): int {. + tags: [ReadIOEffect].} = ## Receives data from ``socket``. This function should normally be used with ## connection-less sockets (UDP sockets). ## @@ -1492,19 +1503,19 @@ proc recvFrom*(socket: TSocket, data: var string, length: int, # TODO: Buffered sockets data.setLen(length) - var sockAddress: Tsockaddr_in - var addrLen = sizeof(sockAddress).TSocklen + var sockAddress: Sockaddr_in + var addrLen = sizeof(sockAddress).SockLen result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint, - cast[ptr TSockAddr](addr(sockAddress)), addr(addrLen)) + cast[ptr SockAddr](addr(sockAddress)), addr(addrLen)) if result != -1: data.setLen(result) address = $inet_ntoa(sockAddress.sin_addr) - port = ntohs(sockAddress.sin_port).TPort + port = ntohs(sockAddress.sin_port).Port -proc recvFromAsync*(socket: TSocket, data: var string, length: int, - address: var string, port: var TPort, - flags = 0'i32): bool {.tags: [FReadIO].} = +proc recvFromAsync*(socket: Socket, data: var string, length: int, + address: var string, port: var Port, + flags = 0'i32): bool {.tags: [ReadIOEffect].} = ## Variant of ``recvFrom`` for non-blocking sockets. Unlike ``recvFrom``, ## this function will raise an EOS error whenever a socket error occurs. ## @@ -1516,13 +1527,13 @@ proc recvFromAsync*(socket: TSocket, data: var string, length: int, when defined(windows): if err.int32 == WSAEWOULDBLOCK: return false - else: osError(err) + else: raiseOSError(err) else: if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK: return false - else: osError(err) + else: raiseOSError(err) -proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} = +proc skip*(socket: Socket) {.tags: [ReadIOEffect], deprecated.} = ## skips all the data that is pending for the socket ## ## **Deprecated since version 0.9.2**: This function is not safe for use. @@ -1531,7 +1542,7 @@ proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} = while recv(socket, buf, bufSize) == bufSize: discard dealloc(buf) -proc skip*(socket: TSocket, size: int, timeout = -1) = +proc skip*(socket: Socket, size: int, timeout = -1) = ## Skips ``size`` amount of bytes. ## ## An optional timeout can be specified in miliseconds, if skipping the @@ -1546,8 +1557,8 @@ proc skip*(socket: TSocket, size: int, timeout = -1) = bytesSkipped += recv(socket, dummy, avail) dealloc(dummy) -proc send*(socket: TSocket, data: pointer, size: int): int {. - tags: [FWriteIO].} = +proc send*(socket: Socket, data: pointer, size: int): int {. + tags: [WriteIOEffect].} = ## sends data to a socket. when defined(ssl): if socket.isSSL: @@ -1560,22 +1571,22 @@ proc send*(socket: TSocket, data: pointer, size: int): int {. const MSG_NOSIGNAL = 0 result = send(socket.fd, data, size, int32(MSG_NOSIGNAL)) -proc send*(socket: TSocket, data: string) {.tags: [FWriteIO].} = +proc send*(socket: Socket, data: string) {.tags: [WriteIOEffect].} = ## sends data to a socket. if socket.nonblocking: - raise newException(EInvalidValue, "This function cannot be used on non-blocking sockets.") + raise newException(ValueError, "This function cannot be used on non-blocking sockets.") let sent = send(socket, cstring(data), data.len) if sent < 0: when defined(ssl): if socket.isSSL: - SSLError() + raiseSslError() - osError(osLastError()) + raiseOSError(osLastError()) if sent != data.len: - raise newException(EOS, "Could not send all data.") + raise newException(OSError, "Could not send all data.") -proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} = +proc sendAsync*(socket: Socket, data: string): int {.tags: [WriteIOEffect].} = ## sends data to a non-blocking socket. ## Returns ``0`` if no data could be sent, if data has been sent ## returns the amount of bytes of ``data`` that was successfully sent. This @@ -1590,16 +1601,16 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} = let ret = SSLGetError(socket.sslHandle, result.cint) case ret of SSL_ERROR_ZERO_RETURN: - SSLError("TLS/SSL connection failed to initiate, socket closed prematurely.") + raiseSslError("TLS/SSL connection failed to initiate, socket closed prematurely.") of SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: - SSLError("Unexpected error occured.") # This should just not happen. + raiseSslError("Unexpected error occured.") # This should just not happen. of SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_READ: return 0 of SSL_ERROR_WANT_X509_LOOKUP: - SSLError("Function for x509 lookup has been called.") + raiseSslError("Function for x509 lookup has been called.") of SSL_ERROR_SYSCALL, SSL_ERROR_SSL: - SSLError() - else: SSLError("Unknown Error") + raiseSslError() + else: raiseSslError("Unknown Error") else: return if result == -1: @@ -1607,28 +1618,28 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} = when defined(windows): if err.int32 == WSAEINPROGRESS: return 0 - else: osError(err) + else: raiseOSError(err) else: if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK: return 0 - else: osError(err) + else: raiseOSError(err) -proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} = +proc trySend*(socket: Socket, data: string): bool {.tags: [WriteIOEffect].} = ## safe alternative to ``send``. Does not raise an EOS when an error occurs, ## and instead returns ``false`` on failure. result = send(socket, cstring(data), data.len) == data.len -proc sendTo*(socket: TSocket, address: string, port: TPort, data: pointer, - size: int, af: TDomain = AF_INET, flags = 0'i32): int {. - tags: [FWriteIO].} = +proc sendTo*(socket: Socket, address: string, port: Port, data: pointer, + size: int, af: Domain = AF_INET, flags = 0'i32): int {. + tags: [WriteIOEffect].} = ## low-level sendTo proc. This proc sends ``data`` to the specified ``address``, ## which may be an IP address or a hostname, if a hostname is specified ## this function will try each IP of that hostname. ## ## **Note:** This proc is not available for SSL sockets. - var hints: Taddrinfo - var aiList: ptr Taddrinfo = nil + var hints: AddrInfo + var aiList: ptr AddrInfo = nil hints.ai_family = toInt(af) hints.ai_socktype = toInt(SOCK_STREAM) hints.ai_protocol = toInt(IPPROTO_TCP) @@ -1639,7 +1650,7 @@ proc sendTo*(socket: TSocket, address: string, port: TPort, data: pointer, var it = aiList while it != nil: result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr, - it.ai_addrlen.TSocklen) + it.ai_addrlen.SockLen) if result != -1'i32: success = true break @@ -1647,8 +1658,8 @@ proc sendTo*(socket: TSocket, address: string, port: TPort, data: pointer, freeaddrinfo(aiList) -proc sendTo*(socket: TSocket, address: string, port: TPort, - data: string): int {.tags: [FWriteIO].} = +proc sendTo*(socket: Socket, address: string, port: Port, + data: string): int {.tags: [WriteIOEffect].} = ## Friendlier version of the low-level ``sendTo``. result = socket.sendTo(address, port, cstring(data), data.len) @@ -1659,33 +1670,33 @@ when defined(Windows): FIONBIO = IOC_IN.int32 or ((sizeof(int32) and IOCPARM_MASK) shl 16) or (102 shl 8) or 126 - proc ioctlsocket(s: TSocketHandle, cmd: clong, + proc ioctlsocket(s: SocketHandle, cmd: clong, argptr: ptr clong): cint {. stdcall, importc:"ioctlsocket", dynlib: "ws2_32.dll".} -proc setBlocking(s: TSocket, blocking: bool) = +proc setBlocking(s: Socket, blocking: bool) = when defined(Windows): var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking if ioctlsocket(s.fd, FIONBIO, addr(mode)) == -1: - osError(osLastError()) + raiseOSError(osLastError()) else: # BSD sockets var x: int = fcntl(s.fd, F_GETFL, 0) if x == -1: - osError(osLastError()) + raiseOSError(osLastError()) else: var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK if fcntl(s.fd, F_SETFL, mode) == -1: - osError(osLastError()) + raiseOSError(osLastError()) s.nonblocking = not blocking discard """ proc setReuseAddr*(s: TSocket) = var blah: int = 1 var mode = SO_REUSEADDR if setsockopt(s.fd, SOL_SOCKET, mode, addr blah, TSOcklen(sizeof(int))) == -1: - OSError(OSLastError()) """ + raiseOSError(osLastError()) """ -proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int, - af: TDomain = AF_INET) {.tags: [FReadIO, FWriteIO].} = +proc connect*(socket: Socket, address: string, port = Port(0), timeout: int, + af: Domain = AF_INET) {.tags: [ReadIOEffect, WriteIOEffect].} = ## Connects to server as specified by ``address`` on port specified by ``port``. ## ## The ``timeout`` paremeter specifies the time in miliseconds to allow for @@ -1694,9 +1705,9 @@ proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int, socket.setBlocking(false) socket.connectAsync(address, port, af) - var s: seq[TSocket] = @[socket] + var s: seq[Socket] = @[socket] if selectWrite(s, timeout) != 1: - raise newException(ETimeout, "Call to 'connect' timed out.") + raise newException(TimeoutError, "Call to 'connect' timed out.") else: when defined(ssl): if socket.isSSL: @@ -1704,17 +1715,17 @@ proc connect*(socket: TSocket, address: string, port = TPort(0), timeout: int, doAssert socket.handshake() socket.setBlocking(originalStatus) -proc isSSL*(socket: TSocket): bool = return socket.isSSL +proc isSSL*(socket: Socket): bool = return socket.isSSL ## Determines whether ``socket`` is a SSL socket. -proc getFD*(socket: TSocket): TSocketHandle = return socket.fd +proc getFD*(socket: Socket): SocketHandle = return socket.fd ## Returns the socket's file descriptor -proc isBlocking*(socket: TSocket): bool = not socket.nonblocking +proc isBlocking*(socket: Socket): bool = not socket.nonblocking ## Determines whether ``socket`` is blocking. when defined(Windows): - var wsa: TWSAData - if wsaStartup(0x0101'i16, addr wsa) != 0: osError(osLastError()) + var wsa: WSAData + if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError()) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index 63622a26c..31aa7497d 100644 --- a/lib/pure/streams.nim +++ b/lib/pure/streams.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -8,158 +8,160 @@ # ## This module provides a stream interface and two implementations thereof: -## the `PFileStream` and the `PStringStream` which implement the stream -## interface for Nimrod file objects (`TFile`) and strings. Other modules +## the `FileStream` and the `StringStream` which implement the stream +## interface for Nim file objects (`File`) and strings. Other modules ## may provide other implementations for this standard stream interface. include "system/inclrtl" -proc newEIO(msg: string): ref EIO = +proc newEIO(msg: string): ref IOError = new(result) result.msg = msg type - PStream* = ref TStream - TStream* = object of TObject ## Stream interface that supports - ## writing or reading. Note that these fields - ## here shouldn't be used directly. They are - ## accessible so that a stream implementation - ## can override them. - closeImpl*: proc (s: PStream) {.nimcall, tags: [], gcsafe.} - atEndImpl*: proc (s: PStream): bool {.nimcall, tags: [], gcsafe.} - setPositionImpl*: proc (s: PStream, pos: int) {.nimcall, tags: [], gcsafe.} - getPositionImpl*: proc (s: PStream): int {.nimcall, tags: [], gcsafe.} - readDataImpl*: proc (s: PStream, buffer: pointer, - bufLen: int): int {.nimcall, tags: [FReadIO], gcsafe.} - writeDataImpl*: proc (s: PStream, buffer: pointer, bufLen: int) {.nimcall, - tags: [FWriteIO], gcsafe.} - flushImpl*: proc (s: PStream) {.nimcall, tags: [FWriteIO], gcsafe.} - -proc flush*(s: PStream) = + Stream* = ref StreamObj + StreamObj* = object of RootObj ## Stream interface that supports + ## writing or reading. Note that these fields + ## here shouldn't be used directly. They are + ## accessible so that a stream implementation + ## can override them. + closeImpl*: proc (s: Stream) {.nimcall, tags: [], gcsafe.} + atEndImpl*: proc (s: Stream): bool {.nimcall, tags: [], gcsafe.} + setPositionImpl*: proc (s: Stream, pos: int) {.nimcall, tags: [], gcsafe.} + getPositionImpl*: proc (s: Stream): int {.nimcall, tags: [], gcsafe.} + readDataImpl*: proc (s: Stream, buffer: pointer, + bufLen: int): int {.nimcall, tags: [ReadIOEffect], gcsafe.} + writeDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int) {.nimcall, + tags: [WriteIOEffect], gcsafe.} + flushImpl*: proc (s: Stream) {.nimcall, tags: [WriteIOEffect], gcsafe.} + +{.deprecated: [PStream: Stream, TStream: StreamObj].} + +proc flush*(s: Stream) = ## flushes the buffers that the stream `s` might use. if not isNil(s.flushImpl): s.flushImpl(s) -proc close*(s: PStream) = +proc close*(s: Stream) = ## closes the stream `s`. if not isNil(s.closeImpl): s.closeImpl(s) -proc close*(s, unused: PStream) {.deprecated.} = +proc close*(s, unused: Stream) {.deprecated.} = ## closes the stream `s`. s.closeImpl(s) -proc atEnd*(s: PStream): bool = +proc atEnd*(s: Stream): bool = ## checks if more data can be read from `f`. Returns true if all data has ## been read. result = s.atEndImpl(s) -proc atEnd*(s, unused: PStream): bool {.deprecated.} = +proc atEnd*(s, unused: Stream): bool {.deprecated.} = ## checks if more data can be read from `f`. Returns true if all data has ## been read. result = s.atEndImpl(s) -proc setPosition*(s: PStream, pos: int) = +proc setPosition*(s: Stream, pos: int) = ## sets the position `pos` of the stream `s`. s.setPositionImpl(s, pos) -proc setPosition*(s, unused: PStream, pos: int) {.deprecated.} = +proc setPosition*(s, unused: Stream, pos: int) {.deprecated.} = ## sets the position `pos` of the stream `s`. s.setPositionImpl(s, pos) -proc getPosition*(s: PStream): int = +proc getPosition*(s: Stream): int = ## retrieves the current position in the stream `s`. result = s.getPositionImpl(s) -proc getPosition*(s, unused: PStream): int {.deprecated.} = +proc getPosition*(s, unused: Stream): int {.deprecated.} = ## retrieves the current position in the stream `s`. result = s.getPositionImpl(s) -proc readData*(s: PStream, buffer: pointer, bufLen: int): int = +proc readData*(s: Stream, buffer: pointer, bufLen: int): int = ## low level proc that reads data into an untyped `buffer` of `bufLen` size. result = s.readDataImpl(s, buffer, bufLen) -proc readData*(s, unused: PStream, buffer: pointer, +proc readData*(s, unused: Stream, buffer: pointer, bufLen: int): int {.deprecated.} = ## low level proc that reads data into an untyped `buffer` of `bufLen` size. result = s.readDataImpl(s, buffer, bufLen) -proc writeData*(s: PStream, buffer: pointer, bufLen: int) = +proc writeData*(s: Stream, buffer: pointer, bufLen: int) = ## low level proc that writes an untyped `buffer` of `bufLen` size ## to the stream `s`. s.writeDataImpl(s, buffer, bufLen) -proc writeData*(s, unused: PStream, buffer: pointer, +proc writeData*(s, unused: Stream, buffer: pointer, bufLen: int) {.deprecated.} = ## low level proc that writes an untyped `buffer` of `bufLen` size ## to the stream `s`. s.writeDataImpl(s, buffer, bufLen) -proc write*[T](s: PStream, x: T) = +proc write*[T](s: Stream, x: T) = ## generic write procedure. Writes `x` to the stream `s`. Implementation: ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## ## s.writeData(s, addr(x), sizeof(x)) var y: T shallowCopy(y, x) writeData(s, addr(y), sizeof(y)) -proc write*(s: PStream, x: string) = +proc write*(s: Stream, x: string) = ## writes the string `x` to the the stream `s`. No length field or ## terminating zero is written. writeData(s, cstring(x), x.len) -proc writeln*(s: PStream, args: varargs[string, `$`]) = +proc writeln*(s: Stream, args: varargs[string, `$`]) = ## writes one or more strings to the the stream `s` followed ## by a new line. No length field or terminating zero is written. for str in args: write(s, str) write(s, "\n") -proc read[T](s: PStream, result: var T) = +proc read[T](s: Stream, result: var T) = ## generic read procedure. Reads `result` from the stream `s`. if readData(s, addr(result), sizeof(T)) != sizeof(T): raise newEIO("cannot read from stream") -proc readChar*(s: PStream): char = +proc readChar*(s: Stream): char = ## reads a char from the stream `s`. Raises `EIO` if an error occured. ## Returns '\0' as an EOF marker. if readData(s, addr(result), sizeof(result)) != 1: result = '\0' -proc readBool*(s: PStream): bool = +proc readBool*(s: Stream): bool = ## reads a bool from the stream `s`. Raises `EIO` if an error occured. read(s, result) -proc readInt8*(s: PStream): int8 = +proc readInt8*(s: Stream): int8 = ## reads an int8 from the stream `s`. Raises `EIO` if an error occured. read(s, result) -proc readInt16*(s: PStream): int16 = +proc readInt16*(s: Stream): int16 = ## reads an int16 from the stream `s`. Raises `EIO` if an error occured. read(s, result) -proc readInt32*(s: PStream): int32 = +proc readInt32*(s: Stream): int32 = ## reads an int32 from the stream `s`. Raises `EIO` if an error occured. read(s, result) -proc readInt64*(s: PStream): int64 = +proc readInt64*(s: Stream): int64 = ## reads an int64 from the stream `s`. Raises `EIO` if an error occured. read(s, result) -proc readFloat32*(s: PStream): float32 = +proc readFloat32*(s: Stream): float32 = ## reads a float32 from the stream `s`. Raises `EIO` if an error occured. read(s, result) -proc readFloat64*(s: PStream): float64 = +proc readFloat64*(s: Stream): float64 = ## reads a float64 from the stream `s`. Raises `EIO` if an error occured. read(s, result) -proc readStr*(s: PStream, length: int): TaintedString = +proc readStr*(s: Stream, length: int): TaintedString = ## reads a string of length `length` from the stream `s`. Raises `EIO` if ## an error occured. result = newString(length).TaintedString var L = readData(s, addr(string(result)[0]), length) if L != length: setLen(result.string, L) -proc readLine*(s: PStream, line: var TaintedString): bool = +proc readLine*(s: Stream, line: var TaintedString): bool = ## reads a line of text from the stream `s` into `line`. `line` must not be ## ``nil``! May throw an IO exception. ## A line of text may be delimited by ``CR``, ``LF`` or @@ -179,7 +181,7 @@ proc readLine*(s: PStream, line: var TaintedString): bool = line.string.add(c) result = true -proc readLine*(s: PStream): TaintedString = +proc readLine*(s: Stream): TaintedString = ## Reads a line from a stream `s`. Note: This is not very efficient. Raises ## `EIO` if an error occured. result = TaintedString"" @@ -194,42 +196,44 @@ proc readLine*(s: PStream): TaintedString = result.string.add(c) type - PStringStream* = ref TStringStream ## a stream that encapsulates a string - TStringStream* = object of TStream + StringStream* = ref StringStreamObj ## a stream that encapsulates a string + StringStreamObj* = object of StreamObj data*: string pos: int - -proc ssAtEnd(s: PStream): bool = - var s = PStringStream(s) + +{.deprecated: [PStringStream: StringStream, TStringStream: StringStreamObj].} + +proc ssAtEnd(s: Stream): bool = + var s = StringStream(s) return s.pos >= s.data.len -proc ssSetPosition(s: PStream, pos: int) = - var s = PStringStream(s) +proc ssSetPosition(s: Stream, pos: int) = + var s = StringStream(s) s.pos = clamp(pos, 0, s.data.high) -proc ssGetPosition(s: PStream): int = - var s = PStringStream(s) +proc ssGetPosition(s: Stream): int = + var s = StringStream(s) return s.pos -proc ssReadData(s: PStream, buffer: pointer, bufLen: int): int = - var s = PStringStream(s) +proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int = + var s = StringStream(s) result = min(bufLen, s.data.len - s.pos) if result > 0: copyMem(buffer, addr(s.data[s.pos]), result) inc(s.pos, result) -proc ssWriteData(s: PStream, buffer: pointer, bufLen: int) = - var s = PStringStream(s) +proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) = + var s = StringStream(s) if bufLen > 0: setLen(s.data, s.data.len + bufLen) copyMem(addr(s.data[s.pos]), buffer, bufLen) inc(s.pos, bufLen) -proc ssClose(s: PStream) = - var s = PStringStream(s) +proc ssClose(s: Stream) = + var s = StringStream(s) s.data = nil -proc newStringStream*(s: string = ""): PStringStream = +proc newStringStream*(s: string = ""): StringStream = ## creates a new stream from the string `s`. new(result) result.data = s @@ -244,27 +248,28 @@ proc newStringStream*(s: string = ""): PStringStream = when not defined(js): type - PFileStream* = ref TFileStream ## a stream that encapsulates a `TFile` - TFileStream* = object of TStream - f: TFile - - proc fsClose(s: PStream) = - if PFileStream(s).f != nil: - close(PFileStream(s).f) - PFileStream(s).f = nil - proc fsFlush(s: PStream) = flushFile(PFileStream(s).f) - proc fsAtEnd(s: PStream): bool = return endOfFile(PFileStream(s).f) - proc fsSetPosition(s: PStream, pos: int) = setFilePos(PFileStream(s).f, pos) - proc fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f)) - - proc fsReadData(s: PStream, buffer: pointer, bufLen: int): int = - result = readBuffer(PFileStream(s).f, buffer, bufLen) - - proc fsWriteData(s: PStream, buffer: pointer, bufLen: int) = - if writeBuffer(PFileStream(s).f, buffer, bufLen) != bufLen: + FileStream* = ref FileStreamObj ## a stream that encapsulates a `TFile` + FileStreamObj* = object of Stream + f: File + {.deprecated: [PFileStream: FileStream, TFileStream: FileStreamObj].} + + proc fsClose(s: Stream) = + if FileStream(s).f != nil: + close(FileStream(s).f) + FileStream(s).f = nil + proc fsFlush(s: Stream) = flushFile(FileStream(s).f) + proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f) + proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos) + proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f)) + + proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = + result = readBuffer(FileStream(s).f, buffer, bufLen) + + proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = + if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: raise newEIO("cannot write to stream") - proc newFileStream*(f: TFile): PFileStream = + proc newFileStream*(f: File): FileStream = ## creates a new stream from the file `f`. new(result) result.f = f @@ -276,11 +281,11 @@ when not defined(js): result.writeDataImpl = fsWriteData result.flushImpl = fsFlush - proc newFileStream*(filename: string, mode: TFileMode): PFileStream = + proc newFileStream*(filename: string, mode: FileMode): FileStream = ## creates a new stream from the file named `filename` with the mode `mode`. ## If the file cannot be opened, nil is returned. See the `system ## <system.html>`_ module for a list of available TFileMode enums. - var f: TFile + var f: File if open(f, filename, mode): result = newFileStream(f) @@ -288,45 +293,47 @@ when true: discard else: type - TFileHandle* = cint ## Operating system file handle - PFileHandleStream* = ref TFileHandleStream - TFileHandleStream* = object of TStream - handle*: TFileHandle + FileHandleStream* = ref FileHandleStreamObj + FileHandleStreamObj* = object of Stream + handle*: FileHandle pos: int - proc newEOS(msg: string): ref EOS = + {.deprecated: [PFileHandleStream: FileHandleStream, + TFileHandleStream: FileHandleStreamObj].} + + proc newEOS(msg: string): ref OSError = new(result) result.msg = msg - proc hsGetPosition(s: PFileHandleStream): int = + proc hsGetPosition(s: FileHandleStream): int = return s.pos when defined(windows): # do not import windows as this increases compile times: - nil + discard else: import posix - proc hsSetPosition(s: PFileHandleStream, pos: int) = + proc hsSetPosition(s: FileHandleStream, pos: int) = discard lseek(s.handle, pos, SEEK_SET) - proc hsClose(s: PFileHandleStream) = discard close(s.handle) - proc hsAtEnd(s: PFileHandleStream): bool = + proc hsClose(s: FileHandleStream) = discard close(s.handle) + proc hsAtEnd(s: FileHandleStream): bool = var pos = hsGetPosition(s) var theEnd = lseek(s.handle, 0, SEEK_END) result = pos >= theEnd hsSetPosition(s, pos) # set position back - proc hsReadData(s: PFileHandleStream, buffer: pointer, bufLen: int): int = + proc hsReadData(s: FileHandleStream, buffer: pointer, bufLen: int): int = result = posix.read(s.handle, buffer, bufLen) inc(s.pos, result) - proc hsWriteData(s: PFileHandleStream, buffer: pointer, bufLen: int) = + proc hsWriteData(s: FileHandleStream, buffer: pointer, bufLen: int) = if posix.write(s.handle, buffer, bufLen) != bufLen: raise newEIO("cannot write to stream") inc(s.pos, bufLen) - proc newFileHandleStream*(handle: TFileHandle): PFileHandleStream = + proc newFileHandleStream*(handle: FileHandle): FileHandleStream = new(result) result.handle = handle result.pos = 0 @@ -338,9 +345,9 @@ else: result.writeData = hsWriteData proc newFileHandleStream*(filename: string, - mode: TFileMode): PFileHandleStream = - when defined(windows): - nil + mode: FileMode): FileHandleStream = + when defined(windows): + discard else: var flags: cint case mode diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim index 7003acfcf..5b7149d8e 100644 --- a/lib/pure/strtabs.nim +++ b/lib/pure/strtabs.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -18,43 +18,46 @@ import include "system/inclrtl" type - TStringTableMode* = enum ## describes the tables operation mode + StringTableMode* = enum ## describes the tables operation mode modeCaseSensitive, ## the table is case sensitive modeCaseInsensitive, ## the table is case insensitive modeStyleInsensitive ## the table is style insensitive - TKeyValuePair = tuple[key, val: string] - TKeyValuePairSeq = seq[TKeyValuePair] - TStringTable* = object of TObject + KeyValuePair = tuple[key, val: string] + KeyValuePairSeq = seq[KeyValuePair] + StringTableObj* = object of RootObj counter: int - data: TKeyValuePairSeq - mode: TStringTableMode + data: KeyValuePairSeq + mode: StringTableMode - PStringTable* = ref TStringTable ## use this type to declare string tables + StringTableRef* = ref StringTableObj ## use this type to declare string tables -proc len*(t: PStringTable): int {.rtl, extern: "nst$1".} = +{.deprecated: [TStringTableMode: StringTableMode, + TStringTable: StringTableObj, PStringTable: StringTableRef].} + +proc len*(t: StringTableRef): int {.rtl, extern: "nst$1".} = ## returns the number of keys in `t`. result = t.counter -iterator pairs*(t: PStringTable): tuple[key, value: string] = +iterator pairs*(t: StringTableRef): tuple[key, value: string] = ## iterates over every (key, value) pair in the table `t`. for h in 0..high(t.data): if not isNil(t.data[h].key): yield (t.data[h].key, t.data[h].val) -iterator keys*(t: PStringTable): string = +iterator keys*(t: StringTableRef): string = ## iterates over every key in the table `t`. for h in 0..high(t.data): if not isNil(t.data[h].key): yield t.data[h].key -iterator values*(t: PStringTable): string = +iterator values*(t: StringTableRef): string = ## iterates over every value in the table `t`. for h in 0..high(t.data): if not isNil(t.data[h].key): yield t.data[h].val type - TFormatFlag* = enum ## flags for the `%` operator + FormatFlag* = enum ## flags for the `%` operator useEnvironment, ## use environment variable if the ``$key`` ## is not found in the table useEmpty, ## use the empty string as a default, thus it @@ -63,19 +66,21 @@ type useKey ## do not replace ``$key`` if it is not found ## in the table (or in the environment) +{.deprecated: [TFormatFlag: FormatFlag].} + # implementation const growthFactor = 2 startSize = 64 -proc myhash(t: PStringTable, key: string): THash = +proc myhash(t: StringTableRef, key: string): THash = case t.mode of modeCaseSensitive: result = hashes.hash(key) of modeCaseInsensitive: result = hashes.hashIgnoreCase(key) of modeStyleInsensitive: result = hashes.hashIgnoreStyle(key) -proc myCmp(t: PStringTable, a, b: string): bool = +proc myCmp(t: StringTableRef, a, b: string): bool = case t.mode of modeCaseSensitive: result = cmp(a, b) == 0 of modeCaseInsensitive: result = cmpIgnoreCase(a, b) == 0 @@ -88,7 +93,7 @@ proc mustRehash(length, counter: int): bool = proc nextTry(h, maxHash: THash): THash {.inline.} = result = ((5 * h) + 1) and maxHash -proc rawGet(t: PStringTable, key: string): int = +proc rawGet(t: StringTableRef, key: string): int = var h: THash = myhash(t, key) and high(t.data) # start with real hash value while not isNil(t.data[h].key): if myCmp(t, t.data[h].key, key): @@ -96,7 +101,7 @@ proc rawGet(t: PStringTable, key: string): int = h = nextTry(h, high(t.data)) result = - 1 -proc `[]`*(t: PStringTable, key: string): string {.rtl, extern: "nstGet".} = +proc `[]`*(t: StringTableRef, key: string): string {.rtl, extern: "nstGet".} = ## retrieves the value at ``t[key]``. If `key` is not in `t`, "" is returned ## and no exception is raised. One can check with ``hasKey`` whether the key ## exists. @@ -104,33 +109,33 @@ proc `[]`*(t: PStringTable, key: string): string {.rtl, extern: "nstGet".} = if index >= 0: result = t.data[index].val else: result = "" -proc mget*(t: PStringTable, key: string): var string {. +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. var index = rawGet(t, key) if index >= 0: result = t.data[index].val - else: raise newException(EInvalidKey, "key does not exist: " & key) + else: raise newException(KeyError, "key does not exist: " & key) -proc hasKey*(t: PStringTable, key: string): bool {.rtl, extern: "nst$1".} = +proc hasKey*(t: StringTableRef, key: string): bool {.rtl, extern: "nst$1".} = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 -proc rawInsert(t: PStringTable, data: var TKeyValuePairSeq, key, val: string) = +proc rawInsert(t: StringTableRef, data: var KeyValuePairSeq, key, val: string) = var h: THash = myhash(t, key) and high(data) while not isNil(data[h].key): h = nextTry(h, high(data)) data[h].key = key data[h].val = val -proc enlarge(t: PStringTable) = - var n: TKeyValuePairSeq +proc enlarge(t: StringTableRef) = + var n: KeyValuePairSeq newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(t.data)): if not isNil(t.data[i].key): rawInsert(t, n, t.data[i].key, t.data[i].val) swap(t.data, n) -proc `[]=`*(t: PStringTable, key, val: string) {.rtl, extern: "nstPut".} = +proc `[]=`*(t: StringTableRef, key, val: string) {.rtl, extern: "nstPut".} = ## puts a (key, value)-pair into `t`. var index = rawGet(t, key) if index >= 0: @@ -141,12 +146,12 @@ proc `[]=`*(t: PStringTable, key, val: string) {.rtl, extern: "nstPut".} = inc(t.counter) proc raiseFormatException(s: string) = - var e: ref EInvalidValue + var e: ref ValueError new(e) e.msg = "format string: key not found: " & s raise e -proc getValue(t: PStringTable, flags: set[TFormatFlag], key: string): string = +proc getValue(t: StringTableRef, flags: set[FormatFlag], key: string): string = if hasKey(t, key): return t[key] # hm difficult: assume safety in taint mode here. XXX This is dangerous! if useEnvironment in flags: result = os.getEnv(key).string @@ -155,7 +160,7 @@ proc getValue(t: PStringTable, flags: set[TFormatFlag], key: string): string = if useKey in flags: result = '$' & key elif not (useEmpty in flags): raiseFormatException(key) -proc newStringTable*(mode: TStringTableMode): PStringTable {. +proc newStringTable*(mode: StringTableMode): StringTableRef {. rtl, extern: "nst$1".} = ## creates a new string table that is empty. new(result) @@ -164,7 +169,7 @@ proc newStringTable*(mode: TStringTableMode): PStringTable {. newSeq(result.data, startSize) proc newStringTable*(keyValuePairs: varargs[string], - mode: TStringTableMode): PStringTable {. + mode: StringTableMode): StringTableRef {. rtl, extern: "nst$1WithPairs".} = ## creates a new string table with given key value pairs. ## Example:: @@ -177,7 +182,7 @@ proc newStringTable*(keyValuePairs: varargs[string], inc(i, 2) proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]], - mode: TStringTableMode = modeCaseSensitive): PStringTable {. + mode: StringTableMode = modeCaseSensitive): StringTableRef {. rtl, extern: "nst$1WithTableConstr".} = ## creates a new string table with given key value pairs. ## Example:: @@ -186,7 +191,7 @@ proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]], result = newStringTable(mode) for key, val in items(keyValuePairs): result[key] = val -proc `%`*(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string {. +proc `%`*(f: string, t: StringTableRef, flags: set[FormatFlag] = {}): string {. rtl, extern: "nstFormat".} = ## The `%` operator for string tables. const @@ -216,7 +221,7 @@ proc `%`*(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string {. add(result, f[i]) inc(i) -proc `$`*(t: PStringTable): string {.rtl, extern: "nstDollar".} = +proc `$`*(t: StringTableRef): string {.rtl, extern: "nstDollar".} = ## The `$` operator for string tables. if t.len == 0: result = "{:}" diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index 1d17de233..55a204b4c 100644 --- a/lib/pure/strutils.nim +++ b/lib/pure/strutils.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -23,7 +23,7 @@ import parseutils include "system/inclrtl" type - TCharSet* = set[char] # for compatibility with Nim + TCharSet* {.deprecated.} = set[char] # for compatibility with Nim const Whitespace* = {' ', '\t', '\v', '\r', '\l', '\f'} @@ -54,7 +54,7 @@ const ## make the `find() proc <#find,string,set[char],int>`_ find **invalid** ## characters in strings. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## let invalid = AllChars - Digits ## doAssert "01234".find(invalid) == -1 ## doAssert "01A34".find(invalid) == 2 @@ -117,7 +117,7 @@ proc normalize*(s: string): string {.noSideEffect, procvar, ## Normalizes the string `s`. ## ## That means to convert it to lower case and remove any '_'. This is needed - ## for Nimrod identifiers for example. + ## for Nim identifiers for example. result = newString(s.len) var j = 0 for i in 0..len(s) - 1: @@ -130,7 +130,7 @@ proc normalize*(s: string): string {.noSideEffect, procvar, if j != s.len: setLen(result, j) proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, - rtl, extern: "nsuCmpIgnoreCase", procvar, operator: 4.} = + rtl, extern: "nsuCmpIgnoreCase", procvar.} = ## Compares two strings in a case insensitive manner. Returns: ## ## | 0 iff a == b @@ -148,7 +148,7 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect, # thus we compile without checks here proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, - rtl, extern: "nsuCmpIgnoreStyle", procvar, operator: 3.} = + rtl, extern: "nsuCmpIgnoreStyle", procvar.} = ## Compares two strings normalized (i.e. case and ## underscores do not matter). Returns: ## @@ -170,7 +170,7 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect, {.pop.} proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect, - rtl, extern: "nsuStrip", operator: 5.} = + rtl, extern: "nsuStrip".} = ## Strips whitespace from `s` and returns the resulting string. ## ## If `leading` is true, leading whitespace is stripped. @@ -205,7 +205,7 @@ iterator split*(s: string, seps: set[char] = Whitespace): string = ## a single split point and leading/trailing separators will be ignored. ## The following example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for word in split(" this is an example "): ## writeln(stdout, word) ## @@ -219,13 +219,13 @@ iterator split*(s: string, seps: set[char] = Whitespace): string = ## ## And the following code: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for word in split(";;this;is;an;;example;;;", {';'}): ## writeln(stdout, word) ## ## ...produces the same output as the first example. The code: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## let date = "2012-11-20T22:08:08.398990" ## let separators = {' ', '-', ':', 'T'} ## for number in split(date, separators): @@ -258,7 +258,7 @@ iterator split*(s: string, sep: char): string = ## characters, this proc will not coalesce groups of the ## separator, returning a string for each found character. The code: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for word in split(";;this;is;an;;example;;;", ';'): ## writeln(stdout, word) ## @@ -308,13 +308,13 @@ iterator splitLines*(s: string): string = ## ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for line in splitLines("\nthis\nis\nan\n\nexample\n"): ## writeln(stdout, line) ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "" ## "this" ## "is" @@ -417,34 +417,34 @@ proc parseInt*(s: string): int {.noSideEffect, procvar, rtl, extern: "nsuParseInt".} = ## Parses a decimal integer value contained in `s`. ## - ## If `s` is not a valid integer, `EInvalidValue` is raised. + ## If `s` is not a valid integer, `ValueError` is raised. var L = parseutils.parseInt(s, result, 0) if L != s.len or L == 0: - raise newException(EInvalidValue, "invalid integer: " & s) + raise newException(ValueError, "invalid integer: " & s) proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar, rtl, extern: "nsuParseBiggestInt".} = ## Parses a decimal integer value contained in `s`. ## - ## If `s` is not a valid integer, `EInvalidValue` is raised. + ## If `s` is not a valid integer, `ValueError` is raised. var L = parseutils.parseBiggestInt(s, result, 0) if L != s.len or L == 0: - raise newException(EInvalidValue, "invalid integer: " & s) + raise newException(ValueError, "invalid integer: " & s) proc parseFloat*(s: string): float {.noSideEffect, procvar, rtl, extern: "nsuParseFloat".} = ## Parses a decimal floating point value contained in `s`. If `s` is not - ## a valid floating point number, `EInvalidValue` is raised. ``NAN``, + ## a valid floating point number, `ValueError` is raised. ``NAN``, ## ``INF``, ``-INF`` are also supported (case insensitive comparison). var L = parseutils.parseFloat(s, result, 0) if L != s.len or L == 0: - raise newException(EInvalidValue, "invalid float: " & s) + raise newException(ValueError, "invalid float: " & s) proc parseHexInt*(s: string): int {.noSideEffect, procvar, rtl, extern: "nsuParseHexInt".} = ## Parses a hexadecimal integer value contained in `s`. ## - ## If `s` is not a valid integer, `EInvalidValue` is raised. `s` can have one + ## If `s` is not a valid integer, `ValueError` is raised. `s` can have one ## of the following optional prefixes: ``0x``, ``0X``, ``#``. Underscores ## within `s` are ignored. var i = 0 @@ -463,7 +463,7 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar, result = result shl 4 or (ord(s[i]) - ord('A') + 10) inc(i) of '\0': break - else: raise newException(EInvalidValue, "invalid integer: " & s) + else: raise newException(ValueError, "invalid integer: " & s) proc parseBool*(s: string): bool = ## Parses a value into a `bool`. @@ -471,21 +471,21 @@ proc parseBool*(s: string): bool = ## If ``s`` is one of the following values: ``y, yes, true, 1, on``, then ## returns `true`. If ``s`` is one of the following values: ``n, no, false, ## 0, off``, then returns `false`. If ``s`` is something else a - ## ``EInvalidValue`` exception is raised. + ## ``ValueError`` exception is raised. case normalize(s) of "y", "yes", "true", "1", "on": result = true of "n", "no", "false", "0", "off": result = false - else: raise newException(EInvalidValue, "cannot interpret as a bool: " & s) + else: raise newException(ValueError, "cannot interpret as a bool: " & s) proc parseEnum*[T: enum](s: string): T = ## Parses an enum ``T``. ## - ## Raises ``EInvalidValue`` for an invalid value in `s`. The comparison is + ## Raises ``ValueError`` for an invalid value in `s`. The comparison is ## done in a style insensitive way. for e in low(T)..high(T): if cmpIgnoreStyle(s, $e) == 0: return e - raise newException(EInvalidValue, "invalid enum value: " & s) + raise newException(ValueError, "invalid enum value: " & s) proc parseEnum*[T: enum](s: string, default: T): T = ## Parses an enum ``T``. @@ -502,7 +502,7 @@ proc repeatChar*(count: int, c: char = ' '): string {.noSideEffect, ## Returns a string of length `count` consisting only of ## the character `c`. You can use this proc to left align strings. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## let ## width = 15 ## text1 = "Hello user!" @@ -527,7 +527,7 @@ proc align*(s: string, count: int, padding = ' '): string {. ## returned unchanged. If you need to left align a string use the `repeatChar ## proc <#repeatChar>`_. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## assert align("abc", 4) == " abc" ## assert align("a", 0) == "a" ## assert align("1232", 6) == " 1232" @@ -547,13 +547,13 @@ iterator tokenize*(s: string, seps: set[char] = Whitespace): tuple[ ## Substrings are separated by a substring containing only `seps`. ## Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for word in tokenize(" this is an example "): ## writeln(stdout, word) ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## (" ", true) ## ("this", false) ## (" ", true) @@ -676,7 +676,7 @@ proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect, ## ## A shorthand for: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## if dest.len > startLen: add(dest, sep) ## ## This is often useful for generating some code where the items need to @@ -684,7 +684,7 @@ proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect, ## `startLen`. The following example creates a string describing ## an array of integers: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var arr = "[" ## for x in items([2, 3, 5, 7, 11]): ## addSep(arr, startLen=len("[")) @@ -692,7 +692,7 @@ proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect, ## add(arr, "]") if dest.len > startLen: add(dest, sep) -proc allCharsInSet*(s: string, theSet: TCharSet): bool = +proc allCharsInSet*(s: string, theSet: set[char]): bool = ## Returns true iff each character of `s` is in the set `theSet`. for c in items(s): if c notin theSet: return false @@ -739,14 +739,14 @@ proc join*(a: openArray[string]): string {. result = "" type - TSkipTable = array[char, int] + SkipTable = array[char, int] -proc preprocessSub(sub: string, a: var TSkipTable) = +proc preprocessSub(sub: string, a: var SkipTable) = var m = len(sub) for i in 0..0xff: a[chr(i)] = m+1 for i in 0..m-1: a[sub[i]] = m-i -proc findAux(s, sub: string, start: int, a: TSkipTable): int = +proc findAux(s, sub: string, start: int, a: SkipTable): int = # Fast "quick search" algorithm: var m = len(sub) @@ -762,11 +762,11 @@ proc findAux(s, sub: string, start: int, a: TSkipTable): int = return -1 proc find*(s, sub: string, start: int = 0): int {.noSideEffect, - rtl, extern: "nsuFindStr", operator: 6.} = + rtl, extern: "nsuFindStr".} = ## Searches for `sub` in `s` starting at position `start`. ## ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned. - var a {.noinit.}: TSkipTable + var a {.noinit.}: SkipTable preprocessSub(sub, a) result = findAux(s, sub, start, a) @@ -857,9 +857,9 @@ proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} = return find(s, chars) >= 0 proc replace*(s, sub: string, by = ""): string {.noSideEffect, - rtl, extern: "nsuReplaceStr", operator: 1.} = + rtl, extern: "nsuReplaceStr".} = ## Replaces `sub` in `s` by the string `by`. - var a {.noinit.}: TSkipTable + var a {.noinit.}: SkipTable result = "" preprocessSub(sub, a) var i = 0 @@ -892,7 +892,7 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect, ## (comparable to ``\\w`` in regular expressions), otherwise it is not ## replaced. const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'} - var a {.noinit.}: TSkipTable + var a {.noinit.}: SkipTable result = "" preprocessSub(sub, a) var i = 0 @@ -929,7 +929,7 @@ proc parseOctInt*(s: string): int {.noSideEffect, rtl, extern: "nsuParseOctInt".} = ## Parses an octal integer value contained in `s`. ## - ## If `s` is not a valid integer, `EInvalidValue` is raised. `s` can have one + ## If `s` is not a valid integer, `ValueError` is raised. `s` can have one ## of the following optional prefixes: ``0o``, ``0O``. Underscores within ## `s` are ignored. var i = 0 @@ -941,7 +941,7 @@ proc parseOctInt*(s: string): int {.noSideEffect, result = result shl 3 or (ord(s[i]) - ord('0')) inc(i) of '\0': break - else: raise newException(EInvalidValue, "invalid integer: " & s) + else: raise newException(ValueError, "invalid integer: " & s) proc toOct*(x: BiggestInt, len: int): string {.noSideEffect, rtl, extern: "nsuToOct".} = @@ -1029,11 +1029,11 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, ## operations. ## ## If `s` does not begin with ``prefix`` and end with ``suffix`` a - ## EInvalidValue exception will be raised. + ## ValueError exception will be raised. result = newStringOfCap(s.len) var i = 0 if s[0 .. prefix.len-1] != prefix: - raise newException(EInvalidValue, + raise newException(ValueError, "String does not start with a prefix of: " & prefix) i.inc() while true: @@ -1058,7 +1058,7 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect, result.add(s[i]) i.inc() if s[i .. -1] != suffix: - raise newException(EInvalidValue, + raise newException(ValueError, "String does not end with a suffix of: " & suffix) proc validIdentifier*(s: string): bool {.noSideEffect, @@ -1168,14 +1168,16 @@ proc c_sprintf(buf, frmt: cstring) {.header: "<stdio.h>", importc: "sprintf", varargs, noSideEffect.} type - TFloatFormat* = enum ## the different modes of floating point formating + FloatFormatMode* = enum ## the different modes of floating point formating ffDefault, ## use the shorter floating point notation ffDecimal, ## use decimal floating point notation ffScientific ## use scientific notation (using ``e`` character) -proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault, +{.deprecated: [TFloatFormat: FloatFormatMode].} + +proc formatBiggestFloat*(f: BiggestFloat, format: FloatFormatMode = ffDefault, precision: range[0..32] = 16): string {. - noSideEffect, operator: 2, rtl, extern: "nsu$1".} = + noSideEffect, rtl, extern: "nsu$1".} = ## Converts a floating point value `f` to a string. ## ## If ``format == ffDecimal`` then precision is the number of digits to @@ -1183,10 +1185,10 @@ proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault, ## If ``format == ffScientific`` then precision is the maximum number ## of significant digits to be printed. ## `precision`'s default value is the maximum number of meaningful digits - ## after the decimal point for Nimrod's ``biggestFloat`` type. + ## after the decimal point for Nim's ``biggestFloat`` type. ## ## If ``precision == 0``, it tries to format it nicely. - const floatFormatToChar: array[TFloatFormat, char] = ['g', 'f', 'e'] + const floatFormatToChar: array[FloatFormatMode, char] = ['g', 'f', 'e'] var frmtstr {.noinit.}: array[0..5, char] buf {.noinit.}: array[0..2500, char] @@ -1204,9 +1206,9 @@ proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault, c_sprintf(buf, frmtstr, f) result = $buf -proc formatFloat*(f: float, format: TFloatFormat = ffDefault, +proc formatFloat*(f: float, format: FloatFormatMode = ffDefault, precision: range[0..32] = 16): string {. - noSideEffect, operator: 2, rtl, extern: "nsu$1".} = + noSideEffect, rtl, extern: "nsu$1".} = ## Converts a floating point value `f` to a string. ## ## If ``format == ffDecimal`` then precision is the number of digits to @@ -1214,13 +1216,13 @@ proc formatFloat*(f: float, format: TFloatFormat = ffDefault, ## If ``format == ffScientific`` then precision is the maximum number ## of significant digits to be printed. ## `precision`'s default value is the maximum number of meaningful digits - ## after the decimal point for Nimrod's ``float`` type. + ## after the decimal point for Nim's ``float`` type. result = formatBiggestFloat(f, format, precision) proc formatSize*(bytes: BiggestInt, decimalSep = '.'): string = ## Rounds and formats `bytes`. Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## formatSize(1'i64 shl 31 + 300'i64) == "2.204GB" ## formatSize(4096) == "4KB" @@ -1249,7 +1251,7 @@ proc findNormalized(x: string, inArray: openArray[string]): int = return -1 proc invalidFormatString() {.noinline.} = - raise newException(EInvalidValue, "invalid format string") + raise newException(ValueError, "invalid format string") proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {. noSideEffect, rtl, extern: "nsuAddf".} = @@ -1310,12 +1312,12 @@ proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect, ## ## This is best explained by an example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "$1 eats $2." % ["The cat", "fish"] ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "The cat eats fish." ## ## The substitution variables (the thing after the ``$``) are enumerated @@ -1324,7 +1326,7 @@ proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect, ## The notation ``$#`` can be used to refer to the next substitution ## variable: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "$# eats $#." % ["The cat", "fish"] ## ## Substitution variables can also be words (that is @@ -1332,15 +1334,15 @@ proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect, ## indices are keys and with odd indices are the corresponding values. ## An example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "$animal eats $food." % ["animal", "The cat", "food", "fish"] ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "The cat eats fish." ## - ## The variables are compared with `cmpIgnoreStyle`. `EInvalidValue` is + ## The variables are compared with `cmpIgnoreStyle`. `ValueError` is ## raised if an ill-formed format string has been passed to the `%` operator. result = newStringOfCap(formatstr.len + a.len shl 4) addf(result, formatstr, a) @@ -1380,8 +1382,8 @@ when isMainModule: doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz " doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz abc" - type TMyEnum = enum enA, enB, enC, enuD, enE - doAssert parseEnum[TMyEnum]("enu_D") == enuD + type MyEnum = enum enA, enB, enC, enuD, enE + doAssert parseEnum[MyEnum]("enu_D") == enuD doAssert parseEnum("invalid enum value", enC) == enC diff --git a/lib/pure/subexes.nim b/lib/pure/subexes.nim index ed87610d6..c87823926 100644 --- a/lib/pure/subexes.nim +++ b/lib/pure/subexes.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Nimrod support for `substitution expressions`:idx: (`subex`:idx:). +## Nim support for `substitution expressions`:idx: (`subex`:idx:). ## ## .. include:: ../doc/subexes.txt ## @@ -28,11 +28,13 @@ proc findNormalized(x: string, inArray: openarray[string]): int = return -1 type - EInvalidSubex* = object of EInvalidValue ## exception that is raised for - ## an invalid subex + SubexError* = object of ValueError ## exception that is raised for + ## an invalid subex + +{.deprecated: [EInvalidSubex: SubexError].} proc raiseInvalidFormat(msg: string) {.noinline.} = - raise newException(EInvalidSubex, "invalid format string: " & msg) + raise newException(SubexError, "invalid format string: " & msg) type TFormatParser = object {.pure, final.} @@ -194,6 +196,9 @@ proc scanDollar(p: var TFormatParser, a: openarray[string], s: var string) = of '$': emitChar p, s, '$' inc i + of '*': + for j in 0..a.high: emitStr p, s, a[j] + inc i of '{': call: let (x, y) = scanSlice(p, a) @@ -291,14 +296,16 @@ proc scanDollar(p: var TFormatParser, a: openarray[string], s: var string) = type - TSubex* = distinct string ## string that contains a substitution expression + Subex* = distinct string ## string that contains a substitution expression + +{.deprecated: [TSubex: Subex].} -proc subex*(s: string): TSubex = +proc subex*(s: string): Subex = ## constructs a *substitution expression* from `s`. Currently this performs ## no syntax checking but this may change in later versions. - result = TSubex(s) + result = Subex(s) -proc addf*(s: var string, formatstr: TSubex, a: varargs[string, `$`]) {. +proc addf*(s: var string, formatstr: Subex, a: varargs[string, `$`]) {. noSideEffect, rtl, extern: "nfrmtAddf".} = ## The same as ``add(s, formatstr % a)``, but more efficient. var p: TFormatParser @@ -312,7 +319,7 @@ proc addf*(s: var string, formatstr: TSubex, a: varargs[string, `$`]) {. emitChar(p, s, p.f[i]) inc(i) -proc `%` *(formatstr: TSubex, a: openarray[string]): string {.noSideEffect, +proc `%` *(formatstr: Subex, a: openarray[string]): string {.noSideEffect, rtl, extern: "nfrmtFormatOpenArray".} = ## The `substitution`:idx: operator performs string substitutions in ## `formatstr` and returns a modified `formatstr`. This is often called @@ -321,13 +328,13 @@ proc `%` *(formatstr: TSubex, a: openarray[string]): string {.noSideEffect, result = newStringOfCap(formatstr.string.len + a.len shl 4) addf(result, formatstr, a) -proc `%` *(formatstr: TSubex, a: string): string {.noSideEffect, +proc `%` *(formatstr: Subex, a: string): string {.noSideEffect, rtl, extern: "nfrmtFormatSingleElem".} = ## This is the same as ``formatstr % [a]``. result = newStringOfCap(formatstr.string.len + a.len) addf(result, formatstr, [a]) -proc format*(formatstr: TSubex, a: varargs[string, `$`]): string {.noSideEffect, +proc format*(formatstr: Subex, a: varargs[string, `$`]): string {.noSideEffect, rtl, extern: "nfrmtFormatVarargs".} = ## The `substitution`:idx: operator performs string substitutions in ## `formatstr` and returns a modified `formatstr`. This is often called diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 20f1d0695..1c1d973ee 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -27,12 +27,13 @@ when defined(windows): var hTemp = GetStdHandle(STD_OUTPUT_HANDLE) if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(), addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0: - osError(osLastError()) + raiseOSError(osLastError()) proc getCursorPos(): tuple [x,y: int] = var c: TCONSOLESCREENBUFFERINFO - if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: osError(osLastError()) - return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y)) + if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: + raiseOSError(osLastError()) + return (int(c.dwCursorPosition.X), int(c.dwCursorPosition.Y)) proc getAttributes(): int16 = var c: TCONSOLESCREENBUFFERINFO @@ -49,9 +50,9 @@ proc setCursorPos*(x, y: int) = ## upper left of the screen. when defined(windows): var c: TCOORD - c.x = int16(x) - c.y = int16(y) - if SetConsoleCursorPosition(conHandle, c) == 0: osError(osLastError()) + c.X = int16(x) + c.Y = int16(y) + if SetConsoleCursorPosition(conHandle, c) == 0: raiseOSError(osLastError()) else: stdout.write("\e[" & $y & ';' & $x & 'f') @@ -61,10 +62,12 @@ proc setCursorXPos*(x: int) = when defined(windows): var scrbuf: TCONSOLESCREENBUFFERINFO var hStdout = conHandle - if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError()) + if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: + raiseOSError(osLastError()) var origin = scrbuf.dwCursorPosition - origin.x = int16(x) - if SetConsoleCursorPosition(conHandle, origin) == 0: osError(osLastError()) + origin.X = int16(x) + if SetConsoleCursorPosition(conHandle, origin) == 0: + raiseOSError(osLastError()) else: stdout.write("\e[" & $x & 'G') @@ -75,10 +78,12 @@ when defined(windows): when defined(windows): var scrbuf: TCONSOLESCREENBUFFERINFO var hStdout = conHandle - if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError()) + if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: + raiseOSError(osLastError()) var origin = scrbuf.dwCursorPosition - origin.y = int16(y) - if SetConsoleCursorPosition(conHandle, origin) == 0: osError(osLastError()) + origin.Y = int16(y) + if SetConsoleCursorPosition(conHandle, origin) == 0: + raiseOSError(osLastError()) else: discard @@ -155,18 +160,20 @@ proc eraseLine* = var scrbuf: TCONSOLESCREENBUFFERINFO var numwrote: DWORD var hStdout = conHandle - if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError()) + if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: + raiseOSError(osLastError()) var origin = scrbuf.dwCursorPosition - origin.x = 0'i16 - if SetConsoleCursorPosition(conHandle, origin) == 0: osError(osLastError()) + origin.X = 0'i16 + if SetConsoleCursorPosition(conHandle, origin) == 0: + raiseOSError(osLastError()) var ht = scrbuf.dwSize.Y - origin.Y var wt = scrbuf.dwSize.X - origin.X if FillConsoleOutputCharacter(hStdout,' ', ht*wt, origin, addr(numwrote)) == 0: - osError(osLastError()) + raiseOSError(osLastError()) if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt, scrbuf.dwCursorPosition, addr(numwrote)) == 0: - osError(osLastError()) + raiseOSError(osLastError()) else: stdout.write("\e[2K") setCursorXPos(0) @@ -178,14 +185,15 @@ proc eraseScreen* = var numwrote: DWORD var origin: TCOORD # is inititalized to 0, 0 var hStdout = conHandle - if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError()) + if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: + raiseOSError(osLastError()) if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y, origin, addr(numwrote)) == 0: - osError(osLastError()) + raiseOSError(osLastError()) if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, scrbuf.dwSize.X * scrbuf.dwSize.Y, origin, addr(numwrote)) == 0: - osError(osLastError()) + raiseOSError(osLastError()) setCursorXPos(0) else: stdout.write("\e[2J") @@ -199,7 +207,7 @@ proc resetAttributes* {.noconv.} = stdout.write("\e[0m") type - TStyle* = enum ## different styles for text output + Style* = enum ## different styles for text output styleBright = 1, ## bright text styleDim, ## dim text styleUnknown, ## unknown @@ -208,13 +216,15 @@ type styleReverse = 7, ## unknown styleHidden ## hidden text +{.deprecated: [TStyle: Style].} + when not defined(windows): var # XXX: These better be thread-local gFG = 0 gBG = 0 -proc setStyle*(style: set[TStyle]) = +proc setStyle*(style: set[Style]) = ## sets the terminal style when defined(windows): var a = 0'i16 @@ -227,7 +237,7 @@ proc setStyle*(style: set[TStyle]) = for s in items(style): stdout.write("\e[" & $ord(s) & 'm') -proc writeStyled*(txt: string, style: set[TStyle] = {styleBright}) = +proc writeStyled*(txt: string, style: set[Style] = {styleBright}) = ## writes the text `txt` in a given `style`. when defined(windows): var old = getAttributes() @@ -244,7 +254,7 @@ proc writeStyled*(txt: string, style: set[TStyle] = {styleBright}) = stdout.write("\e[" & $ord(gBG) & 'm') type - TForegroundColor* = enum ## terminal's foreground colors + ForegroundColor* = enum ## terminal's foreground colors fgBlack = 30, ## black fgRed, ## red fgGreen, ## green @@ -254,7 +264,7 @@ type fgCyan, ## cyan fgWhite ## white - TBackgroundColor* = enum ## terminal's background colors + BackgroundColor* = enum ## terminal's background colors bgBlack = 40, ## black bgRed, ## red bgGreen, ## green @@ -264,13 +274,16 @@ type bgCyan, ## cyan bgWhite ## white -proc setForegroundColor*(fg: TForegroundColor, bright=false) = +{.deprecated: [TForegroundColor: ForegroundColor, + TBackgroundColor: BackgroundColor].} + +proc setForegroundColor*(fg: ForegroundColor, bright=false) = ## sets the terminal's foreground color when defined(windows): var old = getAttributes() and not 0x0007 if bright: old = old or FOREGROUND_INTENSITY - const lookup: array [TForegroundColor, int] = [ + const lookup: array [ForegroundColor, int] = [ 0, (FOREGROUND_RED), (FOREGROUND_GREEN), @@ -285,13 +298,13 @@ proc setForegroundColor*(fg: TForegroundColor, bright=false) = if bright: inc(gFG, 60) stdout.write("\e[" & $gFG & 'm') -proc setBackgroundColor*(bg: TBackgroundColor, bright=false) = +proc setBackgroundColor*(bg: BackgroundColor, bright=false) = ## sets the terminal's background color when defined(windows): var old = getAttributes() and not 0x0070 if bright: old = old or BACKGROUND_INTENSITY - const lookup: array [TBackgroundColor, int] = [ + const lookup: array [BackgroundColor, int] = [ 0, (BACKGROUND_RED), (BACKGROUND_GREEN), @@ -306,22 +319,22 @@ proc setBackgroundColor*(bg: TBackgroundColor, bright=false) = if bright: inc(gBG, 60) stdout.write("\e[" & $gBG & 'm') -proc isatty*(f: TFile): bool = +proc isatty*(f: File): bool = ## returns true if `f` is associated with a terminal device. when defined(posix): - proc isatty(fildes: TFileHandle): cint {. + proc isatty(fildes: FileHandle): cint {. importc: "isatty", header: "<unistd.h>".} else: - proc isatty(fildes: TFileHandle): cint {. + proc isatty(fildes: FileHandle): cint {. importc: "_isatty", header: "<io.h>".} - result = isatty(fileHandle(f)) != 0'i32 + result = isatty(getFileHandle(f)) != 0'i32 -proc styledEchoProcessArg(s: string) = write stdout, s -proc styledEchoProcessArg(style: TStyle) = setStyle({style}) -proc styledEchoProcessArg(style: set[TStyle]) = setStyle style -proc styledEchoProcessArg(color: TForegroundColor) = setForegroundColor color -proc styledEchoProcessArg(color: TBackgroundColor) = setBackgroundColor color +proc styledEchoProcessArg(s: string) = write stdout, s +proc styledEchoProcessArg(style: Style) = setStyle({style}) +proc styledEchoProcessArg(style: set[Style]) = setStyle style +proc styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color +proc styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color macro styledEcho*(m: varargs[expr]): stmt = ## to be documented. diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 8b33d2c73..1cabd381b 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -21,9 +21,9 @@ import include "system/inclrtl" type - TMonth* = enum ## represents a month + Month* = enum ## represents a month mJan, mFeb, mMar, mApr, mMay, mJun, mJul, mAug, mSep, mOct, mNov, mDec - TWeekDay* = enum ## represents a weekday + WeekDay* = enum ## represents a weekday dMon, dTue, dWed, dThu, dFri, dSat, dSun var @@ -32,12 +32,12 @@ var when defined(posix) and not defined(JS): type - TTimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int - TTime* = distinct TTimeImpl ## distinct type that represents a time - ## measured as number of seconds since the epoch + TimeImpl {.importc: "time_t", header: "<sys/time.h>".} = int + Time* = distinct TimeImpl ## distinct type that represents a time + ## measured as number of seconds since the epoch - Ttimeval {.importc: "struct timeval", header: "<sys/select.h>", - final, pure.} = object ## struct timeval + Timeval {.importc: "struct timeval", + header: "<sys/select.h>".} = object ## struct timeval tv_sec: int ## Seconds. tv_usec: int ## Microseconds. @@ -45,7 +45,7 @@ when defined(posix) and not defined(JS): # Ok, we could, but I don't want circular dependencies. # And gettimeofday() is not defined in the posix module anyway. Sigh. - proc posix_gettimeofday(tp: var Ttimeval, unused: pointer = nil) {. + proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {. importc: "gettimeofday", header: "<sys/time.h>".} elif defined(windows): @@ -53,16 +53,16 @@ elif defined(windows): when defined(vcc): # newest version of Visual C++ defines time_t to be of 64 bits - type TTimeImpl {.importc: "time_t", header: "<time.h>".} = int64 + type TimeImpl {.importc: "time_t", header: "<time.h>".} = int64 else: - type TTimeImpl {.importc: "time_t", header: "<time.h>".} = int32 + type TimeImpl {.importc: "time_t", header: "<time.h>".} = int32 type - TTime* = distinct TTimeImpl + Time* = distinct TimeImpl elif defined(JS): type - TTime* {.final, importc.} = object + Time* {.importc.} = object getDay: proc (): int {.tags: [], raises: [], gcsafe.} getFullYear: proc (): int {.tags: [], raises: [], gcsafe.} getHours: proc (): int {.tags: [], raises: [], gcsafe.} @@ -82,7 +82,7 @@ elif defined(JS): getUTCSeconds: proc (): int {.tags: [], raises: [], gcsafe.} getUTCDay: proc (): int {.tags: [], raises: [], gcsafe.} getYear: proc (): int {.tags: [], raises: [], gcsafe.} - parse: proc (s: cstring): TTime {.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.} @@ -103,7 +103,7 @@ elif defined(JS): toLocaleString: proc (): cstring {.tags: [], raises: [], gcsafe.} type - TTimeInfo* = object of TObject ## represents a time in different parts + TimeInfo* = object of RootObj ## represents a time in different parts second*: range[0..61] ## The number of seconds after the minute, ## normally in the range 0 to 59, but can ## be up to 61 to allow for leap seconds. @@ -112,9 +112,9 @@ type hour*: range[0..23] ## The number of hours past midnight, ## in the range 0 to 23. monthday*: range[1..31] ## The day of the month, in the range 1 to 31. - month*: TMonth ## The current month. + month*: Month ## The current month. year*: range[-10_000..10_000] ## The current year. - weekday*: TWeekDay ## The current day of the week. + weekday*: WeekDay ## The current day of the week. yearday*: range[0..365] ## The number of days since January 1, ## in the range 0 to 365. ## Always 0 if the target is JS. @@ -127,7 +127,7 @@ type ## I make some assumptions about the data in here. Either ## everything should be positive or everything negative. Zero is ## fine too. Mixed signs will lead to unexpected results. - TTimeInterval* {.pure.} = object ## a time interval + TimeInterval* = object ## a time interval miliseconds*: int ## The number of miliseconds seconds*: int ## The number of seconds minutes*: int ## The number of minutes @@ -136,75 +136,78 @@ type months*: int ## The number of months years*: int ## The number of years -proc getTime*(): TTime {.tags: [FTime], gcsafe.} +{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time, + TTimeInterval: TimeInterval, TTimeInfo: TimeInfo].} + +proc getTime*(): Time {.tags: [TimeEffect], gcsafe.} ## 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: TTime): TTimeInfo {.tags: [FTime], raises: [], gcsafe.} +proc getLocalTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.} ## converts the calendar time `t` to broken-time representation, ## expressed relative to the user's specified time zone. -proc getGMTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [], gcsafe.} +proc getGMTime*(t: Time): TimeInfo {.tags: [TimeEffect], raises: [], gcsafe.} ## converts the calendar time `t` to broken-down time representation, ## expressed in Coordinated Universal Time (UTC). -proc timeInfoToTime*(timeInfo: TTimeInfo): TTime {.tags: [], gcsafe.} +proc timeInfoToTime*(timeInfo: TimeInfo): Time {.tags: [], gcsafe.} ## 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): TTime {.tags: [], raises: [], gcsafe.} +proc fromSeconds*(since1970: float): Time {.tags: [], raises: [], gcsafe.} ## Takes a float which contains the number of seconds since the unix epoch and ## returns a time object. -proc fromSeconds*(since1970: int64): TTime {.tags: [], raises: [], gcsafe.} = +proc fromSeconds*(since1970: int64): Time {.tags: [], raises: [], gcsafe.} = ## Takes an int which contains the number of seconds since the unix epoch and ## returns a time object. fromSeconds(float(since1970)) -proc toSeconds*(time: TTime): float {.tags: [], raises: [], gcsafe.} +proc toSeconds*(time: Time): float {.tags: [], raises: [], gcsafe.} ## Returns the time in seconds since the unix epoch. -proc `$` *(timeInfo: TTimeInfo): string {.tags: [], raises: [], gcsafe.} - ## converts a `TTimeInfo` object to a string representation. -proc `$` *(time: TTime): string {.tags: [], raises: [], gcsafe.} +proc `$` *(timeInfo: TimeInfo): string {.tags: [], raises: [], gcsafe.} + ## converts a `TimeInfo` object to a string representation. +proc `$` *(time: Time): string {.tags: [], raises: [], gcsafe.} ## converts a calendar time to a string representation. -proc `-`*(a, b: TTime): int64 {. +proc `-`*(a, b: Time): int64 {. rtl, extern: "ntDiffTime", tags: [], raises: [].} ## computes the difference of two calendar times. Result is in seconds. -proc `<`*(a, b: TTime): bool {. +proc `<`*(a, b: Time): bool {. rtl, extern: "ntLtTime", tags: [], raises: [].} = ## returns true iff ``a < b``, that is iff a happened before b. result = a - b < 0 -proc `<=` * (a, b: TTime): bool {. +proc `<=` * (a, b: Time): bool {. rtl, extern: "ntLeTime", tags: [], raises: [].}= ## returns true iff ``a <= b``. result = a - b <= 0 -proc `==`*(a, b: TTime): bool {. +proc `==`*(a, b: Time): bool {. rtl, extern: "ntEqTime", tags: [], raises: [].} = ## returns true if ``a == b``, that is if both times represent the same value result = a - b == 0 when not defined(JS): - proc getTzname*(): tuple[nonDST, DST: string] {.tags: [FTime], raises: [], + proc getTzname*(): tuple[nonDST, DST: string] {.tags: [TimeEffect], raises: [], gcsafe.} ## 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: [FTime], raises: [], gcsafe.} +proc getTimezone*(): int {.tags: [TimeEffect], raises: [], gcsafe.} ## returns the offset of the local (non-DST) timezone in seconds west of UTC. -proc getStartMilsecs*(): int {.deprecated, tags: [FTime], gcsafe.} +proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], gcsafe.} ## get the miliseconds from the start of the program. **Deprecated since ## version 0.8.10.** Use ``epochTime`` or ``cpuTime`` instead. proc initInterval*(miliseconds, seconds, minutes, hours, days, months, - years: int = 0): TTimeInterval = - ## creates a new ``TTimeInterval``. + years: int = 0): TimeInterval = + ## creates a new ``TimeInterval``. result.miliseconds = miliseconds result.seconds = seconds result.minutes = minutes @@ -225,7 +228,7 @@ proc isLeapYear*(year: int): bool = else: return false -proc getDaysInMonth*(month: TMonth, year: int): int = +proc getDaysInMonth*(month: Month, year: int): int = ## gets the amount of days in a ``month`` of a ``year`` # http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month @@ -234,7 +237,7 @@ proc getDaysInMonth*(month: TMonth, year: int): int = of mApr, mJun, mSep, mNov: result = 30 else: result = 31 -proc toSeconds(a: TTimeInfo, interval: TTimeInterval): float = +proc toSeconds(a: TimeInfo, interval: TimeInterval): float = ## Calculates how many seconds the interval is worth by adding up ## all the fields @@ -257,7 +260,7 @@ proc toSeconds(a: TTimeInfo, interval: TTimeInterval): float = result += float(newinterv.seconds) result += newinterv.miliseconds / 1000 -proc `+`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo = +proc `+`*(a: TimeInfo, interval: TimeInterval): TimeInfo = ## adds ``interval`` time. ## ## **Note:** This has been only briefly tested and it may not be @@ -269,7 +272,7 @@ proc `+`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo = else: result = getLocalTime(fromSeconds(t + secs)) -proc `-`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo = +proc `-`*(a: TimeInfo, interval: TimeInterval): TimeInfo = ## subtracts ``interval`` time. ## ## **Note:** This has been only briefly tested, it is inaccurate especially @@ -282,12 +285,12 @@ proc `-`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo = result = getLocalTime(fromSeconds(t - secs)) when not defined(JS): - proc epochTime*(): float {.rtl, extern: "nt$1", tags: [FTime].} + proc epochTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} ## gets time after the UNIX epoch (1970) in seconds. It is a float ## because sub-second resolution is likely to be supported (depending ## on the hardware/OS). - proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [FTime].} + proc cpuTime*(): float {.rtl, extern: "nt$1", tags: [TimeEffect].} ## gets time spent that the CPU spent to run the current process in ## seconds. This may be more useful for benchmarking than ``epochTime``. ## However, it may measure the real time instead (depending on the OS). @@ -295,7 +298,7 @@ when not defined(JS): ## To generate useful timing values, take the difference between ## the results of two ``cpuTime`` calls: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var t0 = cpuTime() ## doWork() ## echo "CPU time [s] ", cpuTime() - t0 @@ -314,42 +317,40 @@ when not defined(JS): yearday {.importc: "tm_yday".}, isdst {.importc: "tm_isdst".}: cint - PTimeInfo = ptr StructTM - PTime = ptr TTime - - TClock {.importc: "clock_t".} = distinct int + TimeInfoPtr = ptr StructTM + Clock {.importc: "clock_t".} = distinct int - proc localtime(timer: PTime): PTimeInfo {. + proc localtime(timer: ptr Time): TimeInfoPtr {. importc: "localtime", header: "<time.h>", tags: [].} - proc gmtime(timer: PTime): PTimeInfo {. + proc gmtime(timer: ptr Time): TimeInfoPtr {. importc: "gmtime", header: "<time.h>", tags: [].} - proc timec(timer: PTime): TTime {. + proc timec(timer: ptr Time): Time {. importc: "time", header: "<time.h>", tags: [].} - proc mktime(t: StructTM): TTime {. + proc mktime(t: StructTM): Time {. importc: "mktime", header: "<time.h>", tags: [].} proc asctime(tblock: StructTM): cstring {. importc: "asctime", header: "<time.h>", tags: [].} - proc ctime(time: PTime): cstring {. + proc ctime(time: ptr Time): cstring {. importc: "ctime", header: "<time.h>", tags: [].} # strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {. # importc: "strftime", header: "<time.h>".} - proc clock(): TClock {.importc: "clock", header: "<time.h>", tags: [FTime].} - proc difftime(a, b: TTime): float {.importc: "difftime", header: "<time.h>", + proc getClock(): Clock {.importc: "clock", header: "<time.h>", tags: [TimeEffect].} + proc difftime(a, b: Time): float {.importc: "difftime", header: "<time.h>", tags: [].} var clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int # our own procs on top of that: - proc tmToTimeInfo(tm: StructTM, local: bool): TTimeInfo = + proc tmToTimeInfo(tm: StructTM, local: bool): TimeInfo = const - weekDays: array [0..6, TWeekDay] = [ + weekDays: array [0..6, WeekDay] = [ dSun, dMon, dTue, dWed, dThu, dFri, dSat] - TTimeInfo(second: int(tm.second), + TimeInfo(second: int(tm.second), minute: int(tm.minute), hour: int(tm.hour), monthday: int(tm.monthday), - month: TMonth(tm.month), + month: Month(tm.month), year: tm.year + 1900'i32, weekday: weekDays[int(tm.weekday)], yearday: int(tm.yearday), @@ -364,9 +365,9 @@ when not defined(JS): timezone: if local: getTimezone() else: 0 ) - proc timeInfoToTM(t: TTimeInfo): StructTM = + proc timeInfoToTM(t: TimeInfo): StructTM = const - weekDays: array [TWeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8] + weekDays: array [WeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8] result.second = t.second result.minute = t.minute result.hour = t.hour @@ -378,36 +379,36 @@ when not defined(JS): result.isdst = if t.isDST: 1 else: 0 when not defined(useNimRtl): - proc `-` (a, b: TTime): int64 = + proc `-` (a, b: Time): int64 = return toBiggestInt(difftime(a, b)) proc getStartMilsecs(): int = - #echo "clocks per sec: ", clocksPerSec, "clock: ", int(clock()) - #return clock() div (clocksPerSec div 1000) + #echo "clocks per sec: ", clocksPerSec, "clock: ", int(getClock()) + #return getClock() div (clocksPerSec div 1000) when defined(macosx): - result = toInt(toFloat(int(clock())) / (toFloat(clocksPerSec) / 1000.0)) + result = toInt(toFloat(int(getClock())) / (toFloat(clocksPerSec) / 1000.0)) else: - result = int(clock()) div (clocksPerSec div 1000) + result = int(getClock()) div (clocksPerSec div 1000) when false: - var a: Ttimeval + var a: Timeval posix_gettimeofday(a) result = a.tv_sec * 1000'i64 + a.tv_usec div 1000'i64 #echo "result: ", result - proc getTime(): TTime = return timec(nil) - proc getLocalTime(t: TTime): TTimeInfo = + proc getTime(): Time = return timec(nil) + proc getLocalTime(t: Time): TimeInfo = var a = t result = tmToTimeInfo(localtime(addr(a))[], true) # copying is needed anyway to provide reentrancity; thus # the conversion is not expensive - proc getGMTime(t: TTime): TTimeInfo = + proc getGMTime(t: Time): TimeInfo = var a = t result = tmToTimeInfo(gmtime(addr(a))[], false) # copying is needed anyway to provide reentrancity; thus # the conversion is not expensive - proc timeInfoToTime(timeInfo: TTimeInfo): TTime = + proc timeInfoToTime(timeInfo: TimeInfo): Time = var cTimeInfo = timeInfo # for C++ we have to make a copy, # because the header of mktime is broken in my version of libc return mktime(timeInfoToTM(cTimeInfo)) @@ -419,12 +420,12 @@ when not defined(JS): add(result, p[i]) inc(i) - proc `$`(timeInfo: TTimeInfo): string = + proc `$`(timeInfo: TimeInfo): string = # BUGFIX: asctime returns a newline at the end! var p = asctime(timeInfoToTM(timeInfo)) result = toStringTillNL(p) - proc `$`(time: TTime): string = + proc `$`(time: Time): string = # BUGFIX: ctime returns a newline at the end! var a = time return toStringTillNL(ctime(addr(a))) @@ -433,13 +434,13 @@ when not defined(JS): epochDiff = 116444736000000000'i64 rateDiff = 10000000'i64 # 100 nsecs - proc unixTimeToWinTime*(t: TTime): int64 = - ## converts a UNIX `TTime` (``time_t``) to a Windows file time + proc unixTimeToWinTime*(t: Time): int64 = + ## converts a UNIX `Time` (``time_t``) to a Windows file time result = int64(t) * rateDiff + epochDiff - proc winTimeToUnixTime*(t: int64): TTime = - ## converts a Windows time to a UNIX `TTime` (``time_t``) - result = TTime((t - epochDiff) div rateDiff) + proc winTimeToUnixTime*(t: int64): Time = + ## converts a Windows time to a UNIX `Time` (``time_t``) + result = Time((t - epochDiff) div rateDiff) proc getTzname(): tuple[nonDST, DST: string] = return ($tzname[0], $tzname[1]) @@ -447,18 +448,18 @@ when not defined(JS): proc getTimezone(): int = return timezone - proc fromSeconds(since1970: float): TTime = TTime(since1970) + proc fromSeconds(since1970: float): Time = Time(since1970) - proc toSeconds(time: TTime): float = float(time) + proc toSeconds(time: Time): float = float(time) when not defined(useNimRtl): proc epochTime(): float = when defined(posix): - var a: Ttimeval + var a: Timeval posix_gettimeofday(a) result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001 elif defined(windows): - var f: winlean.TFiletime + var f: winlean.TFILETIME getSystemTimeAsFileTime(f) var i64 = rdFileTime(f) - epochDiff var secs = i64 div rateDiff @@ -468,15 +469,15 @@ when not defined(JS): {.error: "unknown OS".} proc cpuTime(): float = - result = toFloat(int(clock())) / toFloat(clocksPerSec) + result = toFloat(int(getClock())) / toFloat(clocksPerSec) elif defined(JS): - proc newDate(): TTime {.importc: "new Date".} - proc internGetTime(): TTime {.importc: "new Date", tags: [].} + proc newDate(): Time {.importc: "new Date".} + proc internGetTime(): Time {.importc: "new Date", tags: [].} - proc newDate(value: float): TTime {.importc: "new Date".} - proc newDate(value: string): TTime {.importc: "new Date".} - proc getTime(): TTime = + proc newDate(value: float): Time {.importc: "new Date".} + proc newDate(value: string): Time {.importc: "new Date".} + proc getTime(): Time = # Warning: This is something different in JS. return newDate() @@ -484,7 +485,7 @@ elif defined(JS): weekDays: array [0..6, TWeekDay] = [ dSun, dMon, dTue, dWed, dThu, dFri, dSat] - proc getLocalTime(t: TTime): TTimeInfo = + proc getLocalTime(t: Time): TimeInfo = result.second = t.getSeconds() result.minute = t.getMinutes() result.hour = t.getHours() @@ -494,7 +495,7 @@ elif defined(JS): result.weekday = weekDays[t.getDay()] result.yearday = 0 - proc getGMTime(t: TTime): TTimeInfo = + proc getGMTime(t: Time): TimeInfo = result.second = t.getUTCSeconds() result.minute = t.getUTCMinutes() result.hour = t.getUTCHours() @@ -504,7 +505,7 @@ elif defined(JS): result.weekday = weekDays[t.getUTCDay()] result.yearday = 0 - proc timeInfoToTime*(timeInfo: TTimeInfo): TTime = + proc timeInfoToTime*(timeInfo: TimeInfo): Time = result = internGetTime() result.setSeconds(timeInfo.second) result.setMinutes(timeInfo.minute) @@ -513,10 +514,10 @@ elif defined(JS): result.setFullYear(timeInfo.year) result.setDate(timeInfo.monthday) - proc `$`(timeInfo: TTimeInfo): string = return $(timeInfoToTime(timeInfo)) - proc `$`(time: TTime): string = return $time.toLocaleString() + proc `$`(timeInfo: TimeInfo): string = return $(timeInfoToTime(timeInfo)) + proc `$`(time: Time): string = return $time.toLocaleString() - proc `-` (a, b: TTime): int64 = + proc `-` (a, b: Time): int64 = return a.getTime() - b.getTime() var @@ -526,40 +527,40 @@ elif defined(JS): ## get the miliseconds from the start of the program return int(getTime() - startMilsecs) - proc valueOf(time: TTime): float {.importcpp: "getTime", tags:[]} + proc valueOf(time: Time): float {.importcpp: "getTime", tags:[]} - proc fromSeconds(since1970: float): TTime = result = newDate(since1970) + proc fromSeconds(since1970: float): Time = result = newDate(since1970) - proc toSeconds(time: TTime): float = result = time.valueOf() / 1000 + proc toSeconds(time: Time): float = result = time.valueOf() / 1000 proc getTimezone(): int = result = newDate().getTimezoneOffset() -proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [FTime].} = +proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = ## gets the current date as a string of the format ``YYYY-MM-DD``. var ti = getLocalTime(getTime()) result = $ti.year & '-' & intToStr(ord(ti.month)+1, 2) & '-' & intToStr(ti.monthday, 2) -proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [FTime].} = +proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = ## gets the current clock time as a string of the format ``HH:MM:SS``. var ti = getLocalTime(getTime()) result = intToStr(ti.hour, 2) & ':' & intToStr(ti.minute, 2) & ':' & intToStr(ti.second, 2) -proc `$`*(day: TWeekDay): string = - ## stingify operator for ``TWeekDay``. - const lookup: array[TWeekDay, string] = ["Monday", "Tuesday", "Wednesday", +proc `$`*(day: WeekDay): string = + ## stingify operator for ``WeekDay``. + const lookup: array[WeekDay, string] = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] return lookup[day] -proc `$`*(m: TMonth): string = +proc `$`*(m: Month): string = ## stingify operator for ``TMonth``. - const lookup: array[TMonth, string] = ["January", "February", "March", + const lookup: array[Month, string] = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] return lookup[m] -proc format_token(info: TTimeInfo, token: string, buf: var string) = +proc formatToken(info: TimeInfo, token: string, buf: var string) = ## Helper of the format proc to parse individual tokens. ## ## Pass the found token in the user input string, and the buffer where the @@ -669,10 +670,10 @@ proc format_token(info: TTimeInfo, token: string, buf: var string) = of "": discard else: - raise newException(EInvalidValue, "Invalid format string: " & token) + raise newException(ValueError, "Invalid format string: " & token) -proc format*(info: TTimeInfo, f: string): string = +proc format*(info: TimeInfo, f: string): string = ## This function formats `info` as specified by `f`. The following format ## specifiers are available: ## @@ -718,7 +719,7 @@ proc format*(info: TTimeInfo, f: string): string = while true: case f[i] of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',': - format_token(info, currentF, result) + formatToken(info, currentF, result) currentF = "" if f[i] == '\0': break @@ -735,7 +736,7 @@ proc format*(info: TTimeInfo, f: string): string = if currentF.len < 1 or currentF[high(currentF)] == f[i]: currentF.add(f[i]) else: - format_token(info, currentF, result) + formatToken(info, currentF, result) dec(i) # Move position back to re-process the character separately. currentF = "" @@ -764,7 +765,7 @@ when isMainModule: " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") == "27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 0 00 00:00 UTC" - when not defined(JS) and sizeof(TTime) == 8: + when not defined(JS) and sizeof(Time) == 8: var t3 = getGMTime(fromSeconds(889067643645)) # Fri 7 Jun 19:20:45 BST 30143 assert t3.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" & " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") == diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 3203ee699..2c3d872df 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Nimrod Contributors +# Nim's Runtime Library +# (c) Copyright 2012 Nim Contributors # # See the file "copying.txt", included in this # distribution, for details about the copyright. diff --git a/lib/pure/unicode.nim b/lib/pure/unicode.nim index 6e73eea3f..c2eb001f6 100644 --- a/lib/pure/unicode.nim +++ b/lib/pure/unicode.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -14,13 +14,15 @@ include "system/inclrtl" type - IRune = int # underlying type of TRune - TRune* = distinct IRune ## type that can hold any Unicode character - TRune16* = distinct int16 ## 16 bit Unicode character + RuneImpl = int # underlying type of Rune + Rune* = distinct RuneImpl ## type that can hold any Unicode character + Rune16* = distinct int16 ## 16 bit Unicode character + +{.deprecated: [TRune: Rune, TRune16: Rune16].} -proc `<=%`*(a, b: TRune): bool = return int(a) <=% int(b) -proc `<%`*(a, b: TRune): bool = return int(a) <% int(b) -proc `==`*(a, b: TRune): bool = return int(a) == int(b) +proc `<=%`*(a, b: Rune): bool = return int(a) <=% int(b) +proc `<%`*(a, b: Rune): bool = return int(a) <% int(b) +proc `==`*(a, b: Rune): bool = return int(a) == int(b) template ones(n: expr): expr = ((1 shl n)-1) @@ -52,17 +54,17 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) = ## `i` is incremented by the number of bytes that have been processed. bind ones if ord(s[i]) <=% 127: - result = TRune(ord(s[i])) + result = Rune(ord(s[i])) when doInc: inc(i) elif ord(s[i]) shr 5 == 0b110: # assert(ord(s[i+1]) shr 6 == 0b10) - result = TRune((ord(s[i]) and (ones(5))) shl 6 or - (ord(s[i+1]) and ones(6))) + result = Rune((ord(s[i]) and (ones(5))) shl 6 or + (ord(s[i+1]) and ones(6))) when doInc: inc(i, 2) elif ord(s[i]) shr 4 == 0b1110: # assert(ord(s[i+1]) shr 6 == 0b10) # assert(ord(s[i+2]) shr 6 == 0b10) - result = TRune((ord(s[i]) and ones(4)) shl 12 or + result = Rune((ord(s[i]) and ones(4)) shl 12 or (ord(s[i+1]) and ones(6)) shl 6 or (ord(s[i+2]) and ones(6))) when doInc: inc(i, 3) @@ -70,7 +72,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) = # assert(ord(s[i+1]) shr 6 == 0b10) # assert(ord(s[i+2]) shr 6 == 0b10) # assert(ord(s[i+3]) shr 6 == 0b10) - result = TRune((ord(s[i]) and ones(3)) shl 18 or + result = Rune((ord(s[i]) and ones(3)) shl 18 or (ord(s[i+1]) and ones(6)) shl 12 or (ord(s[i+2]) and ones(6)) shl 6 or (ord(s[i+3]) and ones(6))) @@ -80,7 +82,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) = # assert(ord(s[i+2]) shr 6 == 0b10) # assert(ord(s[i+3]) shr 6 == 0b10) # assert(ord(s[i+4]) shr 6 == 0b10) - result = TRune((ord(s[i]) and ones(2)) shl 24 or + result = Rune((ord(s[i]) and ones(2)) shl 24 or (ord(s[i+1]) and ones(6)) shl 18 or (ord(s[i+2]) and ones(6)) shl 12 or (ord(s[i+3]) and ones(6)) shl 6 or @@ -92,7 +94,7 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) = # assert(ord(s[i+3]) shr 6 == 0b10) # assert(ord(s[i+4]) shr 6 == 0b10) # assert(ord(s[i+5]) shr 6 == 0b10) - result = TRune((ord(s[i]) and ones(1)) shl 30 or + result = Rune((ord(s[i]) and ones(1)) shl 30 or (ord(s[i+1]) and ones(6)) shl 24 or (ord(s[i+2]) and ones(6)) shl 18 or (ord(s[i+3]) and ones(6)) shl 12 or @@ -100,16 +102,16 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) = (ord(s[i+5]) and ones(6))) when doInc: inc(i, 6) else: - result = TRune(ord(s[i])) + result = Rune(ord(s[i])) when doInc: inc(i) -proc runeAt*(s: string, i: int): TRune = +proc runeAt*(s: string, i: int): Rune = ## returns the unicode character in `s` at byte index `i` fastRuneAt(s, i, result, false) -proc toUTF8*(c: TRune): string {.rtl, extern: "nuc$1".} = +proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} = ## converts a rune into its UTF8 representation - var i = IRune(c) + var i = RuneImpl(c) if i <=% 127: result = newString(1) result[0] = chr(i) @@ -132,11 +134,11 @@ proc toUTF8*(c: TRune): string {.rtl, extern: "nuc$1".} = result = newString(1) result[0] = chr(i) -proc `$`*(rune: TRune): string = +proc `$`*(rune: Rune): string = ## converts a rune to a string rune.toUTF8 -proc `$`*(runes: seq[TRune]): string = +proc `$`*(runes: seq[Rune]): string = ## converts a sequence of runes to a string result = "" for rune in runes: result.add(rune.toUTF8) @@ -1100,7 +1102,7 @@ const 0x01f1, 501, # 0x01f3, 499] # -proc binarySearch(c: IRune, tab: openArray[IRune], len, stride: int): int = +proc binarySearch(c: RuneImpl, tab: openArray[RuneImpl], len, stride: int): int = var n = len var t = 0 while n > 1: @@ -1115,41 +1117,41 @@ proc binarySearch(c: IRune, tab: openArray[IRune], len, stride: int): int = return t return -1 -proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} = +proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = ## Converts `c` into lower case. This works for any Unicode character. ## If possible, prefer `toLower` over `toUpper`. - var c = IRune(c) + var c = RuneImpl(c) var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3) if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]: - return TRune(c + tolowerRanges[p+2] - 500) + return Rune(c + tolowerRanges[p+2] - 500) p = binarySearch(c, tolowerSinglets, len(tolowerSinglets) div 2, 2) if p >= 0 and c == tolowerSinglets[p]: - return TRune(c + tolowerSinglets[p+1] - 500) - return TRune(c) + return Rune(c + tolowerSinglets[p+1] - 500) + return Rune(c) -proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} = +proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = ## Converts `c` into upper case. This works for any Unicode character. ## If possible, prefer `toLower` over `toUpper`. - var c = IRune(c) + var c = RuneImpl(c) var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3) if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]: - return TRune(c + toupperRanges[p+2] - 500) + return Rune(c + toupperRanges[p+2] - 500) p = binarySearch(c, toupperSinglets, len(toupperSinglets) div 2, 2) if p >= 0 and c == toupperSinglets[p]: - return TRune(c + toupperSinglets[p+1] - 500) - return TRune(c) + return Rune(c + toupperSinglets[p+1] - 500) + return Rune(c) -proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} = - var c = IRune(c) +proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = + var c = RuneImpl(c) var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2) if p >= 0 and c == toTitleSinglets[p]: - return TRune(c + toTitleSinglets[p+1] - 500) - return TRune(c) + return Rune(c + toTitleSinglets[p+1] - 500) + return Rune(c) -proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## returns true iff `c` is a lower case Unicode character ## If possible, prefer `isLower` over `isUpper`. - var c = IRune(c) + var c = RuneImpl(c) # Note: toUpperRanges is correct here! var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3) if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]: @@ -1158,10 +1160,10 @@ proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = if p >= 0 and c == toupperSinglets[p]: return true -proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## returns true iff `c` is a upper case Unicode character ## If possible, prefer `isLower` over `isUpper`. - var c = IRune(c) + var c = RuneImpl(c) # Note: toLowerRanges is correct here! var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3) if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]: @@ -1170,11 +1172,11 @@ proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = if p >= 0 and c == tolowerSinglets[p]: return true -proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## returns true iff `c` is an *alpha* Unicode character (i.e. a letter) if isUpper(c) or isLower(c): return true - var c = IRune(c) + var c = RuneImpl(c) var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2) if p >= 0 and c >= alphaRanges[p] and c <= alphaRanges[p+1]: return true @@ -1182,21 +1184,21 @@ proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = if p >= 0 and c == alphaSinglets[p]: return true -proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = return isUpper(c) and isLower(c) -proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} = +proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## returns true iff `c` is a Unicode whitespace character - var c = IRune(c) + var c = RuneImpl(c) var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2) if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]: return true -iterator runes*(s: string): TRune = +iterator runes*(s: string): Rune = ## iterates over any unicode character of the string `s`. var i = 0 - result: TRune + result: Rune while i < len(s): fastRuneAt(s, i, result, true) yield result @@ -1209,12 +1211,12 @@ proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} = ## | > 0 iff a > b var i = 0 var j = 0 - var ar, br: TRune + var ar, br: Rune while i < a.len and j < b.len: # slow path: fastRuneAt(a, i, ar) fastRuneAt(b, j, br) - result = IRune(toLower(ar)) - IRune(toLower(br)) + result = RuneImpl(toLower(ar)) - RuneImpl(toLower(br)) if result != 0: return result = a.len - b.len diff --git a/lib/pure/unidecode/unidecode.nim b/lib/pure/unidecode/unidecode.nim index 1d36d11b5..798eef5d0 100644 --- a/lib/pure/unidecode/unidecode.nim +++ b/lib/pure/unidecode/unidecode.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -55,7 +55,7 @@ proc unidecode*(s: string): string = ## ## Example: ## - ## ..code-block:: nimrod + ## ..code-block:: nim ## ## unidecode("\x53\x17\x4E\xB0") ## diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 7cc95f0ad..fa2e30ef4 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2012 Nimrod Contributors +# Nim's Runtime Library +# (c) Copyright 2012 Nim Contributors # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -26,19 +26,22 @@ when not defined(ECMAScript): import terminal type - TTestStatus* = enum OK, FAILED - TOutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE + TestStatus* = enum OK, FAILED + OutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE + +{.deprecated: [TTestStatus: TestStatus, TOutputLevel: OutputLevel]} var - # XXX: These better be thread-local - AbortOnError*: bool - OutputLevel*: TOutputLevel - ColorOutput*: bool + abortOnError* {.threadvar.}: bool + outputLevel* {.threadvar.}: OutputLevel + colorOutput* {.threadvar.}: bool - checkpoints: seq[string] = @[] + checkpoints {.threadvar.}: seq[string] + +checkpoints = @[] -template TestSetupIMPL*: stmt {.immediate, dirty.} = discard -template TestTeardownIMPL*: stmt {.immediate, dirty.} = discard +template testSetupIMPL*: stmt {.immediate, dirty.} = discard +template testTeardownIMPL*: stmt {.immediate, dirty.} = discard proc shouldRun(testName: string): bool = result = true @@ -46,21 +49,21 @@ proc shouldRun(testName: string): bool = template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} = block: template setup*(setupBody: stmt): stmt {.immediate, dirty.} = - template TestSetupIMPL: stmt {.immediate, dirty.} = setupBody + template testSetupIMPL: stmt {.immediate, dirty.} = setupBody template teardown*(teardownBody: stmt): stmt {.immediate, dirty.} = - template TestTeardownIMPL: stmt {.immediate, dirty.} = teardownBody + template testTeardownIMPL: stmt {.immediate, dirty.} = teardownBody body -proc testDone(name: string, s: TTestStatus) = +proc testDone(name: string, s: TestStatus) = if s == FAILED: - program_result += 1 + programResult += 1 - if OutputLevel != PRINT_NONE and (OutputLevel == PRINT_ALL or s == FAILED): + if outputLevel != PRINT_NONE and (outputLevel == PRINT_ALL or s == FAILED): template rawPrint() = echo("[", $s, "] ", name, "\n") when not defined(ECMAScript): - if ColorOutput and not defined(ECMAScript): + if colorOutput and not defined(ECMAScript): var color = (if s == OK: fgGreen else: fgRed) styledEcho styleBright, color, "[", $s, "] ", fgWhite, name, "\n" else: @@ -73,10 +76,10 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} = if shouldRun(name): checkpoints = @[] - var TestStatusIMPL {.inject.} = OK + var testStatusIMPL {.inject.} = OK try: - TestSetupIMPL() + testSetupIMPL() body except: @@ -84,8 +87,8 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} = fail() finally: - TestTeardownIMPL() - testDone name, TestStatusIMPL + testTeardownIMPL() + testDone name, testStatusIMPL proc checkpoint*(msg: string) = checkpoints.add(msg) @@ -97,12 +100,12 @@ template fail* = echo msg when not defined(ECMAScript): - if AbortOnError: quit(1) + if abortOnError: quit(1) - when declared(TestStatusIMPL): - TestStatusIMPL = FAILED + when declared(testStatusIMPL): + testStatusIMPL = FAILED else: - program_result += 1 + programResult += 1 checkpoints = @[] @@ -192,15 +195,15 @@ when declared(stdout): ## Reading settings var envOutLvl = os.getEnv("NIMTEST_OUTPUT_LVL").string - AbortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR") - ColorOutput = not existsEnv("NIMTEST_NO_COLOR") + abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR") + colorOutput = not existsEnv("NIMTEST_NO_COLOR") else: var envOutLvl = "" # TODO - ColorOutput = false + colorOutput = false if envOutLvl.len > 0: - for opt in countup(low(TOutputLevel), high(TOutputLevel)): + for opt in countup(low(OutputLevel), high(OutputLevel)): if $opt == envOutLvl: - OutputLevel = opt + outputLevel = opt break diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim index 7ec823033..2c65d071e 100644 --- a/lib/pure/uri.nim +++ b/lib/pure/uri.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Dominik Picheta # # See the file "copying.txt", included in this @@ -11,12 +11,14 @@ import strutils, parseutils type - TUrl* = distinct string + Url* = distinct string - TUri* = object + Uri* = object scheme*, username*, password*: string hostname*, port*, path*, query*, anchor*: string +{.deprecated: [TUrl: Url, TUri: Uri].} + proc `$`*(url: TUrl): string {.deprecated.} = ## **Deprecated since 0.9.6**: Use ``TUri`` instead. return string(url) @@ -68,7 +70,7 @@ proc parsePath(uri: string, i: var int, result: var TUri) = i.inc parseUntil(uri, result.path, {'?', '#'}, i) # The 'mailto' scheme's PATH actually contains the hostname/username - if result.scheme.ToLower() == "mailto": + if result.scheme.toLower == "mailto": parseAuthority(result.path, result) result.path = "" @@ -172,7 +174,7 @@ proc combine*(base: TUri, reference: TUri): TUri = ## ## Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let foo = combine(parseUri("http://example.com/foo/bar"), parseUri("/baz")) ## assert foo.path == "/baz" ## @@ -229,7 +231,7 @@ proc `/`*(x: TUri, path: string): TUri = ## ## Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: ## let foo = parseUri("http://example.com/foo/bar") / parseUri("/baz") ## assert foo.path == "/foo/bar/baz" ## diff --git a/lib/pure/xmldom.nim b/lib/pure/xmldom.nim index d63b6c5dd..660932d92 100644 --- a/lib/pure/xmldom.nim +++ b/lib/pure/xmldom.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Dominik Picheta # # See the file "copying.txt", included in this @@ -9,14 +9,15 @@ import strutils -## This module implements XML DOM Level 2 Core specification(http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html) +## This module implements XML DOM Level 2 Core +## specification (http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html) #http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html #Exceptions type - EDOMException* = object of EInvalidValue ## Base exception object for all DOM Exceptions + EDOMException* = object of ValueError ## Base exception object for all DOM Exceptions EDOMStringSizeErr* = object of EDOMException ## If the specified range of text does not fit into a DOMString ## Currently not used(Since DOMString is just string) EHierarchyRequestErr* = object of EDOMException ## If any node is inserted somewhere it doesn't belong @@ -55,24 +56,24 @@ type Feature = tuple[name: string, version: string] PDOMImplementation* = ref DOMImplementation DOMImplementation = object - Features: seq[Feature] # Read-Only + features: seq[Feature] # Read-Only PNode* = ref Node - Node = object of TObject + Node = object of RootObj attributes*: seq[PAttr] childNodes*: seq[PNode] - FLocalName: string # Read-only - FNamespaceURI: string # Read-only - FNodeName: string # Read-only + fLocalName: string # Read-only + fNamespaceURI: string # Read-only + fNodeName: string # Read-only nodeValue*: string - FNodeType: int # Read-only - FOwnerDocument: PDocument # Read-Only - FParentNode: PNode # Read-Only + fNodeType: int # Read-only + fOwnerDocument: PDocument # Read-Only + fParentNode: PNode # Read-Only prefix*: string # Setting this should change some values... TODO! PElement* = ref Element Element = object of Node - FTagName: string # Read-only + fTagName: string # Read-only PCharacterData* = ref CharacterData CharacterData = object of Node @@ -80,15 +81,15 @@ type PDocument* = ref Document Document = object of Node - FImplementation: PDOMImplementation # Read-only - FDocumentElement: PElement # Read-only + fImplementation: PDOMImplementation # Read-only + fDocumentElement: PElement # Read-only PAttr* = ref Attr Attr = object of Node - FName: string # Read-only - FSpecified: bool # Read-only + fName: string # Read-only + fSpecified: bool # Read-only value*: string - FOwnerElement: PElement # Read-only + fOwnerElement: PElement # Read-only PDocumentFragment* = ref DocumentFragment DocumentFragment = object of Node @@ -96,7 +97,7 @@ type PText* = ref Text Text = object of CharacterData - PComment* = ref comment + PComment* = ref Comment Comment = object of CharacterData PCDataSection* = ref CDataSection @@ -105,13 +106,13 @@ type PProcessingInstruction* = ref ProcessingInstruction ProcessingInstruction = object of Node data*: string - FTarget: string # Read-only + fTarget: string # Read-only # DOMImplementation proc getDOM*(): PDOMImplementation = ## Returns a DOMImplementation new(result) - result.Features = @[(name: "core", version: "2.0"), + result.features = @[(name: "core", version: "2.0"), (name: "core", version: "1.0"), (name: "XML", version: "2.0")] @@ -119,15 +120,15 @@ proc createDocument*(dom: PDOMImplementation, namespaceURI: string, qualifiedNam ## Creates an XML Document object of the specified type with its document element. var doc: PDocument new(doc) - doc.FNamespaceURI = namespaceURI - doc.FImplementation = dom + doc.fNamespaceURI = namespaceURI + doc.fImplementation = dom var elTag: PElement new(elTag) - elTag.FTagName = qualifiedName - elTag.FNodeName = qualifiedName - doc.FDocumentElement = elTag - doc.FNodeType = DocumentNode + elTag.fTagName = qualifiedName + elTag.fNodeName = qualifiedName + doc.fDocumentElement = elTag + doc.fNodeType = DocumentNode return doc @@ -137,32 +138,32 @@ proc createDocument*(dom: PDOMImplementation, n: PElement): PDocument = # This procedure is not in the specification, it's provided for the parser. var doc: PDocument new(doc) - doc.FDocumentElement = n - doc.FImplementation = dom - doc.FNodeType = DocumentNode + doc.fDocumentElement = n + doc.fImplementation = dom + doc.fNodeType = DocumentNode return doc proc hasFeature*(dom: PDOMImplementation, feature: string, version: string = ""): bool = ## Returns ``true`` if this ``version`` of the DomImplementation implements ``feature``, otherwise ``false`` - for iName, iVersion in items(dom.Features): + for iName, iVersion in items(dom.features): if iName == feature: if version == "": - return True + return true else: if iVersion == version: - return True - return False + return true + return false # Document # Attributes proc implementation*(doc: PDocument): PDOMImplementation = - return doc.FImplementation + return doc.fImplementation proc documentElement*(doc: PDocument): PElement = - return doc.FDocumentElement + return doc.fDocumentElement # Internal procedures proc findNodes(nl: PNode, name: string): seq[PNode] = @@ -172,8 +173,8 @@ proc findNodes(nl: PNode, name: string): seq[PNode] = if nl.childNodes.len() == 0: return @[] for i in items(nl.childNodes): - if i.FNodeType == ElementNode: - if i.FNodeName == name or name == "*": + if i.fNodeType == ElementNode: + if i.fNodeName == name or name == "*": r.add(i) if not isNil(i.childNodes): @@ -189,8 +190,8 @@ proc findNodesNS(nl: PNode, namespaceURI: string, localName: string): seq[PNode] if nl.childNodes.len() == 0: return @[] for i in items(nl.childNodes): - if i.FNodeType == ElementNode: - if (i.FNamespaceURI == namespaceURI or namespaceURI == "*") and (i.FLocalName == localName or localName == "*"): + if i.fNodeType == ElementNode: + if (i.fNamespaceURI == namespaceURI or namespaceURI == "*") and (i.fLocalName == localName or localName == "*"): r.add(i) if not isNil(i.childNodes): @@ -209,16 +210,16 @@ proc createAttribute*(doc: PDocument, name: string): PAttr = if illegalChars in name: raise newException(EInvalidCharacterErr, "Invalid character") - var AttrNode: PAttr - new(AttrNode) - AttrNode.FName = name - AttrNode.FNodeName = name - AttrNode.FLocalName = nil - AttrNode.prefix = nil - AttrNode.FNamespaceURI = nil - AttrNode.value = "" - AttrNode.FSpecified = False - return AttrNode + var attrNode: PAttr + new(attrNode) + attrNode.fName = name + attrNode.fNodeName = name + attrNode.fLocalName = nil + attrNode.prefix = nil + attrNode.fNamespaceURI = nil + attrNode.value = "" + attrNode.fSpecified = false + return attrNode proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PAttr = ## Creates an attribute of the given qualified name and namespace URI @@ -237,48 +238,48 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str raise newException(ENamespaceErr, "When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"") - var AttrNode: PAttr - new(AttrNode) - AttrNode.FName = qualifiedName - AttrNode.FNodeName = qualifiedName - AttrNode.FSpecified = False - AttrNode.FNamespaceURI = namespaceURI + var attrNode: PAttr + new(attrNode) + attrNode.fName = qualifiedName + attrNode.fNodeName = qualifiedName + attrNode.fSpecified = false + attrNode.fNamespaceURI = namespaceURI if qualifiedName.contains(':'): - AttrNode.prefix = qualifiedName.split(':')[0] - AttrNode.FLocalName = qualifiedName.split(':')[1] + attrNode.prefix = qualifiedName.split(':')[0] + attrNode.fLocalName = qualifiedName.split(':')[1] else: - AttrNode.prefix = nil - AttrNode.FLocalName = qualifiedName - AttrNode.value = "" + attrNode.prefix = nil + attrNode.fLocalName = qualifiedName + attrNode.value = "" - AttrNode.FNodeType = AttributeNode - return AttrNode + attrNode.fNodeType = AttributeNode + return attrNode -proc createCDATASection*(doc: PDocument, data: string): PCDATASection = +proc createCDATASection*(doc: PDocument, data: string): PCDataSection = ## Creates a CDATASection node whose value is the specified string. - var CData: PCDATASection - new(CData) - CData.data = data - CData.nodeValue = data - CData.FNodeName = "#text" # Not sure about this, but this is technically a TextNode - CData.FNodeType = CDataSectionNode - return CData + var cData: PCDataSection + new(cData) + cData.data = data + cData.nodeValue = data + cData.fNodeName = "#text" # Not sure about this, but this is technically a TextNode + cData.fNodeType = CDataSectionNode + return cData proc createComment*(doc: PDocument, data: string): PComment = ## Creates a Comment node given the specified string. - var Comm: PComment - new(Comm) - Comm.data = data - Comm.nodeValue = data + var comm: PComment + new(comm) + comm.data = data + comm.nodeValue = data - Comm.FNodeType = CommentNode - return Comm + comm.fNodeType = CommentNode + return comm proc createDocumentFragment*(doc: PDocument): PDocumentFragment = ## Creates an empty DocumentFragment object. - var DF: PDocumentFragment - new(DF) - return DF + var df: PDocumentFragment + new(df) + return df proc createElement*(doc: PDocument, tagName: string): PElement = ## Creates an element of the type specified. @@ -289,22 +290,22 @@ proc createElement*(doc: PDocument, tagName: string): PElement = var elNode: PElement new(elNode) - elNode.FTagName = tagName - elNode.FNodeName = tagName - elNode.FLocalName = nil + elNode.fTagName = tagName + elNode.fNodeName = tagName + elNode.fLocalName = nil elNode.prefix = nil - elNode.FNamespaceURI = nil + elNode.fNamespaceURI = nil elNode.childNodes = @[] elNode.attributes = @[] - elNode.FNodeType = ElementNode + elNode.fNodeType = ElementNode return elNode proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement = ## Creates an element of the given qualified name and namespace URI. if qualifiedName.contains(':'): - if isNIl(namespaceURI): + if isNil(namespaceURI): raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil") elif qualifiedName.split(':')[0].toLower() == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace": raise newException(ENamespaceErr, @@ -316,19 +317,19 @@ proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: strin var elNode: PElement new(elNode) - elNode.FTagName = qualifiedName - elNode.FNodeName = qualifiedName + elNode.fTagName = qualifiedName + elNode.fNodeName = qualifiedName if qualifiedName.contains(':'): elNode.prefix = qualifiedName.split(':')[0] - elNode.FLocalName = qualifiedName.split(':')[1] + elNode.fLocalName = qualifiedName.split(':')[1] else: elNode.prefix = nil - elNode.FLocalName = qualifiedName - elNode.FNamespaceURI = namespaceURI + elNode.fLocalName = qualifiedName + elNode.fNamespaceURI = namespaceURI elNode.childNodes = @[] elNode.attributes = @[] - elNode.FNodeType = ElementNode + elNode.fNodeType = ElementNode return elNode @@ -339,12 +340,12 @@ proc createProcessingInstruction*(doc: PDocument, target: string, data: string): if illegalChars in target: raise newException(EInvalidCharacterErr, "Invalid character") - var PI: PProcessingInstruction - new(PI) - PI.FTarget = target - PI.data = data - PI.FNodeType = ProcessingInstructionNode - return PI + var pi: PProcessingInstruction + new(pi) + pi.fTarget = target + pi.data = data + pi.fNodeType = ProcessingInstructionNode + return pi proc createTextNode*(doc: PDocument, data: string): PText = #Propably TextNode ## Creates a Text node given the specified string. @@ -352,9 +353,9 @@ proc createTextNode*(doc: PDocument, data: string): PText = #Propably TextNode new(txtNode) txtNode.data = data txtNode.nodeValue = data - txtNode.FNodeName = "#text" + txtNode.fNodeName = "#text" - txtNode.FNodeType = TextNode + txtNode.fNodeType = TextNode return txtNode discard """proc getElementById*(doc: PDocument, elementId: string): PElement = @@ -365,42 +366,42 @@ proc getElementsByTagName*(doc: PDocument, tagName: string): seq[PNode] = ## Returns a NodeList of all the Elements with a given tag name in ## the order in which they are encountered in a preorder traversal of the Document tree. var result: seq[PNode] = @[] - if doc.FDocumentElement.FNodeName == tagName or tagName == "*": - result.add(doc.FDocumentElement) + if doc.fDocumentElement.fNodeName == tagName or tagName == "*": + result.add(doc.fDocumentElement) - result.add(doc.FDocumentElement.findNodes(tagName)) + result.add(doc.fDocumentElement.findNodes(tagName)) return result proc getElementsByTagNameNS*(doc: PDocument, namespaceURI: string, localName: string): seq[PNode] = ## Returns a NodeList of all the Elements with a given localName and namespaceURI ## in the order in which they are encountered in a preorder traversal of the Document tree. var result: seq[PNode] = @[] - if doc.FDocumentElement.FLocalName == localName or localName == "*": - if doc.FDocumentElement.FNamespaceURI == namespaceURI or namespaceURI == "*": - result.add(doc.FDocumentElement) + if doc.fDocumentElement.fLocalName == localName or localName == "*": + if doc.fDocumentElement.fNamespaceURI == namespaceURI or namespaceURI == "*": + result.add(doc.fDocumentElement) - result.add(doc.FDocumentElement.findNodesNS(namespaceURI, localName)) + result.add(doc.fDocumentElement.findNodesNS(namespaceURI, localName)) return result proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode = ## Imports a node from another document to this document - case importedNode.FNodeType + case importedNode.fNodeType of AttributeNode: var nAttr: PAttr = PAttr(importedNode) - nAttr.FOwnerDocument = doc - nAttr.FParentNode = nil - nAttr.FOwnerElement = nil - nAttr.FSpecified = True + nAttr.fOwnerDocument = doc + nAttr.fParentNode = nil + nAttr.fOwnerElement = nil + nAttr.fSpecified = true return nAttr of DocumentFragmentNode: var n: PNode new(n) n = importedNode - n.FOwnerDocument = doc - n.FParentNode = nil + n.fOwnerDocument = doc + n.fParentNode = nil - n.FOwnerDocument = doc - n.FParentNode = nil + n.fOwnerDocument = doc + n.fParentNode = nil var tmp: seq[PNode] = n.childNodes n.childNodes = @[] if deep: @@ -412,8 +413,8 @@ proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode = var n: PNode new(n) n = importedNode - n.FOwnerDocument = doc - n.FParentNode = nil + n.fOwnerDocument = doc + n.fParentNode = nil var tmpA: seq[PAttr] = n.attributes n.attributes = @[] @@ -432,8 +433,8 @@ proc importNode*(doc: PDocument, importedNode: PNode, deep: bool): PNode = var n: PNode new(n) n = importedNode - n.FOwnerDocument = doc - n.FParentNode = nil + n.fOwnerDocument = doc + n.fParentNode = nil return n else: raise newException(ENotSupportedErr, "The type of node being imported is not supported") @@ -461,58 +462,58 @@ proc lastChild*(n: PNode): PNode = proc localName*(n: PNode): string = ## Returns this nodes local name - return n.FLocalName + return n.fLocalName proc namespaceURI*(n: PNode): string = ## Returns this nodes namespace URI - return n.FNamespaceURI + return n.fNamespaceURI proc `namespaceURI=`*(n: PNode, value: string) = - n.FNamespaceURI = value + n.fNamespaceURI = value proc nextSibling*(n: PNode): PNode = ## Returns the next sibling of this node - if isNil(n.FParentNode) or isNil(n.FParentNode.childNodes): + if isNil(n.fParentNode) or isNil(n.fParentNode.childNodes): return nil - var nLow: int = low(n.FParentNode.childNodes) - var nHigh: int = high(n.FParentNode.childNodes) + var nLow: int = low(n.fParentNode.childNodes) + var nHigh: int = high(n.fParentNode.childNodes) for i in nLow..nHigh: - if n.FParentNode.childNodes[i] == n: - return n.FParentNode.childNodes[i + 1] + if n.fParentNode.childNodes[i] == n: + return n.fParentNode.childNodes[i + 1] return nil proc nodeName*(n: PNode): string = ## Returns the name of this node - return n.FNodeName + return n.fNodeName proc nodeType*(n: PNode): int = ## Returns the type of this node - return n.FNodeType + return n.fNodeType proc ownerDocument*(n: PNode): PDocument = ## Returns the owner document of this node - return n.FOwnerDocument + return n.fOwnerDocument proc parentNode*(n: PNode): PNode = ## Returns the parent node of this node - return n.FParentNode + return n.fParentNode proc previousSibling*(n: PNode): PNode = ## Returns the previous sibling of this node - if isNil(n.FParentNode) or isNil(n.FParentNode.childNodes): + if isNil(n.fParentNode) or isNil(n.fParentNode.childNodes): return nil - var nLow: int = low(n.FParentNode.childNodes) - var nHigh: int = high(n.FParentNode.childNodes) + var nLow: int = low(n.fParentNode.childNodes) + var nHigh: int = high(n.fParentNode.childNodes) for i in nLow..nHigh: - if n.FParentNode.childNodes[i] == n: - return n.FParentNode.childNodes[i - 1] + if n.fParentNode.childNodes[i] == n: + return n.fParentNode.childNodes[i - 1] return nil proc `prefix=`*(n: PNode, value: string) = @@ -523,25 +524,25 @@ proc `prefix=`*(n: PNode, value: string) = if illegalChars in value: raise newException(EInvalidCharacterErr, "Invalid character") - if isNil(n.FNamespaceURI): + if isNil(n.fNamespaceURI): raise newException(ENamespaceErr, "namespaceURI cannot be nil") - elif value.toLower() == "xml" and n.FNamespaceURI != "http://www.w3.org/XML/1998/namespace": + elif value.toLower() == "xml" and n.fNamespaceURI != "http://www.w3.org/XML/1998/namespace": raise newException(ENamespaceErr, "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"") - elif value.toLower() == "xmlns" and n.FNamespaceURI != "http://www.w3.org/2000/xmlns/": + elif value.toLower() == "xmlns" and n.fNamespaceURI != "http://www.w3.org/2000/xmlns/": raise newException(ENamespaceErr, "When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"") - elif value.toLower() == "xmlns" and n.FNodeType == AttributeNode: + elif value.toLower() == "xmlns" and n.fNodeType == AttributeNode: raise newException(ENamespaceErr, "An AttributeNode cannot have a prefix of \"xmlns\"") - n.FNodeName = value & ":" & n.FLocalName + n.fNodeName = value & ":" & n.fLocalName if n.nodeType == ElementNode: var el: PElement = PElement(n) - el.FTagName = value & ":" & n.FLocalName + el.fTagName = value & ":" & n.fLocalName elif n.nodeType == AttributeNode: var attr: PAttr = PAttr(n) - attr.FName = value & ":" & n.FLocalName + attr.fName = value & ":" & n.fLocalName # Procedures proc appendChild*(n: PNode, newChild: PNode) = @@ -555,7 +556,7 @@ proc appendChild*(n: PNode, newChild: PNode) = raise newException(EHierarchyRequestErr, "The node to append is already in this nodes children.") # Check if newChild is from this nodes document - if n.FOwnerDocument != newChild.FOwnerDocument: + if n.fOwnerDocument != newChild.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") if n == newChild: @@ -566,7 +567,7 @@ proc appendChild*(n: PNode, newChild: PNode) = if isNil(n.childNodes): n.childNodes = @[] - newChild.FParentNode = n + newChild.fParentNode = n for i in low(n.childNodes)..high(n.childNodes): if n.childNodes[i] == newChild: n.childNodes[i] = newChild @@ -575,13 +576,13 @@ proc appendChild*(n: PNode, newChild: PNode) = proc cloneNode*(n: PNode, deep: bool): PNode = ## Returns a duplicate of this node, if ``deep`` is `true`, Element node's children are copied - case n.FNodeType + case n.fNodeType of AttributeNode: var newNode: PAttr new(newNode) newNode = PAttr(n) - newNode.FSpecified = True - newNode.FOwnerElement = nil + newNode.fSpecified = true + newNode.fOwnerElement = nil return newNode of ElementNode: var newNode: PElement @@ -613,32 +614,32 @@ proc insertBefore*(n: PNode, newChild: PNode, refChild: PNode): PNode = ## If ``refChild`` is nil, insert ``newChild`` at the end of the list of children. # Check if newChild is from this nodes document - if n.FOwnerDocument != newChild.FOwnerDocument: + if n.fOwnerDocument != newChild.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") if isNil(n.childNodes): - n.ChildNodes = @[] + n.childNodes = @[] for i in low(n.childNodes)..high(n.childNodes): if n.childNodes[i] == refChild: n.childNodes.insert(newChild, i - 1) return - n.ChildNodes.add(newChild) + n.childNodes.add(newChild) proc isSupported*(n: PNode, feature: string, version: string): bool = ## Tests whether the DOM implementation implements a specific ## feature and that feature is supported by this node. - return n.FOwnerDocument.FImplementation.hasFeature(feature, version) + return n.fOwnerDocument.fImplementation.hasFeature(feature, version) proc isEmpty(s: string): bool = if isNil(s) or s == "": - return True + return true for i in items(s): if i != ' ': - return False - return True + return false + return true proc normalize*(n: PNode) = ## Merges all seperated TextNodes together, and removes any empty TextNodes @@ -646,7 +647,7 @@ proc normalize*(n: PNode) = var i: int = 0 var newChildNodes: seq[PNode] = @[] - while True: + while true: if isNil(n.childNodes) or i >= n.childNodes.len: break if n.childNodes[i].nodeType == TextNode: @@ -684,7 +685,7 @@ proc replaceChild*(n: PNode, newChild: PNode, oldChild: PNode): PNode = ## Replaces the child node ``oldChild`` with ``newChild`` in the list of children, and returns the ``oldChild`` node. # Check if newChild is from this nodes document - if n.FOwnerDocument != newChild.FOwnerDocument: + if n.fOwnerDocument != newChild.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") if not isNil(n.childNodes): @@ -698,159 +699,159 @@ proc replaceChild*(n: PNode, newChild: PNode, oldChild: PNode): PNode = # NamedNodeMap -proc getNamedItem*(NList: seq[PNode], name: string): PNode = +proc getNamedItem*(nList: seq[PNode], name: string): PNode = ## Retrieves a node specified by ``name``. If this node cannot be found returns ``nil`` - for i in items(NList): + for i in items(nList): if i.nodeName() == name: return i return nil -proc getNamedItem*(NList: seq[PAttr], name: string): PAttr = +proc getNamedItem*(nList: seq[PAttr], name: string): PAttr = ## Retrieves a node specified by ``name``. If this node cannot be found returns ``nil`` - for i in items(NList): + for i in items(nList): if i.nodeName() == name: return i return nil -proc getNamedItemNS*(NList: seq[PNode], namespaceURI: string, localName: string): PNode = +proc getNamedItemNS*(nList: seq[PNode], namespaceURI: string, localName: string): PNode = ## Retrieves a node specified by ``localName`` and ``namespaceURI``. If this node cannot be found returns ``nil`` - for i in items(NList): + for i in items(nList): if i.namespaceURI() == namespaceURI and i.localName() == localName: return i return nil -proc getNamedItemNS*(NList: seq[PAttr], namespaceURI: string, localName: string): PAttr = +proc getNamedItemNS*(nList: seq[PAttr], namespaceURI: string, localName: string): PAttr = ## Retrieves a node specified by ``localName`` and ``namespaceURI``. If this node cannot be found returns ``nil`` - for i in items(NList): - if i.NamespaceURI() == namespaceURI and i.LocalName() == localName: + for i in items(nList): + if i.namespaceURI() == namespaceURI and i.localName() == localName: return i return nil -proc item*(NList: seq[PNode], index: int): PNode = +proc item*(nList: seq[PNode], index: int): PNode = ## Returns the ``index`` th item in the map. ## If ``index`` is greater than or equal to the number of nodes in this map, this returns ``nil``. - if index >= NList.len(): return nil - else: return NList[index] + if index >= nList.len(): return nil + else: return nList[index] -proc removeNamedItem*(NList: var seq[PNode], name: string): PNode = +proc removeNamedItem*(nList: var seq[PNode], name: string): PNode = ## Removes a node specified by ``name`` ## Raises the ``ENotFoundErr`` exception, if the node was not found - for i in low(NList)..high(NList): - if NList[i].FNodeName == name: - result = NList[i] - NList.delete(i) + for i in low(nList)..high(nList): + if nList[i].fNodeName == name: + result = nList[i] + nList.delete(i) return result raise newException(ENotFoundErr, "Node not found") -proc removeNamedItemNS*(NList: var seq[PNode], namespaceURI: string, localName: string): PNode = +proc removeNamedItemNS*(nList: var seq[PNode], namespaceURI: string, localName: string): PNode = ## Removes a node specified by local name and namespace URI - for i in low(NList)..high(NList): - if NList[i].FLocalName == localName and NList[i].FNamespaceURI == namespaceURI: - result = NList[i] - NList.delete(i) + for i in low(nList)..high(nList): + if nList[i].fLocalName == localName and nList[i].fNamespaceURI == namespaceURI: + result = nList[i] + nList.delete(i) return result raise newException(ENotFoundErr, "Node not found") -proc setNamedItem*(NList: var seq[PNode], arg: PNode): PNode = +proc setNamedItem*(nList: var seq[PNode], arg: PNode): PNode = ## Adds ``arg`` as a ``Node`` to the ``NList`` ## If a node with the same name is already present in this map, it is replaced by the new one. - if not isNil(NList): - if NList.len() > 0: + if not isNil(nList): + if nList.len() > 0: #Check if newChild is from this nodes document - if NList[0].FOwnerDocument != arg.FOwnerDocument: + if nList[0].fOwnerDocument != arg.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") #Exceptions End - var item: PNode = NList.getNamedItem(arg.NodeName()) + var item: PNode = nList.getNamedItem(arg.nodeName()) if isNil(item): - NList.add(arg) + nList.add(arg) return nil else: # Node with the same name exists var index: int = 0 - for i in low(NList)..high(NList): - if NList[i] == item: + for i in low(nList)..high(nList): + if nList[i] == item: index = i break - NList[index] = arg + nList[index] = arg return item # Return the replaced node -proc setNamedItem*(NList: var seq[PAttr], arg: PAttr): PAttr = +proc setNamedItem*(nList: var seq[PAttr], arg: PAttr): PAttr = ## Adds ``arg`` as a ``Node`` to the ``NList`` ## If a node with the same name is already present in this map, it is replaced by the new one. - if not isNil(NList): - if NList.len() > 0: + if not isNil(nList): + if nList.len() > 0: # Check if newChild is from this nodes document - if NList[0].FOwnerDocument != arg.FOwnerDocument: + if nList[0].fOwnerDocument != arg.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - if not isNil(arg.FOwnerElement): + if not isNil(arg.fOwnerElement): raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") # Exceptions end - var item: PAttr = NList.getNamedItem(arg.nodeName()) + var item: PAttr = nList.getNamedItem(arg.nodeName()) if isNil(item): - NList.add(arg) + nList.add(arg) return nil else: # Node with the same name exists var index: int = 0 - for i in low(NList)..high(NList): - if NList[i] == item: + for i in low(nList)..high(nList): + if nList[i] == item: index = i break - NList[index] = arg + nList[index] = arg return item # Return the replaced node -proc setNamedItemNS*(NList: var seq[PNode], arg: PNode): PNode = +proc setNamedItemNS*(nList: var seq[PNode], arg: PNode): PNode = ## Adds a node using its ``namespaceURI`` and ``localName`` - if not isNil(NList): - if NList.len() > 0: + if not isNil(nList): + if nList.len() > 0: # Check if newChild is from this nodes document - if NList[0].FOwnerDocument != arg.FOwnerDocument: + if nList[0].fOwnerDocument != arg.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") #Exceptions end - var item: PNode = NList.getNamedItemNS(arg.namespaceURI(), arg.localName()) + var item: PNode = nList.getNamedItemNS(arg.namespaceURI(), arg.localName()) if isNil(item): - NList.add(arg) + nList.add(arg) return nil else: # Node with the same name exists var index: int = 0 - for i in low(NList)..high(NList): - if NList[i] == item: + for i in low(nList)..high(nList): + if nList[i] == item: index = i break - NList[index] = arg + nList[index] = arg return item # Return the replaced node -proc setNamedItemNS*(NList: var seq[PAttr], arg: PAttr): PAttr = +proc setNamedItemNS*(nList: var seq[PAttr], arg: PAttr): PAttr = ## Adds a node using its ``namespaceURI`` and ``localName`` - if not isNil(NList): - if NList.len() > 0: + if not isNil(nList): + if nList.len() > 0: # Check if newChild is from this nodes document - if NList[0].FOwnerDocument != arg.FOwnerDocument: + if nList[0].fOwnerDocument != arg.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - if not isNil(arg.FOwnerElement): + if not isNil(arg.fOwnerElement): raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") # Exceptions end - var item: PAttr = NList.getNamedItemNS(arg.namespaceURI(), arg.localName()) + var item: PAttr = nList.getNamedItemNS(arg.namespaceURI(), arg.localName()) if isNil(item): - NList.add(arg) + nList.add(arg) return nil else: # Node with the same name exists var index: int = 0 - for i in low(NList)..high(NList): - if NList[i] == item: + for i in low(nList)..high(nList): + if nList[i] == item: index = i break - NList[index] = arg + nList[index] = arg return item # Return the replaced node # CharacterData - Decided to implement this, @@ -861,17 +862,17 @@ proc setNamedItemNS*(NList: var seq[PAttr], arg: PAttr): PAttr = proc name*(a: PAttr): string = ## Returns the name of the Attribute - return a.FName + return a.fName proc specified*(a: PAttr): bool = ## Specifies whether this attribute was specified in the original document - return a.FSpecified + return a.fSpecified proc ownerElement*(a: PAttr): PElement = ## Returns this Attributes owner element - return a.FOwnerElement + return a.fOwnerElement # Element # Attributes @@ -879,7 +880,7 @@ proc ownerElement*(a: PAttr): PElement = proc tagName*(el: PElement): string = ## Returns the Element Tag Name - return el.FTagName + return el.fTagName # Procedures proc getAttribute*(el: PElement, name: string): string = @@ -945,15 +946,15 @@ proc removeAttribute*(el: PElement, name: string) = ## Removes an attribute by ``name`` if not isNil(el.attributes): for i in low(el.attributes)..high(el.attributes): - if el.attributes[i].FName == name: + if el.attributes[i].fName == name: el.attributes.delete(i) proc removeAttributeNS*(el: PElement, namespaceURI: string, localName: string) = ## Removes an attribute by ``localName`` and ``namespaceURI`` if not isNil(el.attributes): for i in low(el.attributes)..high(el.attributes): - if el.attributes[i].FNamespaceURI == namespaceURI and - el.attributes[i].FLocalName == localName: + if el.attributes[i].fNamespaceURI == namespaceURI and + el.attributes[i].fLocalName == localName: el.attributes.delete(i) proc removeAttributeNode*(el: PElement, oldAttr: PAttr): PAttr = @@ -974,11 +975,11 @@ proc setAttributeNode*(el: PElement, newAttr: PAttr): PAttr = ## returned, otherwise ``nil`` is returned. # Check if newAttr is from this nodes document - if el.FOwnerDocument != newAttr.FOwnerDocument: + if el.fOwnerDocument != newAttr.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - if not isNil(newAttr.FOwnerElement): + if not isNil(newAttr.fOwnerElement): raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") # Exceptions end @@ -992,11 +993,11 @@ proc setAttributeNodeNS*(el: PElement, newAttr: PAttr): PAttr = ## and the replaced attribute is returned, otherwise ``nil`` is returned. # Check if newAttr is from this nodes document - if el.FOwnerDocument != newAttr.FOwnerDocument: + if el.fOwnerDocument != newAttr.fOwnerDocument: raise newException(EWrongDocumentErr, "This node belongs to a different document, use importNode.") - if not isNil(newAttr.FOwnerElement): + if not isNil(newAttr.fOwnerElement): raise newException(EInuseAttributeErr, "This attribute is in use by another element, use cloneNode") # Exceptions end @@ -1010,17 +1011,17 @@ proc setAttribute*(el: PElement, name: string, value: string) = ## value is changed to be that of the value parameter ## Raises the EInvalidCharacterErr if the specified ``name`` contains ## illegal characters - var AttrNode = el.FOwnerDocument.createAttribute(name) + var attrNode = el.fOwnerDocument.createAttribute(name) # Check if name contains illegal characters if illegalChars in name: raise newException(EInvalidCharacterErr, "Invalid character") - discard el.setAttributeNode(AttrNode) + discard el.setAttributeNode(attrNode) # Set the info later, the setAttributeNode checks # if FOwnerElement is nil, and if it isn't it raises an exception - AttrNode.FOwnerElement = el - AttrNode.FSpecified = True - AttrNode.value = value + attrNode.fOwnerElement = el + attrNode.fSpecified = true + attrNode.value = value proc setAttributeNS*(el: PElement, namespaceURI, localName, value: string) = ## Adds a new attribute, as specified by ``namespaceURI``, ``localName`` @@ -1030,43 +1031,43 @@ proc setAttributeNS*(el: PElement, namespaceURI, localName, value: string) = if illegalChars in namespaceURI or illegalChars in localName: raise newException(EInvalidCharacterErr, "Invalid character") - var AttrNode = el.FOwnerDocument.createAttributeNS(namespaceURI, localName) + var attrNode = el.fOwnerDocument.createAttributeNS(namespaceURI, localName) - discard el.setAttributeNodeNS(AttrNode) + discard el.setAttributeNodeNS(attrNode) # Set the info later, the setAttributeNode checks # if FOwnerElement is nil, and if it isn't it raises an exception - AttrNode.FOwnerElement = el - AttrNode.FSpecified = True - AttrNode.value = value + attrNode.fOwnerElement = el + attrNode.fSpecified = true + attrNode.value = value # Text -proc splitData*(TextNode: PText, offset: int): PText = +proc splitData*(textNode: PText, offset: int): PText = ## Breaks this node into two nodes at the specified offset, ## keeping both in the tree as siblings. - if offset > TextNode.data.len(): + if offset > textNode.data.len(): raise newException(EIndexSizeErr, "Index out of bounds") - var left: string = TextNode.data.substr(0, offset) - TextNode.data = left - var right: string = TextNode.data.substr(offset, TextNode.data.len()) + var left: string = textNode.data.substr(0, offset) + textNode.data = left + var right: string = textNode.data.substr(offset, textNode.data.len()) - if not isNil(TextNode.FParentNode) and not isNil(TextNode.FParentNode.childNodes): - for i in low(TextNode.FParentNode.childNodes)..high(TextNode.FParentNode.childNodes): - if TextNode.FParentNode.childNodes[i] == TextNode: - var newNode: PText = TextNode.FOwnerDocument.createTextNode(right) - TextNode.FParentNode.childNodes.insert(newNode, i) + if not isNil(textNode.fParentNode) and not isNil(textNode.fParentNode.childNodes): + for i in low(textNode.fParentNode.childNodes)..high(textNode.fParentNode.childNodes): + if textNode.fParentNode.childNodes[i] == textNode: + var newNode: PText = textNode.fOwnerDocument.createTextNode(right) + textNode.fParentNode.childNodes.insert(newNode, i) return newNode else: - var newNode: PText = TextNode.FOwnerDocument.createTextNode(right) + var newNode: PText = textNode.fOwnerDocument.createTextNode(right) return newNode # ProcessingInstruction -proc target*(PI: PProcessingInstruction): string = +proc target*(pi: PProcessingInstruction): string = ## Returns the Processing Instructions target - return PI.FTarget + return pi.fTarget # --Other stuff-- diff --git a/lib/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim index fda46bac0..7f34d72a8 100644 --- a/lib/pure/xmldomparser.nim +++ b/lib/pure/xmldomparser.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Dominik Picheta # # See the file "copying.txt", included in this @@ -15,13 +15,13 @@ import xmldom, os, streams, parsexml, strutils type # Parsing errors - EMismatchedTag* = object of EInvalidValue ## Raised when a tag is not properly closed - EParserError* = object of EInvalidValue ## Raised when an unexpected XML Parser event occurs + EMismatchedTag* = object of ValueError ## Raised when a tag is not properly closed + EParserError* = object of ValueError ## Raised when an unexpected XML Parser event occurs # For namespaces - xmlnsAttr = tuple[name, value: string, ownerElement: PElement] + XmlnsAttr = tuple[name, value: string, ownerElement: PElement] -var nsList: seq[xmlnsAttr] = @[] # Used for storing namespaces +var nsList: seq[XmlnsAttr] = @[] # Used for storing namespaces proc getNS(prefix: string): string = var defaultNS: seq[string] = @[] @@ -43,13 +43,13 @@ proc getNS(prefix: string): string = return "" -proc parseText(x: var TXmlParser, doc: var PDocument): PText = +proc parseText(x: var XmlParser, doc: var PDocument): PText = result = doc.createTextNode(x.charData()) -proc parseElement(x: var TXmlParser, doc: var PDocument): PElement = +proc parseElement(x: var XmlParser, doc: var PDocument): PElement = var n = doc.createElement("") - while True: + while true: case x.kind() of xmlEof: break @@ -102,10 +102,10 @@ proc parseElement(x: var TXmlParser, doc: var PDocument): PElement = of xmlComment: n.appendChild(doc.createComment(x.charData())) of xmlPI: - n.appendChild(doc.createProcessingInstruction(x.PIName(), x.PIRest())) + n.appendChild(doc.createProcessingInstruction(x.piName(), x.piRest())) of xmlWhitespace, xmlElementClose, xmlEntity, xmlSpecial: - # Unused 'events' + discard " Unused \'events\'" else: raise newException(EParserError, "Unexpected XML Parser event") @@ -114,30 +114,30 @@ proc parseElement(x: var TXmlParser, doc: var PDocument): PElement = raise newException(EMismatchedTag, "Mismatched tag at line " & $x.getLine() & " column " & $x.getColumn) -proc loadXMLStream*(stream: PStream): PDocument = +proc loadXMLStream*(stream: Stream): PDocument = ## Loads and parses XML from a stream specified by ``stream``, and returns ## a ``PDocument`` - var x: TXmlParser + var x: XmlParser open(x, stream, nil, {reportComments}) - var XmlDoc: PDocument - var DOM: PDOMImplementation = getDOM() + var xmlDoc: PDocument + var dom: PDOMImplementation = getDOM() - while True: + while true: x.next() case x.kind() of xmlEof: break of xmlElementStart, xmlElementOpen: - var el: PElement = parseElement(x, XmlDoc) - XmlDoc = dom.createDocument(el) + var el: PElement = parseElement(x, xmlDoc) + xmlDoc = dom.createDocument(el) of xmlWhitespace, xmlElementClose, xmlEntity, xmlSpecial: - # Unused 'events' + discard " Unused \'events\'" else: raise newException(EParserError, "Unexpected XML Parser event") - return XmlDoc + return xmlDoc proc loadXML*(xml: string): PDocument = ## Loads and parses XML from a string specified by ``xml``, and returns @@ -151,12 +151,12 @@ proc loadXMLFile*(path: string): PDocument = ## a ``PDocument`` var s = newFileStream(path, fmRead) - if s == nil: raise newException(EIO, "Unable to read file " & path) + if s == nil: raise newException(IOError, "Unable to read file " & path) return loadXMLStream(s) when isMainModule: - var xml = loadXMLFile(r"C:\Users\Dominik\Desktop\Code\Nimrod\xmldom\test.xml") + var xml = loadXMLFile("nim/xmldom/test.xml") #echo(xml.getElementsByTagName("m:test2")[0].namespaceURI) #echo(xml.getElementsByTagName("bla:test")[0].namespaceURI) #echo(xml.getElementsByTagName("test")[0].namespaceURI) diff --git a/lib/pure/xmlparser.nim b/lib/pure/xmlparser.nim index 8b8bb3b03..8591e894c 100644 --- a/lib/pure/xmlparser.nim +++ b/lib/pure/xmlparser.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,23 +12,25 @@ import streams, parsexml, strtabs, xmltree type - EInvalidXml* = object of EInvalidValue ## exception that is raised - ## for invalid XML - errors*: seq[string] ## all detected parsing errors + XmlError* = object of ValueError ## exception that is raised + ## for invalid XML + errors*: seq[string] ## all detected parsing errors + +{.deprecated: [EInvalidXml: XmlError].} proc raiseInvalidXml(errors: seq[string]) = - var e: ref EInvalidXml + var e: ref XmlError new(e) e.msg = errors[0] e.errors = errors raise e -proc addNode(father, son: PXmlNode) = +proc addNode(father, son: XmlNode) = if son != nil: add(father, son) -proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode +proc parse(x: var XmlParser, errors: var seq[string]): XmlNode -proc untilElementEnd(x: var TXmlParser, result: PXmlNode, +proc untilElementEnd(x: var XmlParser, result: XmlNode, errors: var seq[string]) = while true: case x.kind @@ -45,7 +47,7 @@ proc untilElementEnd(x: var TXmlParser, result: PXmlNode, else: result.addNode(parse(x, errors)) -proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode = +proc parse(x: var XmlParser, errors: var seq[string]): XmlNode = case x.kind of xmlComment: result = newComment(x.charData) @@ -98,11 +100,11 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode = next(x) of xmlEof: discard -proc parseXml*(s: PStream, filename: string, - errors: var seq[string]): PXmlNode = +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. - var x: TXmlParser + var x: XmlParser open(x, s, filename, {reportComments}) while true: x.next() @@ -118,28 +120,28 @@ proc parseXml*(s: PStream, filename: string, break close(x) -proc parseXml*(s: PStream): PXmlNode = +proc parseXml*(s: Stream): XmlNode = ## parses the XTML from stream `s` and returns a ``PXmlNode``. All parsing ## errors are turned into an ``EInvalidXML`` exception. var errors: seq[string] = @[] result = parseXml(s, "unknown_html_doc", errors) - if errors.len > 0: raiseInvalidXMl(errors) + if errors.len > 0: raiseInvalidXml(errors) -proc loadXml*(path: string, errors: var seq[string]): PXmlNode = +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` ## sequence. var s = newFileStream(path, fmRead) - if s == nil: raise newException(EIO, "Unable to read file: " & path) + if s == nil: raise newException(IOError, "Unable to read file: " & path) result = parseXml(s, path, errors) -proc loadXml*(path: string): PXmlNode = +proc loadXml*(path: string): XmlNode = ## Loads and parses XML from file specified by ``path``, and returns ## a ``PXmlNode``. All parsing errors are turned into an ``EInvalidXML`` ## exception. var errors: seq[string] = @[] result = loadXml(path, errors) - if errors.len > 0: raiseInvalidXMl(errors) + if errors.len > 0: raiseInvalidXml(errors) when isMainModule: import os @@ -148,7 +150,7 @@ when isMainModule: var x = loadXml(paramStr(1), errors) for e in items(errors): echo e - var f: TFile + var f: File if open(f, "xmltest.txt", fmWrite): f.write($x) f.close() diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 1af7db7d5..b84da9586 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,76 +12,79 @@ import macros, strtabs type - PXmlNode* = ref TXmlNode ## an XML tree consists of ``PXmlNode``'s. + XmlNode* = ref XmlNodeObj ## an XML tree consists of ``PXmlNode``'s. - TXmlNodeKind* = enum ## different kinds of ``PXmlNode``'s + XmlNodeKind* = enum ## different kinds of ``PXmlNode``'s xnText, ## a text element xnElement, ## an element with 0 or more children xnCData, ## a CDATA node xnEntity, ## an entity (like ``&thing;``) xnComment ## an XML comment - PXmlAttributes* = PStringTable ## an alias for a string to string mapping + XmlAttributes* = StringTableRef ## an alias for a string to string mapping - TXmlNode {.pure, final, acyclic.} = object - case k: TXmlNodeKind # private, use the kind() proc to read this field. + XmlNodeObj {.acyclic.} = object + case k: XmlNodeKind # private, use the kind() proc to read this field. of xnText, xnComment, xnCData, xnEntity: fText: string of xnElement: fTag: string - s: seq[PXmlNode] - fAttr: PXmlAttributes + s: seq[XmlNode] + fAttr: XmlAttributes fClientData: int ## for other clients - -proc newXmlNode(kind: TXmlNodeKind): PXmlNode = - ## creates a new ``PXmlNode``. + +{.deprecated: [PXmlNode: XmlNode, TXmlNodeKind: XmlNodeKind, PXmlAttributes: + XmlAttributes, TXmlNode: XmlNodeObj].} + +proc newXmlNode(kind: XmlNodeKind): XmlNode = + ## creates a new ``XmlNode``. new(result) result.k = kind -proc newElement*(tag: string): PXmlNode = +proc newElement*(tag: string): XmlNode = ## creates a new ``PXmlNode`` of kind ``xnText`` with the given `tag`. result = newXmlNode(xnElement) result.fTag = tag result.s = @[] # init attributes lazily to safe memory -proc newText*(text: string): PXmlNode = +proc newText*(text: string): XmlNode = ## creates a new ``PXmlNode`` of kind ``xnText`` with the text `text`. result = newXmlNode(xnText) result.fText = text -proc newComment*(comment: string): PXmlNode = +proc newComment*(comment: string): XmlNode = ## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `comment`. result = newXmlNode(xnComment) result.fText = comment -proc newCData*(cdata: string): PXmlNode = +proc newCData*(cdata: string): XmlNode = ## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `cdata`. result = newXmlNode(xnCData) result.fText = cdata -proc newEntity*(entity: string): PXmlNode = +proc newEntity*(entity: string): XmlNode = ## creates a new ``PXmlNode`` of kind ``xnEntity`` with the text `entity`. result = newXmlNode(xnCData) result.fText = entity -proc text*(n: PXmlNode): string {.inline.} = +proc text*(n: XmlNode): string {.inline.} = ## gets the associated text with the node `n`. `n` can be a CDATA, Text, ## comment, or entity node. assert n.k in {xnText, xnComment, xnCData, xnEntity} result = n.fText -proc rawText*(n: PXmlNode): string {.inline.} = +proc rawText*(n: XmlNode): string {.inline.} = ## returns the underlying 'text' string by reference. ## This is only used for speed hacks. shallowCopy(result, n.fText) -proc rawTag*(n: PXmlNode): string {.inline.} = +proc rawTag*(n: XmlNode): string {.inline.} = ## returns the underlying 'tag' string by reference. ## This is only used for speed hacks. shallowCopy(result, n.fTag) -proc innerText*(n: PXmlNode): string = +proc innerText*(n: XmlNode): string = ## gets the inner text of `n`. `n` has to be an ``xnElement`` node. Only ## ``xnText`` and ``xnEntity`` nodes are considered part of `n`'s inner text, ## other child nodes are silently ignored. @@ -90,55 +93,55 @@ proc innerText*(n: PXmlNode): string = for i in 0 .. n.s.len-1: if n.s[i].k in {xnText, xnEntity}: result.add(n.s[i].fText) -proc tag*(n: PXmlNode): string {.inline.} = +proc tag*(n: XmlNode): string {.inline.} = ## gets the tag name of `n`. `n` has to be an ``xnElement`` node. assert n.k == xnElement result = n.fTag -proc add*(father, son: PXmlNode) {.inline.} = +proc add*(father, son: XmlNode) {.inline.} = ## adds the child `son` to `father`. add(father.s, son) -proc len*(n: PXmlNode): int {.inline.} = +proc len*(n: XmlNode): int {.inline.} = ## returns the number `n`'s children. if n.k == xnElement: result = len(n.s) -proc kind*(n: PXmlNode): TXmlNodeKind {.inline.} = +proc kind*(n: XmlNode): XmlNodeKind {.inline.} = ## returns `n`'s kind. result = n.k -proc `[]`* (n: PXmlNode, i: int): PXmlNode {.inline.} = +proc `[]`* (n: XmlNode, i: int): XmlNode {.inline.} = ## returns the `i`'th child of `n`. assert n.k == xnElement result = n.s[i] -iterator items*(n: PXmlNode): PXmlNode {.inline.} = +iterator items*(n: XmlNode): XmlNode {.inline.} = ## iterates over any child of `n`. assert n.k == xnElement for i in 0 .. n.len-1: yield n[i] -proc attrs*(n: PXmlNode): PXmlAttributes {.inline.} = +proc attrs*(n: XmlNode): XmlAttributes {.inline.} = ## gets the attributes belonging to `n`. ## Returns `nil` if attributes have not been initialised for this node. assert n.k == xnElement result = n.fAttr -proc `attrs=`*(n: PXmlNode, attr: PXmlAttributes) {.inline.} = +proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} = ## sets the attributes belonging to `n`. assert n.k == xnElement n.fAttr = attr -proc attrsLen*(n: PXmlNode): int {.inline.} = +proc attrsLen*(n: XmlNode): int {.inline.} = ## returns the number of `n`'s attributes. assert n.k == xnElement if not isNil(n.fAttr): result = len(n.fAttr) -proc clientData*(n: PXmlNode): int {.inline.} = +proc clientData*(n: XmlNode): int {.inline.} = ## gets the client data of `n`. The client data field is used by the HTML ## parser and generator. result = n.fClientData -proc `clientData=`*(n: PXmlNode, data: int) {.inline.} = +proc `clientData=`*(n: XmlNode, data: int) {.inline.} = ## sets the client data of `n`. The client data field is used by the HTML ## parser and generator. n.fClientData = data @@ -176,13 +179,13 @@ proc addIndent(result: var string, indent: int) = result.add("\n") for i in 1..indent: result.add(' ') -proc noWhitespace(n: PXmlNode): bool = +proc noWhitespace(n: XmlNode): bool = #for i in 1..n.len-1: # if n[i].kind != n[0].kind: return true for i in 0..n.len-1: if n[i].kind in {xnText, xnEntity}: return true -proc add*(result: var string, n: PXmlNode, indent = 0, indWidth = 2) = +proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) = ## adds the textual representation of `n` to `result`. if n == nil: return case n.k @@ -222,7 +225,7 @@ proc add*(result: var string, n: PXmlNode, indent = 0, indWidth = 2) = result.add("<!-- ") result.addEscaped(n.fText) result.add(" -->") - of xnCDATA: + of xnCData: result.add("<![CDATA[") result.add(n.fText) result.add("]]>") @@ -235,14 +238,14 @@ const xmlHeader* = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" ## header to use for complete XML output -proc `$`*(n: PXmlNode): string = +proc `$`*(n: XmlNode): string = ## converts `n` into its string representation. No ``<$xml ...$>`` declaration ## is produced, so that the produced XML fragments are composable. result = "" result.add(n) -proc newXmlTree*(tag: string, children: openArray[PXmlNode], - attributes: PXmlAttributes = nil): PXmlNode = +proc newXmlTree*(tag: string, children: openArray[XmlNode], + attributes: XmlAttributes = nil): XmlNode = ## creates a new XML tree with `tag`, `children` and `attributes` result = newXmlNode(xnElement) result.fTag = tag @@ -276,17 +279,17 @@ proc xmlConstructor(e: PNimrodNode): PNimrodNode {.compileTime.} = macro `<>`*(x: expr): expr {.immediate.} = ## Constructor macro for XML. Example usage: ## - ## .. code-block:: nimrod - ## <>a(href="http://nimrod-code.org", newText("Nimrod rules.")) + ## .. code-block:: nim + ## <>a(href="http://nim-code.org", newText("Nim rules.")) ## ## Produces an XML tree for:: ## - ## <a href="http://nimrod-code.org">Nimrod rules.</a> + ## <a href="http://nim-code.org">Nim rules.</a> ## let x = callsite() result = xmlConstructor(x) -proc child*(n: PXmlNode, name: string): PXmlNode = +proc child*(n: XmlNode, name: string): XmlNode = ## Finds the first child element of `n` with a name of `name`. ## Returns `nil` on failure. assert n.kind == xnElement @@ -295,23 +298,23 @@ proc child*(n: PXmlNode, name: string): PXmlNode = if i.tag == name: return i -proc attr*(n: PXmlNode, name: string): string = +proc attr*(n: XmlNode, name: string): string = ## Finds the first attribute of `n` with a name of `name`. ## Returns "" on failure. assert n.kind == xnElement if n.attrs == nil: return "" return n.attrs[name] -proc findAll*(n: PXmlNode, tag: string, result: var seq[PXmlNode]) = +proc findAll*(n: XmlNode, tag: string, result: var seq[XmlNode]) = ## Iterates over all the children of `n` returning those matching `tag`. ## ## Found nodes satisfying the condition will be appended to the `result` ## sequence, which can't be nil or the proc will crash. Usage example: ## - ## .. code-block:: nimrod + ## .. code-block:: ## var - ## html: PXmlNode - ## tags: seq[PXmlNode] = @[] + ## html: XmlNode + ## tags: seq[XmlNode] = @[] ## ## html = buildHtml() ## findAll(html, "img", tags) @@ -327,11 +330,11 @@ proc findAll*(n: PXmlNode, tag: string, result: var seq[PXmlNode]) = elif child.k == xnElement: child.findAll(tag, result) -proc findAll*(n: PXmlNode, tag: string): seq[PXmlNode] = +proc findAll*(n: XmlNode, tag: string): seq[XmlNode] = ## Shortcut version to assign in let blocks. Example: ## - ## .. code-block:: nimrod - ## var html: PXmlNode + ## .. code-block:: + ## var html: XmlNode ## ## html = buildHtml(html) ## for imgTag in html.findAll("img"): @@ -340,5 +343,5 @@ proc findAll*(n: PXmlNode, tag: string): seq[PXmlNode] = findAll(n, tag, result) when isMainModule: - assert """<a href="http://nimrod-code.org">Nimrod rules.</a>""" == - $(<>a(href="http://nimrod-code.org", newText("Nimrod rules."))) + assert """<a href="http://nim-code.org">Nim rules.</a>""" == + $(<>a(href="http://nim-code.org", newText("Nim rules."))) diff --git a/lib/stdlib.babel b/lib/stdlib.nimble index f22598aba..0805ead54 100644 --- a/lib/stdlib.babel +++ b/lib/stdlib.nimble @@ -2,5 +2,5 @@ name = "stdlib" version = "0.9.0" author = "Dominik Picheta" -description = "Nimrod's standard library." +description = "Nim's standard library." license = "MIT" diff --git a/lib/system.nim b/lib/system.nim index 0df8849f5..da49386ed 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1,7 +1,7 @@ # # -# Nimrod's Runtime Library -# (c) Copyright 2013 Andreas Rumpf +# Nim's Runtime Library +# (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -77,44 +77,53 @@ type auto* = expr any* = distinct auto - TSignedInt* = int|int8|int16|int32|int64 + SomeSignedInt* = int|int8|int16|int32|int64 ## type class matching all signed integer types - TUnsignedInt* = uint|uint8|uint16|uint32|uint64 + SomeUnsignedInt* = uint|uint8|uint16|uint32|uint64 ## type class matching all unsigned integer types - TInteger* = TSignedInt|TUnsignedInt + SomeInteger* = SomeSignedInt|SomeUnsignedInt ## type class matching all integer types - TOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32 + SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32 ## type class matching all ordinal types; however this includes enums with ## holes. - TReal* = float|float32|float64 + SomeReal* = float|float32|float64 ## type class matching all floating point number types - TNumber* = TInteger|TReal + SomeNumber* = SomeInteger|SomeReal ## type class matching all number types proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.} ## Special compile-time procedure that checks whether `x` is ## defined. ## `x` is an external symbol introduced through the compiler's - ## `-d:x switch <nimrodc.html#compile-time-symbols>`_ to enable build time + ## `-d:x switch <nimc.html#compile-time-symbols>`_ to enable build time ## conditionals: ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## when not defined(release): ## # Do here programmer friendly expensive sanity checks. ## # Put here the normal code +when defined(nimalias): + {.deprecated: [ + TSignedInt: SomeSignedInt, + TUnsignedInt: SomeUnsignedInt, + TInteger: SomeInteger, + TReal: SomeReal, + TNumber: SomeNumber, + TOrdinal: SomeOrdinal].} + proc declared*(x: expr): bool {.magic: "Defined", noSideEffect.} ## Special compile-time procedure that checks whether `x` is ## declared. `x` has to be an identifier or a qualified identifier. ## This can be used to check whether a library provides a certain ## feature or not: ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## when not defined(strutils.toUpper): ## # provide our own toUpper proc here, because strutils is ## # missing it. @@ -183,6 +192,7 @@ proc high*[T](x: T): T {.magic: "High", noSideEffect.} ## returns the highest possible index of an array, a sequence, a string or ## the highest possible value of an ordinal value `x`. As a special ## semantic rule, `x` may also be a type identifier. + ## ``high(int)`` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:. proc low*[T](x: T): T {.magic: "Low", noSideEffect.} ## returns the lowest possible index of an array, a sequence, a string or @@ -202,10 +212,13 @@ type set*{.magic: "Set".}[T] ## Generic type to construct bit sets. type - TSlice* {.final, pure.}[T] = object ## builtin slice type - a*, b*: T ## the bounds + Slice* {.final, pure.}[T] = object ## builtin slice type + a*, b*: T ## the bounds + +when defined(nimalias): + {.deprecated: [TSlice: Slice].} -proc `..`*[T](a, b: T): TSlice[T] {.noSideEffect, inline.} = +proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline.} = ## `slice`:idx: operator that constructs an interval ``[a, b]``, both `a` ## and `b` are inclusive. Slices can also be used in the set constructor ## and in ordinal case statements, but then they are special-cased by the @@ -213,7 +226,7 @@ proc `..`*[T](a, b: T): TSlice[T] {.noSideEffect, inline.} = result.a = a result.b = b -proc `..`*[T](b: T): TSlice[T] {.noSideEffect, inline.} = +proc `..`*[T](b: T): Slice[T] {.noSideEffect, inline.} = ## `slice`:idx: operator that constructs an interval ``[default(T), b]`` result.b = b @@ -296,7 +309,7 @@ when not defined(JS) and not defined(NimrodVM): include "system/hti" type - Byte* = uint8 ## this is an alias for ``uint8``, that is an unsigned + byte* = uint8 ## this is an alias for ``uint8``, that is an unsigned ## int 8 bits wide. Natural* = range[0..high(int)] @@ -307,29 +320,29 @@ type ## is an int type ranging from one to the maximum value ## of an int. This type is often useful for documentation and debugging. - TObject* {.exportc: "TNimObject", inheritable.} = - object ## the root of Nimrod's object hierarchy. Objects should + RootObj* {.exportc: "TNimObject", inheritable.} = + object ## the root of Nim's object hierarchy. Objects should ## inherit from TObject or one of its descendants. However, ## objects that have no ancestor are allowed. - PObject* = ref TObject ## reference to TObject + RootRef* = ref RootObj ## reference to RootObj - TEffect* {.compilerproc.} = object of TObject ## \ + RootEffect* {.compilerproc.} = object of RootObj ## \ ## base effect class; each effect should ## inherit from `TEffect` unless you know what ## you doing. - FTime* = object of TEffect ## Time effect. - FIO* = object of TEffect ## IO effect. - FReadIO* = object of FIO ## Effect describing a read IO operation. - FWriteIO* = object of FIO ## Effect describing a write IO operation. - FExecIO* = object of FIO ## Effect describing an executing IO operation. + TimeEffect* = object of RootEffect ## Time effect. + IOEffect* = object of RootEffect ## IO effect. + ReadIOEffect* = object of IOEffect ## Effect describing a read IO operation. + WriteIOEffect* = object of IOEffect ## Effect describing a write IO operation. + ExecIOEffect* = object of IOEffect ## Effect describing an executing IO operation. - E_Base* {.compilerproc.} = object of TObject ## \ + Exception* {.compilerproc.} = object of RootObj ## \ ## Base exception class. ## - ## Each exception has to inherit from `E_Base`. See the full `exception + ## Each exception has to inherit from `Exception`. See the full `exception ## hierarchy`_. - parent: ref E_Base ## parent exception (can be used as a stack) - name: cstring ## The exception's name is its Nimrod identifier. + 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 @@ -337,143 +350,156 @@ type ## is bad style. trace: string - EAsynch* = object of E_Base ## \ - ## Abstract exception class for *asynchronous exceptions* (interrupts). - ## - ## This is rarely needed: most exception types inherit from `ESynch - ## <#ESynch>`_. See the full `exception hierarchy`_. - EControlC* = object of EAsynch ## \ - ## Raised for Ctrl+C key presses in console applications. - ## - ## See the full `exception hierarchy`_. - ESynch* = object of E_Base ## \ - ## Abstract exception class for *synchronous exceptions*. - ## - ## Most exceptions should be inherited (directly or indirectly) from - ## `ESynch` instead of from `EAsynch <#EAsynch>`_. See the full `exception - ## hierarchy`_. - ESystem* = object of ESynch ## \ + SystemError* = object of Exception ## \ ## Abstract class for exceptions that the runtime system raises. ## ## See the full `exception hierarchy`_. - EIO* = object of ESystem ## \ + IOError* = object of SystemError ## \ ## Raised if an IO error occured. ## ## See the full `exception hierarchy`_. - EOS* = object of ESystem ## \ + OSError* = object of SystemError ## \ ## Raised if an operating system service failed. ## ## See the full `exception hierarchy`_. errorCode*: int32 ## OS-defined error code describing this error. - EInvalidLibrary* = object of EOS ## \ + LibraryError* = object of OSError ## \ ## Raised if a dynamic library could not be loaded. ## ## See the full `exception hierarchy`_. - EResourceExhausted* = object of ESystem ## \ + ResourceExhaustedError* = object of SystemError ## \ ## Raised if a resource request could not be fullfilled. ## ## See the full `exception hierarchy`_. - EArithmetic* = object of ESynch ## \ + ArithmeticError* = object of Exception ## \ ## Raised if any kind of arithmetic error occured. ## ## See the full `exception hierarchy`_. - EDivByZero* {.compilerproc.} = object of EArithmetic ## \ + DivByZeroError* = object of ArithmeticError ## \ ## Raised for runtime integer divide-by-zero errors. ## ## See the full `exception hierarchy`_. - EOverflow* {.compilerproc.} = object of EArithmetic ## \ + + OverflowError* = object of ArithmeticError ## \ ## Raised for runtime integer overflows. ## ## This happens for calculations whose results are too large to fit in the ## provided bits. See the full `exception hierarchy`_. - EAccessViolation* {.compilerproc.} = object of ESynch ## \ + AccessViolationError* = object of Exception ## \ ## Raised for invalid memory access errors ## ## See the full `exception hierarchy`_. - EAssertionFailed* {.compilerproc.} = object of ESynch ## \ + AssertionError* = object of Exception ## \ ## Raised when assertion is proved wrong. ## ## Usually the result of using the `assert() template <#assert>`_. See the ## full `exception hierarchy`_. - EInvalidValue* = object of ESynch ## \ + ValueError* = object of Exception ## \ ## Raised for string and object conversion errors. - EInvalidKey* = object of EInvalidValue ## \ + KeyError* = object of ValueError ## \ ## Raised if a key cannot be found in a table. ## ## Mostly used by the `tables <tables.html>`_ module, it can also be raised ## by other collection modules like `sets <sets.html>`_ or `strtabs ## <strtabs.html>`_. See the full `exception hierarchy`_. - EOutOfMemory* = object of ESystem ## \ + OutOfMemError* = object of SystemError ## \ ## Raised for unsuccessful attempts to allocate memory. ## ## See the full `exception hierarchy`_. - EInvalidIndex* = object of ESynch ## \ + IndexError* = object of Exception ## \ ## Raised if an array index is out of bounds. ## ## See the full `exception hierarchy`_. - EInvalidField* = object of ESynch ## \ + + FieldError* = object of Exception ## \ ## Raised if a record field is not accessible because its dicriminant's ## value does not fit. ## ## See the full `exception hierarchy`_. - EOutOfRange* = object of ESynch ## \ + RangeError* = object of Exception ## \ ## Raised if a range check error occurred. ## ## See the full `exception hierarchy`_. - EStackOverflow* = object of ESystem ## \ + StackOverflowError* = object of SystemError ## \ ## Raised if the hardware stack used for subroutine calls overflowed. ## ## See the full `exception hierarchy`_. - ENoExceptionToReraise* = object of ESynch ## \ + ReraiseError* = object of Exception ## \ ## Raised if there is no exception to reraise. ## ## See the full `exception hierarchy`_. - EInvalidObjectAssignment* = object of ESynch ## \ + ObjectAssignmentError* = object of Exception ## \ ## Raised if an object gets assigned to its parent's object. ## ## See the full `exception hierarchy`_. - EInvalidObjectConversion* = object of ESynch ## \ + ObjectConversionError* = object of Exception ## \ ## Raised if an object is converted to an incompatible object type. ## ## See the full `exception hierarchy`_. - EFloatingPoint* = object of ESynch ## \ + FloatingPointError* = object of Exception ## \ ## Base class for floating point exceptions. ## ## See the full `exception hierarchy`_. - EFloatInvalidOp* {.compilerproc.} = object of EFloatingPoint ## \ + FloatInvalidOpError* = object of FloatingPointError ## \ ## Raised by invalid operations according to IEEE. ## ## Raised by ``0.0/0.0``, for example. See the full `exception ## hierarchy`_. - EFloatDivByZero* {.compilerproc.} = object of EFloatingPoint ## \ + FloatDivByZeroError* = object of FloatingPointError ## \ ## Raised by division by zero. ## ## Divisor is zero and dividend is a finite nonzero number. See the full ## `exception hierarchy`_. - EFloatOverflow* {.compilerproc.} = object of EFloatingPoint ## \ + FloatOverflowError* = object of FloatingPointError ## \ ## Raised for overflows. ## ## The operation produced a result that exceeds the range of the exponent. ## See the full `exception hierarchy`_. - EFloatUnderflow* {.compilerproc.} = object of EFloatingPoint ## \ + FloatUnderflowError* = object of FloatingPointError ## \ ## Raised for underflows. ## ## The operation produced a result that is too small to be represented as a ## normal number. See the full `exception hierarchy`_. - EFloatInexact* {.compilerproc.} = object of EFloatingPoint ## \ + FloatInexactError* = object of FloatingPointError ## \ ## Raised for inexact results. ## ## The operation produced a result that cannot be represented with infinite ## precision -- for example: ``2.0 / 3.0, log(1.1)`` ## - ## **NOTE**: Nimrod currently does not detect these! See the full + ## **NOTE**: Nim currently does not detect these! See the full ## `exception hierarchy`_. - EDeadThread* = object of ESynch ## \ + DeadThreadError* = object of Exception ## \ ## Raised if it is attempted to send a message to a dead thread. ## ## See the full `exception hierarchy`_. - TResult* = enum Failure, Success + TResult* {.deprecated.} = enum Failure, Success + +{.deprecated: [TObject: RootObj, PObject: RootRef, TEffect: RootEffect, + FTime: TimeEffect, FIO: IOEffect, FReadIO: ReadIOEffect, + FWriteIO: WriteIOEffect, FExecIO: ExecIOEffect, + + E_Base: Exception, ESystem: SystemError, EIO: IOError, + EOS: OSError, EInvalidLibrary: LibraryError, + EResourceExhausted: ResourceExhaustedError, + EArithmetic: ArithmeticError, EDivByZero: DivByZeroError, + EOverflow: OverflowError, EAccessViolation: AccessViolationError, + EAssertionFailed: AssertionError, EInvalidValue: ValueError, + EInvalidKey: KeyError, EOutOfMemory: OutOfMemError, + EInvalidIndex: IndexError, EInvalidField: FieldError, + EOutOfRange: RangeError, EStackOverflow: StackOverflowError, + ENoExceptionToReraise: ReraiseError, + EInvalidObjectAssignment: ObjectAssignmentError, + EInvalidObjectConversion: ObjectConversionError, + EDeadThread: DeadThreadError, + EFloatInexact: FloatInexactError, + EFloatUnderflow: FloatUnderflowError, + EFloatingPoint: FloatingPointError, + EFloatInvalidOp: FloatInvalidOpError, + EFloatDivByZero: FloatDivByZeroError, + EFloatOverflow: FloatOverflowError, + ESynch: Exception +].} proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.} ## returns the size of ``x`` in bytes. Since this is a low-level proc, @@ -484,7 +510,7 @@ proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.} proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.} ## unary ``<`` that can be used for nice looking excluding ranges: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for i in 0 .. <10: echo i ## ## Semantically this is the same as ``pred``. @@ -519,7 +545,7 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.} ## ``nil``. After the creation of the sequence you should assign entries to ## the sequence instead of adding them. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var inputStrings : seq[string] ## newSeq(inputStrings, 3) ## inputStrings[0] = "The fourth" @@ -535,7 +561,7 @@ proc newSeq*[T](len = 0): seq[T] = ## ``nil``. After the creation of the sequence you should assign entries to ## the sequence instead of adding them. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var inputStrings = newSeq[string](3) ## inputStrings[0] = "The fourth" ## inputStrings[1] = "assignment" @@ -666,7 +692,7 @@ proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.} ## computes the integer division. This is roughly the same as ## ``floor(x/y)``. - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## 1 div 2 == 0 ## 2 div 2 == 1 ## 3 div 2 == 1 @@ -685,7 +711,7 @@ proc `shr` *(x, y: int16): int16 {.magic: "ShrI", noSideEffect.} proc `shr` *(x, y: int32): int32 {.magic: "ShrI", noSideEffect.} proc `shr` *(x, y: int64): int64 {.magic: "ShrI64", noSideEffect.} ## computes the `shift right` operation of `x` and `y`. - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## 0b0001_0000'i8 shr 2 == 0b0100_0000'i8 ## 0b1000_0000'i8 shr 2 == 0b0000_0000'i8 ## 0b0000_0001'i8 shr 9 == 0b0000_0000'i8 @@ -824,12 +850,12 @@ proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} ## One should overload this proc if one wants to overload the ``in`` operator. ## The parameters are in reverse order! ``a in b`` is a template for ## ``contains(b, a)``. - ## This is because the unification algorithm that Nimrod uses for overload + ## This is because the unification algorithm that Nim uses for overload ## resolution works from left to right. ## But for the ``in`` operator that would be the wrong direction for this ## piece of code: ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## var s: set[range['a'..'z']] = {'a'..'c'} ## writeln(stdout, 'b' in s) ## @@ -839,11 +865,11 @@ proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} ## is achieved by reversing the parameters for ``contains``; ``in`` then ## passes its arguments in reverse order. -proc contains*[T](s: TSlice[T], value: T): bool {.noSideEffect, inline.} = +proc contains*[T](s: Slice[T], value: T): bool {.noSideEffect, inline.} = ## Checks if `value` is withing the range of `s`; returns true iff ## `value >= s.a and value <= s.b` ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert((1..3).contains(1) == true) ## assert((1..3).contains(2) == true) ## assert((1..3).contains(4) == false) @@ -852,20 +878,20 @@ proc contains*[T](s: TSlice[T], value: T): bool {.noSideEffect, inline.} = template `in` * (x, y: expr): expr {.immediate, dirty.} = contains(y, x) ## Sugar for contains ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert(1 in (1..3) == true) ## assert(5 in (1..3) == false) template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x) ## Sugar for not containing ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert(1 notin (1..3) == false) ## assert(5 notin (1..3) == true) proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} ## Checks if T is of the same type as S ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## proc test[T](a: T): int = ## when (T is int): ## return a @@ -880,7 +906,7 @@ template `isnot` *(x, y: expr): expr {.immediate.} = not (x is y) proc `of` *[T, S](x: T, y: S): bool {.magic: "Of", noSideEffect.} ## Checks if `x` has a type of `y` ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert(EFloatingPoint of EBase) ## assert(EIO of ESystem) ## assert(EDivByZero of EBase) @@ -936,25 +962,25 @@ proc `&` * (x: string, y: char): string {. magic: "ConStrStr", noSideEffect, merge.} ## Concatenates `x` with `y` ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert("ab" & 'c' == "abc") proc `&` * (x: char, y: char): string {. magic: "ConStrStr", noSideEffect, merge.} ## Concatenates `x` and `y` into a string ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert('a' & 'b' == "ab") proc `&` * (x, y: string): string {. magic: "ConStrStr", noSideEffect, merge.} ## Concatenates `x` and `y` ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert("ab" & "cd" == "abcd") proc `&` * (x: char, y: string): string {. magic: "ConStrStr", noSideEffect, merge.} ## Concatenates `x` with `y` ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert('a' & "bc" == "abc") # implementation note: These must all have the same magic value "ConStrStr" so @@ -963,7 +989,7 @@ proc `&` * (x: char, y: string): string {. proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} ## Appends `y` to `x` in place ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## var tmp = "" ## tmp.add('a') ## tmp.add('b') @@ -971,14 +997,14 @@ proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} ## Concatenates `x` and `y` in place ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## var tmp = "" ## tmp.add("ab") ## tmp.add("cd") ## assert(tmp == "abcd") type - TEndian* = enum ## is a type describing the endianness of a processor. + Endianness* = enum ## is a type describing the endianness of a processor. littleEndian, bigEndian const @@ -994,23 +1020,23 @@ const ## is the time of compilation as a string of the form ## ``HH:MM:SS``. This works thanks to compiler magic. - NimrodVersion* {.magic: "NimrodVersion"}: string = "0.0.0" - ## is the version of Nimrod as a string. + NimVersion* {.magic: "NimrodVersion"}: string = "0.0.0" + ## is the version of Nim as a string. ## This works thanks to compiler magic. - NimrodMajor* {.magic: "NimrodMajor"}: int = 0 - ## is the major number of Nimrod's version. + NimMajor* {.magic: "NimrodMajor"}: int = 0 + ## is the major number of Nim's version. ## This works thanks to compiler magic. - NimrodMinor* {.magic: "NimrodMinor"}: int = 0 - ## is the minor number of Nimrod's version. + NimMinor* {.magic: "NimrodMinor"}: int = 0 + ## is the minor number of Nim's version. ## This works thanks to compiler magic. - NimrodPatch* {.magic: "NimrodPatch"}: int = 0 - ## is the patch number of Nimrod's version. + NimPatch* {.magic: "NimrodPatch"}: int = 0 + ## is the patch number of Nim's version. ## This works thanks to compiler magic. - cpuEndian* {.magic: "CpuEndian"}: TEndian = littleEndian + cpuEndian* {.magic: "CpuEndian"}: Endianness = littleEndian ## is the endianness of the target CPU. This is a valuable piece of ## information for low-level code only. This works thanks to compiler ## magic. @@ -1025,12 +1051,15 @@ const ## "i386", "alpha", "powerpc", "sparc", "amd64", "mips", "arm". seqShallowFlag = low(int) - + +{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion, + NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].} + proc compileOption*(option: string): bool {. magic: "CompileOption", noSideEffect.} ## can be used to determine an on|off compile-time option. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## when compileOption("floatchecks"): ## echo "compiled with floating point NaN and Inf checks" @@ -1038,7 +1067,7 @@ proc compileOption*(option, arg: string): bool {. magic: "CompileOptionArg", noSideEffect.} ## can be used to determine an enum compile-time option. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## when compileOption("opt", "size") and compileOption("gc", "boehm"): ## echo "compiled with optimization for size and uses Boehm's GC" @@ -1095,7 +1124,7 @@ proc quit*(errorcode: int = QuitSuccess) {. ## procedures. It does *not* call the garbage collector to free all the ## memory, unless a quit procedure calls ``GC_collect``. ## - ## The proc ``quit(QuitSuccess)`` is called implicitly when your nimrod + ## The proc ``quit(QuitSuccess)`` is called implicitly when your nim ## program finishes without incident. A raised unhandled exception is ## equivalent to calling ``quit(QuitFailure)``. ## @@ -1117,7 +1146,7 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = ## Generic proc for adding a data item `y` to a container `x`. ## For containers that have an order, `add` means *append*. New generic ## containers should also call their adding proc `add` for consistency. - ## Generic code becomes much easier to write if the Nimrod naming scheme is + ## Generic code becomes much easier to write if the Nim naming scheme is ## respected. let xl = x.len setLen(x, xl + y.len) @@ -1155,25 +1184,27 @@ proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} = x[i] = item proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.} - ## takes any Nimrod variable and returns its string representation. It + ## takes any Nim variable and returns its string representation. It ## works even for complex data graphs with cycles. This is a great ## debugging tool. type - TAddress* = int + ByteAddress* = int ## is the signed integer type that should be used for converting ## pointers to integer addresses for readability. BiggestInt* = int64 - ## is an alias for the biggest signed integer type the Nimrod compiler + ## is an alias for the biggest signed integer type the Nim compiler ## supports. Currently this is ``int64``, but it is platform-dependant ## in general. BiggestFloat* = float64 - ## is an alias for the biggest floating point type the Nimrod + ## is an alias for the biggest floating point type the Nim ## compiler supports. Currently this is ``float64``, but it is ## platform-dependant in general. +{.deprecated: [TAddress: ByteAddress].} + when defined(windows): type clong* {.importc: "long", nodecl.} = int32 @@ -1206,7 +1237,7 @@ type # these work for most platforms: ## This is the same as the type ``double`` in *C*. clongdouble* {.importc: "long double", nodecl.} = BiggestFloat ## This is the same as the type ``long double`` in *C*. - ## This C type is not supported by Nimrod's code generator + ## This C type is not supported by Nim's code generator cuchar* {.importc: "unsigned char", nodecl.} = char ## This is the same as the type ``unsigned char`` in *C*. @@ -1560,7 +1591,7 @@ iterator `||`*[S, T](a: S, b: T, annotation=""): T {. ## Note that the compiler maps that to ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as ## such isn't aware of the parallelism in your code! Be careful! Later - ## versions of ``||`` will get proper support by Nimrod's code generator + ## versions of ``||`` will get proper support by Nim's code generator ## and GC. discard @@ -1612,7 +1643,7 @@ proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.} = proc clamp*[T](x, a, b: T): T = ## limits the value ``x`` within the interval [a, b] ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert((1.4).clamp(0.0, 1.0) == 1.0) ## assert((0.5).clamp(0.0, 1.0) == 0.5) if x < a: return a @@ -1716,7 +1747,7 @@ proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect.} = ## Concatenates two sequences. ## Requires copying of the sequences. ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) newSeq(result, x.len + y.len) for i in 0..x.len-1: @@ -1728,7 +1759,7 @@ proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect.} = ## Appends element y to the end of the sequence. ## Requires copying of the sequence ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) newSeq(result, x.len + 1) for i in 0..x.len-1: @@ -1739,7 +1770,7 @@ proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} = ## Prepends the element x to the beginning of the sequence. ## Requires copying of the sequence ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) newSeq(result, y.len + 1) result[0] = x @@ -1810,7 +1841,7 @@ proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] = ## Since the input is not modified you can use this version of ``map`` to ## transform the type of the elements in the input sequence. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## let ## a = @[1, 2, 3, 4] ## b = map(a, proc(x: int): string = $x) @@ -1824,7 +1855,7 @@ proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) = ## Note that this version of ``map`` requires your input and output types to ## be the same, since they are modified in-place. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var a = @["1", "2", "3", "4"] ## echo repr(a) ## # --> ["1", "2", "3", "4"] @@ -1833,7 +1864,7 @@ proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) = ## # --> ["142", "242", "342", "442"] for i in 0..data.len-1: op(data[i]) -iterator fields*[T: tuple|object](x: T): TObject {. +iterator fields*[T: tuple|object](x: T): RootObj {. magic: "Fields", noSideEffect.} ## iterates over every field of `x`. Warning: This really transforms ## the 'for' and unrolls the loop. The current implementation also has a bug @@ -1844,7 +1875,7 @@ iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] { ## Warning: This is really transforms the 'for' and unrolls the loop. ## The current implementation also has a bug that affects symbol binding ## in the loop body. -iterator fieldPairs*[T: tuple|object](x: T): TObject {. +iterator fieldPairs*[T: tuple|object](x: T): RootObj {. magic: "FieldPairs", noSideEffect.} ## Iterates over every field of `x` returning their name and value. ## @@ -1853,7 +1884,7 @@ iterator fieldPairs*[T: tuple|object](x: T): TObject {. ## you want to run for each type. To perform the comparison use the `is ## operator <manual.html#is-operator>`_. Example: ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## ## type ## Custom = object @@ -1915,7 +1946,7 @@ proc `$`*[T: tuple|object](x: T): string = ## generic ``$`` operator for tuples that is lifted from the components ## of `x`. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## $(23, 45) == "(23, 45)" ## $() == "()" result = "(" @@ -1941,7 +1972,7 @@ proc `$`*[T](x: set[T]): string = ## generic ``$`` operator for sets that is lifted from the components ## of `x`. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ${23, 45} == "{23, 45}" collectionToString(x, "{", "}") @@ -1949,7 +1980,7 @@ proc `$`*[T](x: seq[T]): string = ## generic ``$`` operator for seqs that is lifted from the components ## of `x`. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## $(@[23, 45]) == "@[23, 45]" collectionToString(x, "@[", "]") @@ -1975,13 +2006,15 @@ when not defined(nimrodVM) and hostOS != "standalone": ## Ordinary code does not need to call this (and should not). type - TGC_Strategy* = enum ## the strategy the GC should use for the application + GC_Strategy* = enum ## the strategy the GC should use for the application gcThroughput, ## optimize for throughput gcResponsiveness, ## optimize for responsiveness (default) gcOptimizeTime, ## optimize for speed gcOptimizeSpace ## optimize for memory footprint - proc GC_setStrategy*(strategy: TGC_Strategy) {.rtl, deprecated.} + {.deprecated: [TGC_Strategy: GC_Strategy].} + + proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated.} ## tells the GC the desired strategy for the application. ## **Deprecated** since version 0.8.14. This has always been a nop. @@ -2015,7 +2048,7 @@ template accumulateResult*(iter: expr) = for x in iter: add(result, x) # we have to compute this here before turning it off in except.nim anyway ... -const nimrodStackTrace = compileOption("stacktrace") +const NimStackTrace = compileOption("stacktrace") {.push checks: off.} # obviously we cannot generate checking operations here :-) @@ -2024,7 +2057,7 @@ const nimrodStackTrace = compileOption("stacktrace") # of the code var - globalRaiseHook*: proc (e: ref E_Base): bool {.nimcall, gcsafe.} + globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, gcsafe.} ## with this hook you can influence exception handling on a global level. ## If not nil, every 'raise' statement ends up calling this hook. Ordinary ## application code should never set this hook! You better know what you @@ -2032,7 +2065,7 @@ var ## exception is caught and does not propagate further through the call ## stack. - localRaiseHook* {.threadvar.}: proc (e: ref E_Base): bool {.nimcall, gcsafe.} + localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, gcsafe.} ## with this hook you can influence exception handling on a ## thread local level. ## If not nil, every 'raise' statement ends up calling this hook. Ordinary @@ -2046,7 +2079,7 @@ var ## writes an error message and terminates the program. `outOfMemHook` can ## be used to raise an exception in case of OOM like so: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## var gOutOfMem: ref EOutOfMemory ## new(gOutOfMem) # need to be allocated *before* OOM really happened! @@ -2092,7 +2125,7 @@ elif hostOS != "standalone": inc(i) {.pop.} -proc echo*[T](x: varargs[T, `$`]) {.magic: "Echo", tags: [FWriteIO], gcsafe.} +proc echo*[T](x: varargs[T, `$`]) {.magic: "Echo", tags: [WriteIOEffect], gcsafe.} ## Writes and flushes the parameters to the standard output. ## ## Special built-in that takes a variable number of arguments. Each argument @@ -2224,9 +2257,9 @@ when not defined(JS): #and not defined(NimrodVM): type CFile {.importc: "FILE", header: "<stdio.h>", final, incompletestruct.} = object - TFile* = ptr CFile ## The type representing a file handle. + File* = ptr CFile ## The type representing a file handle. - TFileMode* = enum ## The file mode when opening a file. + FileMode* = enum ## The file mode when opening a file. fmRead, ## Open the file for read access only. fmWrite, ## Open the file for write access only. fmReadWrite, ## Open the file for read and write access. @@ -2238,49 +2271,51 @@ when not defined(JS): #and not defined(NimrodVM): fmAppend ## Open the file for writing only; append data ## at the end. - TFileHandle* = cint ## type that represents an OS file handle; this is - ## useful for low-level file access + FileHandle* = cint ## type that represents an OS file handle; this is + ## useful for low-level file access + + {.deprecated: [TFile: File, TFileHandle: FileHandle, TFileMode: FileMode].} # text file handling: var - stdin* {.importc: "stdin", header: "<stdio.h>".}: TFile + stdin* {.importc: "stdin", header: "<stdio.h>".}: File ## The standard input stream. - stdout* {.importc: "stdout", header: "<stdio.h>".}: TFile + stdout* {.importc: "stdout", header: "<stdio.h>".}: File ## The standard output stream. - stderr* {.importc: "stderr", header: "<stdio.h>".}: TFile + stderr* {.importc: "stderr", header: "<stdio.h>".}: File ## The standard error stream. when defined(useStdoutAsStdmsg): - template stdmsg*: TFile = stdout + template stdmsg*: File = stdout else: - template stdmsg*: TFile = stderr + template stdmsg*: File = stderr ## Template which expands to either stdout or stderr depending on ## `useStdoutAsStdmsg` compile-time switch. - proc open*(f: var TFile, filename: string, - mode: TFileMode = fmRead, bufSize: int = -1): bool {.tags: [], + proc open*(f: var File, filename: string, + mode: FileMode = fmRead, bufSize: int = -1): bool {.tags: [], gcsafe.} ## Opens a file named `filename` with given `mode`. ## ## Default mode is readonly. Returns true iff the file could be opened. ## This throws no exception if the file could not be opened. - proc open*(f: var TFile, filehandle: TFileHandle, - mode: TFileMode = fmRead): bool {.tags: [], gcsafe.} + proc open*(f: var File, filehandle: FileHandle, + mode: FileMode = fmRead): bool {.tags: [], gcsafe.} ## Creates a ``TFile`` from a `filehandle` with given `mode`. ## ## Default mode is readonly. Returns true iff the file could be opened. proc open*(filename: string, - mode: TFileMode = fmRead, bufSize: int = -1): TFile = + mode: FileMode = fmRead, bufSize: int = -1): File = ## Opens a file named `filename` with given `mode`. ## ## Default mode is readonly. Raises an ``IO`` exception if the file ## could not be opened. if not open(result, filename, mode, bufSize): - sysFatal(EIO, "cannot open: ", filename) + sysFatal(IOError, "cannot open: ", filename) - proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool {. + proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {. tags: [], gcsafe.} ## reopens the file `f` with given `filename` and `mode`. This ## is often used to redirect the `stdin`, `stdout` or `stderr` @@ -2288,52 +2323,52 @@ when not defined(JS): #and not defined(NimrodVM): ## ## Default mode is readonly. Returns true iff the file could be reopened. - proc close*(f: TFile) {.importc: "fclose", header: "<stdio.h>", tags: [].} + proc close*(f: File) {.importc: "fclose", header: "<stdio.h>", tags: [].} ## Closes the file. - proc endOfFile*(f: TFile): bool {.tags: [], gcsafe.} + proc endOfFile*(f: File): bool {.tags: [], gcsafe.} ## Returns true iff `f` is at the end. - proc readChar*(f: TFile): char {. - importc: "fgetc", header: "<stdio.h>", tags: [FReadIO].} + proc readChar*(f: File): char {. + importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].} ## Reads a single character from the stream `f`. - proc flushFile*(f: TFile) {. - importc: "fflush", header: "<stdio.h>", tags: [FWriteIO].} + proc flushFile*(f: File) {. + importc: "fflush", header: "<stdio.h>", tags: [WriteIOEffect].} ## Flushes `f`'s buffer. - proc readAll*(file: TFile): TaintedString {.tags: [FReadIO], gcsafe.} + proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], gcsafe.} ## Reads all data from the stream `file`. ## ## Raises an IO exception in case of an error. It is an error if the ## current file position is not at the beginning of the file. - proc readFile*(filename: string): TaintedString {.tags: [FReadIO], gcsafe.} + proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], gcsafe.} ## Opens a file named `filename` for reading. Then calls `readAll` ## and closes the file afterwards. Returns the string. ## Raises an IO exception in case of an error. - proc writeFile*(filename, content: string) {.tags: [FWriteIO], gcsafe.} + proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], gcsafe.} ## Opens a file named `filename` for writing. Then writes the ## `content` completely to the file and closes the file afterwards. ## Raises an IO exception in case of an error. - proc write*(f: TFile, r: float32) {.tags: [FWriteIO], gcsafe.} - proc write*(f: TFile, i: int) {.tags: [FWriteIO], gcsafe.} - proc write*(f: TFile, i: BiggestInt) {.tags: [FWriteIO], gcsafe.} - proc write*(f: TFile, r: BiggestFloat) {.tags: [FWriteIO], gcsafe.} - proc write*(f: TFile, s: string) {.tags: [FWriteIO], gcsafe.} - proc write*(f: TFile, b: bool) {.tags: [FWriteIO], gcsafe.} - proc write*(f: TFile, c: char) {.tags: [FWriteIO], gcsafe.} - proc write*(f: TFile, c: cstring) {.tags: [FWriteIO], gcsafe.} - proc write*(f: TFile, a: varargs[string, `$`]) {.tags: [FWriteIO], gcsafe.} + proc write*(f: File, r: float32) {.tags: [WriteIOEffect], gcsafe.} + proc write*(f: File, i: int) {.tags: [WriteIOEffect], gcsafe.} + proc write*(f: File, i: BiggestInt) {.tags: [WriteIOEffect], gcsafe.} + proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], gcsafe.} + proc write*(f: File, s: string) {.tags: [WriteIOEffect], gcsafe.} + proc write*(f: File, b: bool) {.tags: [WriteIOEffect], gcsafe.} + proc write*(f: File, c: char) {.tags: [WriteIOEffect], gcsafe.} + proc write*(f: File, c: cstring) {.tags: [WriteIOEffect], gcsafe.} + proc write*(f: File, a: varargs[string, `$`]) {.tags: [WriteIOEffect], gcsafe.} ## Writes a value to the file `f`. May throw an IO exception. - proc readLine*(f: TFile): TaintedString {.tags: [FReadIO], gcsafe.} + proc readLine*(f: File): TaintedString {.tags: [ReadIOEffect], gcsafe.} ## reads a line of text from the file `f`. May throw an IO exception. ## A line of text may be delimited by ``CR``, ``LF`` or ## ``CRLF``. The newline character(s) are not part of the returned string. - proc readLine*(f: TFile, line: var TaintedString): bool {.tags: [FReadIO], + proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], gcsafe.} ## reads a line of text from the file `f` into `line`. `line` must not be ## ``nil``! May throw an IO exception. @@ -2343,66 +2378,69 @@ when not defined(JS): #and not defined(NimrodVM): ## otherwise. If ``false`` is returned `line` contains no new data. when not defined(booting): - proc writeln*[Ty](f: TFile, x: varargs[Ty, `$`]) {.inline, - tags: [FWriteIO], gcsafe.} + proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, + tags: [WriteIOEffect], gcsafe.} ## writes the values `x` to `f` and then writes "\n". ## May throw an IO exception. else: - proc writeln*[Ty](f: TFile, x: varargs[Ty, `$`]) {.inline, - tags: [FWriteIO].} + proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, + tags: [WriteIOEffect].} - proc getFileSize*(f: TFile): int64 {.tags: [FReadIO], gcsafe.} + proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], gcsafe.} ## retrieves the file size (in bytes) of `f`. - proc readBytes*(f: TFile, a: var openArray[int8], start, len: int): int {. - tags: [FReadIO], gcsafe.} + proc readBytes*(f: File, a: var openArray[int8], start, len: int): int {. + tags: [ReadIOEffect], gcsafe.} ## 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 ## `len` (if not as many bytes are remaining), but not greater. - proc readChars*(f: TFile, a: var openArray[char], start, len: int): int {. - tags: [FReadIO], gcsafe.} + proc readChars*(f: File, a: var openArray[char], start, len: int): int {. + tags: [ReadIOEffect], gcsafe.} ## 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 ## `len` (if not as many bytes are remaining), but not greater. - proc readBuffer*(f: TFile, buffer: pointer, len: int): int {. - tags: [FReadIO], gcsafe.} + proc readBuffer*(f: File, buffer: pointer, len: int): int {. + tags: [ReadIOEffect], gcsafe.} ## reads `len` bytes into the buffer pointed to by `buffer`. Returns ## 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: TFile, a: openArray[int8], start, len: int): int {. - tags: [FWriteIO], gcsafe.} + proc writeBytes*(f: File, a: openArray[int8], start, len: int): int {. + tags: [WriteIOEffect], gcsafe.} ## 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 ## of an error. - proc writeChars*(f: TFile, a: openArray[char], start, len: int): int {. - tags: [FWriteIO], gcsafe.} + proc writeChars*(f: File, a: openArray[char], start, len: int): int {. + tags: [WriteIOEffect], gcsafe.} ## 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 ## of an error. - proc writeBuffer*(f: TFile, buffer: pointer, len: int): int {. - tags: [FWriteIO], gcsafe.} + proc writeBuffer*(f: File, buffer: pointer, len: int): int {. + tags: [WriteIOEffect], gcsafe.} ## writes the bytes of buffer pointed to by the parameter `buffer` to the ## file `f`. Returns the number of actual written bytes, which may be less ## than `len` in case of an error. - proc setFilePos*(f: TFile, pos: int64) {.gcsafe.} + proc setFilePos*(f: File, pos: int64) {.gcsafe.} ## sets the position of the file pointer that is used for read/write ## operations. The file's first byte has the index zero. - proc getFilePos*(f: TFile): int64 {.gcsafe.} + proc getFilePos*(f: File): int64 {.gcsafe.} ## retrieves the current position of the file pointer that is used to ## read from the file `f`. The file's first byte has the index zero. - proc fileHandle*(f: TFile): TFileHandle {.importc: "fileno", - header: "<stdio.h>"} + proc getFileHandle*(f: File): FileHandle {.importc: "fileno", + header: "<stdio.h>"} ## returns the OS file handle of the file ``f``. This is only useful for ## platform specific programming. + when not defined(nimfix): + {.deprecated: [fileHandle: getFileHandle].} + proc cstringArrayToSeq*(a: cstringArray, len: int): seq[string] = ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be ## of length ``len``. @@ -2454,7 +2492,7 @@ when not defined(JS): #and not defined(NimrodVM): status: int context: C_JmpBuf hasRaiseAction: bool - raiseAction: proc (e: ref E_Base): bool {.closure.} + raiseAction: proc (e: ref Exception): bool {.closure.} when declared(initAllocator): initAllocator() @@ -2470,14 +2508,14 @@ when not defined(JS): #and not defined(NimrodVM): ## allows you to override the behaviour of your application when CTRL+C ## is pressed. Only one such hook is supported. - proc writeStackTrace*() {.tags: [FWriteIO].} + proc writeStackTrace*() {.tags: [WriteIOEffect].} ## writes the current stack trace to ``stderr``. This is only works ## for debug builds. when hostOS != "standalone": proc getStackTrace*(): string ## gets the current stack trace. This only works for debug builds. - proc getStackTrace*(e: ref E_Base): string + proc getStackTrace*(e: ref Exception): string ## gets the stack trace associated with `e`, which is the stack that ## lead to the ``raise`` statement. This only works for debug builds. @@ -2505,7 +2543,7 @@ when not defined(JS): #and not defined(NimrodVM): proc getDiscriminant(aa: pointer, n: ptr TNimNode): int = sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") var d: int - var a = cast[TAddress](aa) + var a = cast[ByteAddress](aa) case n.typ.size of 1: d = ze(cast[ptr int8](a +% n.offset)[]) of 2: d = ze(cast[ptr int16](a +% n.offset)[]) @@ -2534,13 +2572,13 @@ when not defined(JS): #and not defined(NimrodVM): include "system/sysio" when hostOS != "standalone": - iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} = + iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} = ## Iterates over any line in the file named `filename`. ## ## If the file does not exist `EIO` is raised. The trailing newline ## character(s) are removed from the iterated lines. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## import strutils ## ## proc transformLetters(filename: string) = @@ -2553,14 +2591,14 @@ when not defined(JS): #and not defined(NimrodVM): while f.readLine(res): yield res close(f) - iterator lines*(f: TFile): TaintedString {.tags: [FReadIO].} = + iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} = ## Iterate over any line in the file `f`. ## ## The trailing newline character(s) are removed from the iterated lines. ## Example: ## - ## .. code-block:: nimrod - ## proc countZeros(filename: TFile): tuple[lines, zeros: int] = + ## .. code-block:: nim + ## proc countZeros(filename: File): tuple[lines, zeros: int] = ## for line in filename.lines: ## for letter in line: ## if letter == '0': @@ -2573,7 +2611,7 @@ when not defined(JS): #and not defined(NimrodVM): include "system/assign" include "system/repr" - proc getCurrentException*(): ref E_Base {.compilerRtl, inl, gcsafe.} = + proc getCurrentException*(): ref Exception {.compilerRtl, inl, gcsafe.} = ## retrieves the current exception; if there is none, nil is returned. result = currException @@ -2583,7 +2621,7 @@ when not defined(JS): #and not defined(NimrodVM): var e = getCurrentException() return if e == nil: "" else: e.msg - proc onRaise*(action: proc(e: ref E_Base): bool{.closure.}) = + proc onRaise*(action: proc(e: ref Exception): bool{.closure.}) = ## can be used in a ``try`` statement to setup a Lisp-like ## `condition system`:idx:\: This prevents the 'raise' statement to ## raise an exception but instead calls ``action``. @@ -2593,6 +2631,12 @@ when not defined(JS): #and not defined(NimrodVM): excHandler.hasRaiseAction = true excHandler.raiseAction = action + proc setCurrentException*(exc: ref Exception) {.inline, gcsafe.} = + ## sets the current exception. + ## + ## **Warning**: Only use this if you know what you are doing. + currException = exc + {.push stack_trace: off, profiler:off.} when defined(endb) and not defined(NimrodVM): include "system/debugger" @@ -2609,7 +2653,7 @@ when not defined(JS): #and not defined(NimrodVM): ## platforms this can help the processor predict better which branch is ## going to be run. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for value in inputValues: ## if likely(value <= 100): ## process(value) @@ -2623,7 +2667,7 @@ when not defined(JS): #and not defined(NimrodVM): ## platforms this can help the processor predict better which branch is ## going to be run. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for value in inputValues: ## if unlikely(value > 100): ## echo "Value too big!" @@ -2657,7 +2701,7 @@ elif defined(JS): proc GC_disable() = discard proc GC_enable() = discard proc GC_fullCollect() = discard - proc GC_setStrategy(strategy: TGC_Strategy) = discard + proc GC_setStrategy(strategy: GC_Strategy) = discard proc GC_enableMarkAndSweep() = discard proc GC_disableMarkAndSweep() = discard proc GC_getStatistics(): string = return "" @@ -2669,7 +2713,7 @@ elif defined(JS): proc dealloc(p: pointer) = discard proc alloc(size: int): pointer = discard proc alloc0(size: int): pointer = discard - proc realloc(p: Pointer, newsize: int): pointer = discard + proc realloc(p: pointer, newsize: int): pointer = discard proc allocShared(size: int): pointer = discard proc allocShared0(size: int): pointer = discard @@ -2721,16 +2765,16 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} = for i in 0 .. <b.len: s[i+a] = b[i] when hostOS != "standalone": - proc `[]`*(s: string, x: TSlice[int]): string {.inline.} = + proc `[]`*(s: string, x: Slice[int]): string {.inline.} = ## slice operation for strings. Negative indexes are supported. result = s.substr(x.a-|s, x.b-|s) - proc `[]=`*(s: var string, x: TSlice[int], b: string) = + proc `[]=`*(s: var string, x: Slice[int], b: string) = ## slice assignment for strings. Negative indexes are supported. If ## ``b.len`` is not exactly the number of elements that are referred to ## by `x`, a `splice`:idx: is performed: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## var s = "abcdef" ## s[1 .. -2] = "xyz" ## assert s == "axyzf" @@ -2741,7 +2785,7 @@ when hostOS != "standalone": else: spliceImpl(s, a, L, b) -proc `[]`*[Idx, T](a: array[Idx, T], x: TSlice[int]): seq[T] = +proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] = ## slice operation for arrays. Negative indexes are **not** supported ## because the array might have negative bounds. when low(a) < 0: @@ -2750,7 +2794,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: TSlice[int]): seq[T] = newSeq(result, L) for i in 0.. <L: result[i] = a[i + x.a] -proc `[]=`*[Idx, T](a: var array[Idx, T], x: TSlice[int], b: openArray[T]) = +proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) = ## slice assignment for arrays. Negative indexes are **not** supported ## because the array might have negative bounds. when low(a) < 0: @@ -2759,9 +2803,9 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: TSlice[int], b: openArray[T]) = if L == b.len: for i in 0 .. <L: a[i+x.a] = b[i] else: - sysFatal(EOutOfRange, "different lengths for slice assignment") + sysFatal(RangeError, "different lengths for slice assignment") -proc `[]`*[Idx, T](a: array[Idx, T], x: TSlice[Idx]): seq[T] = +proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] = ## slice operation for arrays. Negative indexes are **not** supported ## because the array might have negative bounds. var L = ord(x.b) - ord(x.a) + 1 @@ -2771,7 +2815,7 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: TSlice[Idx]): seq[T] = result[i] = a[j] inc(j) -proc `[]=`*[Idx, T](a: var array[Idx, T], x: TSlice[Idx], b: openArray[T]) = +proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) = ## slice assignment for arrays. Negative indexes are **not** supported ## because the array might have negative bounds. var L = ord(x.b) - ord(x.a) + 1 @@ -2781,16 +2825,16 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: TSlice[Idx], b: openArray[T]) = a[j] = b[i] inc(j) else: - sysFatal(EOutOfRange, "different lengths for slice assignment") + sysFatal(RangeError, "different lengths for slice assignment") -proc `[]`*[T](s: seq[T], x: TSlice[int]): seq[T] = +proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] = ## slice operation for sequences. Negative indexes are supported. var a = x.a-|s var L = x.b-|s - a + 1 newSeq(result, L) for i in 0.. <L: result[i] = s[i + a] -proc `[]=`*[T](s: var seq[T], x: TSlice[int], b: openArray[T]) = +proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) = ## slice assignment for sequences. Negative indexes are supported. If ## ``b.len`` is not exactly the number of elements that are referred to ## by `x`, a `splice`:idx: is performed. @@ -2807,7 +2851,7 @@ proc slurp*(filename: string): string {.magic: "Slurp".} proc staticRead*(filename: string): string {.magic: "Slurp".} ## Compile-time ``readFile`` proc for easy `resource`:idx: embedding: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## const myResource = staticRead"mydatafile.bin" ## ## ``slurp`` is an alias for ``staticRead``. @@ -2822,21 +2866,21 @@ proc staticExec*(command: string, input = ""): string {. ## if `input` is not an empty string, it will be passed as a standard input ## to the executed program. ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & ## "\nCompiled on " & staticExec("uname -v") ## ## ``gorge`` is an alias for ``staticExec``. Note that you can use this proc - ## inside a pragma like `passC <nimrodc.html#passc-pragma>`_ or `passL - ## <nimrodc.html#passl-pragma>`_. + ## inside a pragma like `passC <nimc.html#passc-pragma>`_ or `passL + ## <nimc.html#passl-pragma>`_. -proc `+=`*[T: TOrdinal|uint|uint64](x: var T, y: T) {.magic: "Inc", noSideEffect.} +proc `+=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.magic: "Inc", noSideEffect.} ## Increments an ordinal -proc `-=`*[T: TOrdinal|uint|uint64](x: var T, y: T) {.magic: "Dec", noSideEffect.} +proc `-=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.magic: "Dec", noSideEffect.} ## Decrements an ordinal -proc `*=`*[T: TOrdinal|uint|uint64](x: var T, y: T) {.inline, noSideEffect.} = +proc `*=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.inline, noSideEffect.} = ## Binary `*=` operator for ordinals x = x * y @@ -2870,7 +2914,7 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[ ## to retrieve information about the current filename and line number. ## Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## import strutils ## ## template testException(exception, code: expr): stmt = @@ -2897,7 +2941,7 @@ template currentSourcePath*: string = instantiationInfo(-1, true).filename ## returns the full file-system path of the current source proc raiseAssert*(msg: string) {.noinline.} = - sysFatal(EAssertionFailed, msg) + sysFatal(AssertionError, msg) when true: proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = @@ -2910,12 +2954,12 @@ when true: template assert*(cond: bool, msg = "") = ## Raises ``EAssertionFailure`` with `msg` if `cond` is false. ## - ## Provides a means to implement `programming by contracts`:idx: in Nimrod. + ## Provides a means to implement `programming by contracts`:idx: in Nim. ## ``assert`` evaluates expression ``cond`` and if ``cond`` is false, it ## raises an ``EAssertionFailure`` exception. However, the compiler may not ## generate any code at all for ``assert`` if it is advised to do so through ## the ``-d:release`` or ``--assertions:off`` `command line switches - ## <nimrodc.html#command-line-switches>`_. + ## <nimc.html#command-line-switches>`_. ## ## Use ``assert`` for debugging purposes only. bind instantiationInfo @@ -2958,7 +3002,7 @@ template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} = ## statements following `onFailedAssert` in the current lexical scope. ## Can be defined multiple times in a single function. ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## proc example(x: int): TErrorCode = ## onFailedAssert(msg): @@ -2995,7 +3039,7 @@ proc shallow*(s: var string) {.noSideEffect, inline.} = type TNimrodNode {.final.} = object PNimrodNode* {.magic: "PNimrodNode".} = ref TNimrodNode - ## represents a Nimrod AST node. Macros operate on this type. + ## represents a Nim AST node. Macros operate on this type. when false: template eval*(blk: stmt): stmt = @@ -3024,7 +3068,7 @@ proc compiles*(x): bool {.magic: "Compiles", noSideEffect.} = ## without any semantic error. ## This can be used to check whether a type supports some operation: ## - ## .. code-block:: Nimrod + ## .. code-block:: Nim ## when not compiles(3 + 4): ## echo "'+' for integers is available" discard @@ -3046,14 +3090,14 @@ when hostOS != "standalone": if x == nil: x = y else: x.add(y) -proc locals*(): TObject {.magic: "Locals", noSideEffect.} = +proc locals*(): RootObj {.magic: "Locals", noSideEffect.} = ## generates a tuple constructor expression listing all the local variables ## in the current scope. This is quite fast as it does not rely ## on any debug or runtime information. Note that in constrast to what ## the official signature says, the return type is not ``TObject`` but a ## tuple of a structure that depends on the current scope. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## proc testLocals() = ## var ## a = "something" diff --git a/lib/system/alloc.nim b/lib/system/alloc.nim index 602e5c7fa..9f227f0c5 100644 --- a/lib/system/alloc.nim +++ b/lib/system/alloc.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# Low level allocator for Nimrod. Has been designed to support the GC. +# Low level allocator for Nim. Has been designed to support the GC. # TODO: # - eliminate "used" field # - make searching for block O(1) @@ -218,7 +218,7 @@ proc llAlloc(a: var TMemRegion, size: int): pointer = a.llmem.size = PageSize - sizeof(TLLChunk) a.llmem.acc = sizeof(TLLChunk) a.llmem.next = old - result = cast[pointer](cast[TAddress](a.llmem) + a.llmem.acc) + result = cast[pointer](cast[ByteAddress](a.llmem) + a.llmem.acc) dec(a.llmem.size, size) inc(a.llmem.acc, size) zeroMem(result, size) @@ -321,7 +321,7 @@ iterator allObjects(m: TMemRegion): pointer {.inline.} = var c = cast[PSmallChunk](c) let size = c.size - var a = cast[TAddress](addr(c.data)) + var a = cast[ByteAddress](addr(c.data)) let limit = a + c.acc while a <% limit: yield cast[pointer](a) @@ -335,27 +335,27 @@ proc isCell(p: pointer): bool {.inline.} = # ------------- chunk management ---------------------------------------------- proc pageIndex(c: PChunk): int {.inline.} = - result = cast[TAddress](c) shr PageShift + result = cast[ByteAddress](c) shr PageShift proc pageIndex(p: pointer): int {.inline.} = - result = cast[TAddress](p) shr PageShift + result = cast[ByteAddress](p) shr PageShift proc pageAddr(p: pointer): PChunk {.inline.} = - result = cast[PChunk](cast[TAddress](p) and not PageMask) + result = cast[PChunk](cast[ByteAddress](p) and not PageMask) #sysAssert(Contains(allocator.chunkStarts, pageIndex(result))) proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk = incCurrMem(a, size) inc(a.freeMem, size) result = cast[PBigChunk](osAllocPages(size)) - sysAssert((cast[TAddress](result) and PageMask) == 0, "requestOsChunks 1") + sysAssert((cast[ByteAddress](result) and PageMask) == 0, "requestOsChunks 1") #zeroMem(result, size) result.next = nil result.prev = nil result.used = false result.size = size # update next.prevSize: - var nxt = cast[TAddress](result) +% size + var nxt = cast[ByteAddress](result) +% size sysAssert((nxt and PageMask) == 0, "requestOsChunks 2") var next = cast[PChunk](nxt) if pageIndex(next) in a.chunkStarts: @@ -363,7 +363,7 @@ proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk = next.prevSize = size # set result.prevSize: var lastSize = if a.lastSize != 0: a.lastSize else: PageSize - var prv = cast[TAddress](result) -% lastSize + var prv = cast[ByteAddress](result) -% lastSize sysAssert((nxt and PageMask) == 0, "requestOsChunks 3") var prev = cast[PChunk](prv) if pageIndex(prev) in a.chunkStarts and prev.size == lastSize: @@ -376,7 +376,7 @@ proc requestOsChunks(a: var TMemRegion, size: int): PBigChunk = proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) = # update next.prevSize: var c = cast[PChunk](p) - var nxt = cast[TAddress](p) +% c.size + var nxt = cast[ByteAddress](p) +% c.size sysAssert((nxt and PageMask) == 0, "freeOsChunks") var next = cast[PChunk](nxt) if pageIndex(next) in a.chunkStarts: @@ -429,8 +429,8 @@ proc listRemove[T](head: var T, c: T) {.inline.} = proc updatePrevSize(a: var TMemRegion, c: PBigChunk, prevSize: int) {.inline.} = - var ri = cast[PChunk](cast[TAddress](c) +% c.size) - sysAssert((cast[TAddress](ri) and PageMask) == 0, "updatePrevSize") + var ri = cast[PChunk](cast[ByteAddress](c) +% c.size) + sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "updatePrevSize") if isAccessible(a, ri): ri.prevSize = prevSize @@ -439,8 +439,8 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) = sysAssert(c.size >= PageSize, "freeBigChunk") inc(a.freeMem, c.size) when coalescRight: - var ri = cast[PChunk](cast[TAddress](c) +% c.size) - sysAssert((cast[TAddress](ri) and PageMask) == 0, "freeBigChunk 2") + var ri = cast[PChunk](cast[ByteAddress](c) +% c.size) + sysAssert((cast[ByteAddress](ri) and PageMask) == 0, "freeBigChunk 2") if isAccessible(a, ri) and chunkUnused(ri): sysAssert(not isSmallChunk(ri), "freeBigChunk 3") if not isSmallChunk(ri): @@ -449,8 +449,8 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) = excl(a.chunkStarts, pageIndex(ri)) when coalescLeft: if c.prevSize != 0: - var le = cast[PChunk](cast[TAddress](c) -% c.prevSize) - sysAssert((cast[TAddress](le) and PageMask) == 0, "freeBigChunk 4") + var le = cast[PChunk](cast[ByteAddress](c) -% c.prevSize) + sysAssert((cast[ByteAddress](le) and PageMask) == 0, "freeBigChunk 4") if isAccessible(a, le) and chunkUnused(le): sysAssert(not isSmallChunk(le), "freeBigChunk 5") if not isSmallChunk(le): @@ -468,7 +468,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) = freeOsChunks(a, c, c.size) proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) = - var rest = cast[PBigChunk](cast[TAddress](c) +% size) + var rest = cast[PBigChunk](cast[ByteAddress](c) +% size) sysAssert(rest notin a.freeChunksList, "splitChunk") rest.size = c.size - size rest.used = false @@ -559,7 +559,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer = c.prev = nil listAdd(a.freeSmallChunks[s], c) result = addr(c.data) - sysAssert((cast[TAddress](result) and (MemAlign-1)) == 0, "rawAlloc 4") + sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 4") else: sysAssert(allocInv(a), "rawAlloc: begin c != nil") sysAssert c.next != c, "rawAlloc 5" @@ -569,21 +569,21 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer = if c.freeList == nil: sysAssert(c.acc + smallChunkOverhead() + size <= SmallChunkSize, "rawAlloc 7") - result = cast[pointer](cast[TAddress](addr(c.data)) +% c.acc) + result = cast[pointer](cast[ByteAddress](addr(c.data)) +% c.acc) inc(c.acc, size) else: result = c.freeList sysAssert(c.freeList.zeroField == 0, "rawAlloc 8") c.freeList = c.freeList.next dec(c.free, size) - sysAssert((cast[TAddress](result) and (MemAlign-1)) == 0, "rawAlloc 9") + sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 9") sysAssert(allocInv(a), "rawAlloc: end c != nil") sysAssert(allocInv(a), "rawAlloc: before c.free < size") if c.free < size: sysAssert(allocInv(a), "rawAlloc: before listRemove test") listRemove(a.freeSmallChunks[s], c) sysAssert(allocInv(a), "rawAlloc: end listRemove test") - sysAssert(((cast[TAddress](result) and PageMask) - smallChunkOverhead()) %% + sysAssert(((cast[ByteAddress](result) and PageMask) - smallChunkOverhead()) %% size == 0, "rawAlloc 21") sysAssert(allocInv(a), "rawAlloc: end small size") else: @@ -594,9 +594,9 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer = sysAssert c.next == nil, "rawAlloc 11" sysAssert c.size == size, "rawAlloc 12" result = addr(c.data) - sysAssert((cast[TAddress](result) and (MemAlign-1)) == 0, "rawAlloc 13") + sysAssert((cast[ByteAddress](result) and (MemAlign-1)) == 0, "rawAlloc 13") if a.root == nil: a.root = bottom - add(a, a.root, cast[TAddress](result), cast[TAddress](result)+%size) + add(a, a.root, cast[ByteAddress](result), cast[ByteAddress](result)+%size) sysAssert(isAccessible(a, result), "rawAlloc 14") sysAssert(allocInv(a), "rawAlloc: end") when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result) @@ -613,7 +613,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) = # `p` is within a small chunk: var c = cast[PSmallChunk](c) var s = c.size - sysAssert(((cast[TAddress](p) and PageMask) - smallChunkOverhead()) %% + sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %% s == 0, "rawDealloc 3") var f = cast[ptr TFreeCell](p) #echo("setting to nil: ", $cast[TAddress](addr(f.zeroField))) @@ -636,7 +636,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) = listRemove(a.freeSmallChunks[s div MemAlign], c) c.size = SmallChunkSize freeBigChunk(a, cast[PBigChunk](c)) - sysAssert(((cast[TAddress](p) and PageMask) - smallChunkOverhead()) %% + sysAssert(((cast[ByteAddress](p) and PageMask) - smallChunkOverhead()) %% s == 0, "rawDealloc 2") else: # set to 0xff to check for usage after free bugs: @@ -655,7 +655,7 @@ proc isAllocatedPtr(a: TMemRegion, p: pointer): bool = if not chunkUnused(c): if isSmallChunk(c): var c = cast[PSmallChunk](c) - var offset = (cast[TAddress](p) and (PageSize-1)) -% + var offset = (cast[ByteAddress](p) and (PageSize-1)) -% smallChunkOverhead() result = (c.acc >% offset) and (offset %% c.size == 0) and (cast[ptr TFreeCell](p).zeroField >% 1) @@ -673,12 +673,12 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer = if not chunkUnused(c): if isSmallChunk(c): var c = cast[PSmallChunk](c) - var offset = (cast[TAddress](p) and (PageSize-1)) -% + var offset = (cast[ByteAddress](p) and (PageSize-1)) -% smallChunkOverhead() if c.acc >% offset: - sysAssert(cast[TAddress](addr(c.data)) +% offset == - cast[TAddress](p), "offset is not what you think it is") - var d = cast[ptr TFreeCell](cast[TAddress](addr(c.data)) +% + sysAssert(cast[ByteAddress](addr(c.data)) +% offset == + cast[ByteAddress](p), "offset is not what you think it is") + var d = cast[ptr TFreeCell](cast[ByteAddress](addr(c.data)) +% offset -% (offset %% c.size)) if d.zeroField >% 1: result = d @@ -704,7 +704,7 @@ proc interiorAllocatedPtr(a: TMemRegion, p: pointer): pointer = sysAssert isAllocatedPtr(a, result), " result wrong pointer!" proc ptrSize(p: pointer): int = - var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell)) + var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell)) var c = pageAddr(p) sysAssert(not chunkUnused(c), "ptrSize") result = c.size -% sizeof(TFreeCell) @@ -715,7 +715,7 @@ proc alloc(allocator: var TMemRegion, size: int): pointer = result = rawAlloc(allocator, size+sizeof(TFreeCell)) cast[ptr TFreeCell](result).zeroField = 1 # mark it as used sysAssert(not isAllocatedPtr(allocator, result), "alloc") - result = cast[pointer](cast[TAddress](result) +% sizeof(TFreeCell)) + result = cast[pointer](cast[ByteAddress](result) +% sizeof(TFreeCell)) proc alloc0(allocator: var TMemRegion, size: int): pointer = result = alloc(allocator, size) @@ -723,7 +723,7 @@ proc alloc0(allocator: var TMemRegion, size: int): pointer = proc dealloc(allocator: var TMemRegion, p: pointer) = sysAssert(p != nil, "dealloc 0") - var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell)) + var x = cast[pointer](cast[ByteAddress](p) -% sizeof(TFreeCell)) sysAssert(x != nil, "dealloc 1") sysAssert(isAccessible(allocator, x), "is not accessible") sysAssert(cast[ptr TFreeCell](x).zeroField == 1, "dealloc 2") @@ -769,7 +769,7 @@ template instantiateForRegion(allocator: expr) = result = interiorAllocatedPtr(allocator, p) proc isAllocatedPtr*(p: pointer): bool = - let p = cast[pointer](cast[TAddress](p)-%TAddress(sizeof(TCell))) + let p = cast[pointer](cast[ByteAddress](p)-%ByteAddress(sizeof(TCell))) result = isAllocatedPtr(allocator, p) proc deallocOsPages = deallocOsPages(allocator) @@ -784,7 +784,7 @@ template instantiateForRegion(allocator: expr) = dealloc(allocator, p) proc realloc(p: pointer, newsize: int): pointer = - result = realloc(allocator, p, newsize) + result = realloc(allocator, p, newSize) when false: proc countFreeMem(): int = @@ -833,7 +833,7 @@ template instantiateForRegion(allocator: expr) = result = realloc(sharedHeap, p, newsize) releaseSys(heapLock) else: - result = realloc(p, newsize) + result = realloc(p, newSize) when hasThreadSupport: diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 673d55582..6bc44719f 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -8,7 +8,7 @@ # # This include file contains headers of Ansi C procs -# and definitions of Ansi C types in Nimrod syntax +# and definitions of Ansi C types in Nim syntax # All symbols are prefixed with 'c_' to avoid ambiguities {.push hints:off} diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim index 7672947cd..c4df287cf 100644 --- a/lib/system/arithm.nim +++ b/lib/system/arithm.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,10 +12,10 @@ proc raiseOverflow {.compilerproc, noinline, noreturn.} = # a single proc to reduce code size to a minimum - sysFatal(EOverflow, "over- or underflow") + sysFatal(OverflowError, "over- or underflow") proc raiseDivByZero {.compilerproc, noinline, noreturn.} = - sysFatal(EDivByZero, "divison by zero") + sysFatal(DivByZeroError, "divison by zero") proc addInt64(a, b: int64): int64 {.compilerProc, inline.} = result = a +% b @@ -328,16 +328,16 @@ when not declared(mulInt): # written in other languages. proc raiseFloatInvalidOp {.noinline, noreturn.} = - sysFatal(EFloatInvalidOp, "FPU operation caused a NaN result") + sysFatal(FloatInvalidOpError, "FPU operation caused a NaN result") proc nanCheck(x: float64) {.compilerProc, inline.} = if x != x: raiseFloatInvalidOp() proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} = if x > 0.0: - sysFatal(EFloatOverflow, "FPU operation caused an overflow") + sysFatal(FloatOverflowError, "FPU operation caused an overflow") else: - sysFatal(EFloatUnderflow, "FPU operations caused an underflow") + sysFatal(FloatUnderflowError, "FPU operations caused an underflow") proc infCheck(x: float64) {.compilerProc, inline.} = if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x) diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 0e27eb57f..6c58c24c2 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,8 +13,8 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) {.gcsafe. proc genericAssignAux(dest, src: pointer, n: ptr TNimNode, shallow: bool) {.gcsafe.} = var - d = cast[TAddress](dest) - s = cast[TAddress](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) case n.kind of nkSlot: genericAssignAux(cast[pointer](d +% n.offset), @@ -40,8 +40,8 @@ proc genericAssignAux(dest, src: pointer, n: ptr TNimNode, proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = var - d = cast[TAddress](dest) - s = cast[TAddress](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) sysAssert(mt != nil, "genericAssignAux 2") case mt.kind of tyString: @@ -62,11 +62,11 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) = return sysAssert(dest != nil, "genericAssignAux 3") unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[TAddress](cast[PPointer](dest)[]) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericAssignAux( cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), - cast[pointer](cast[TAddress](s2) +% i *% mt.base.size +% + cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% GenericSeqSize), mt.base, shallow) of tyObject: @@ -130,15 +130,15 @@ proc genericSeqAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} = proc genericAssignOpenArray(dest, src: pointer, len: int, mt: PNimType) {.compilerproc.} = var - d = cast[TAddress](dest) - s = cast[TAddress](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) for i in 0..len-1: genericAssign(cast[pointer](d +% i*% mt.base.size), cast[pointer](s +% i*% mt.base.size), mt.base) proc objectInit(dest: pointer, typ: PNimType) {.compilerProc, gcsafe.} proc objectInitAux(dest: pointer, n: ptr TNimNode) {.gcsafe.} = - var d = cast[TAddress](dest) + var d = cast[ByteAddress](dest) case n.kind of nkNone: sysAssert(false, "objectInitAux") of nkSlot: objectInit(cast[pointer](d +% n.offset), n.typ) @@ -152,7 +152,7 @@ proc objectInitAux(dest: pointer, n: ptr TNimNode) {.gcsafe.} = proc objectInit(dest: pointer, typ: PNimType) = # the generic init proc that takes care of initialization of complex # objects on the stack or heap - var d = cast[TAddress](dest) + var d = cast[ByteAddress](dest) case typ.kind of tyObject: # iterate over any structural type @@ -184,7 +184,7 @@ else: proc genericReset(dest: pointer, mt: PNimType) {.compilerProc, gcsafe.} proc genericResetAux(dest: pointer, n: ptr TNimNode) = - var d = cast[TAddress](dest) + var d = cast[ByteAddress](dest) case n.kind of nkNone: sysAssert(false, "genericResetAux") of nkSlot: genericReset(cast[pointer](d +% n.offset), n.typ) @@ -196,7 +196,7 @@ proc genericResetAux(dest: pointer, n: ptr TNimNode) = zeroMem(cast[pointer](d +% n.offset), n.typ.size) proc genericReset(dest: pointer, mt: PNimType) = - var d = cast[TAddress](dest) + var d = cast[ByteAddress](dest) sysAssert(mt != nil, "genericReset 2") case mt.kind of tyString, tyRef, tySequence: @@ -223,4 +223,4 @@ proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int, var oldBranch = selectBranch(oldDiscVal, L, a) var newBranch = selectBranch(newDiscVal, L, a) if newBranch != oldBranch and oldDiscVal != 0: - sysFatal(EInvalidField, "assignment to discriminant changes object branch") + sysFatal(FieldError, "assignment to discriminant changes object branch") diff --git a/lib/system/atomics.nim b/lib/system/atomics.nim index 695a5f63e..a6ec288a1 100644 --- a/lib/system/atomics.nim +++ b/lib/system/atomics.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# Atomic operations for Nimrod. +# Atomic operations for Nim. {.push stackTrace:off.} const someGcc = defined(gcc) or defined(llvm_gcc) or defined(clang) @@ -31,7 +31,7 @@ when someGcc and hasThreadSupport: ## with acquire loads ## and release stores in all threads. - TAtomType* = TNumber|pointer|ptr|char + TAtomType* = SomeNumber|pointer|ptr|char ## Type Class representing valid types for use with atomic procs proc atomicLoadN*[T: TAtomType](p: ptr T, mem: AtomMemModel): T {. @@ -159,6 +159,7 @@ when someGcc and hasThreadSupport: elif defined(vcc) and hasThreadSupport: proc addAndFetch*(p: ptr int, val: int): int {. importc: "NimXadd", nodecl.} + proc fence*() {.importc: "_ReadWriteBarrier", header: "<intrin.h>".} else: proc addAndFetch*(p: ptr int, val: int): int {.inline.} = diff --git a/lib/system/avltree.nim b/lib/system/avltree.nim index bced15d6a..157799b28 100644 --- a/lib/system/avltree.nim +++ b/lib/system/avltree.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/system/cellsets.nim b/lib/system/cellsets.nim index 3825e5b47..0e3a01eba 100644 --- a/lib/system/cellsets.nim +++ b/lib/system/cellsets.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -27,7 +27,7 @@ type TBitIndex = range[0..UnitsPerPage-1] TPageDesc {.final, pure.} = object next: PPageDesc # all nodes are connected with this pointer - key: TAddress # start address at bit 0 + key: ByteAddress # start address at bit 0 bits: array[TBitIndex, int] # a bit vector PPageDescArray = ptr array[0..1000_000, PPageDesc] @@ -98,7 +98,7 @@ proc nextTry(h, maxHash: int): int {.inline.} = # generates each int in range(maxHash) exactly once (see any text on # random-number generation for proof). -proc cellSetGet(t: TCellSet, key: TAddress): PPageDesc = +proc cellSetGet(t: TCellSet, key: ByteAddress): PPageDesc = var h = cast[int](key) and t.max while t.data[h] != nil: if t.data[h].key == key: return t.data[h] @@ -123,7 +123,7 @@ proc cellSetEnlarge(t: var TCellSet) = dealloc(t.data) t.data = n -proc cellSetPut(t: var TCellSet, key: TAddress): PPageDesc = +proc cellSetPut(t: var TCellSet, key: ByteAddress): PPageDesc = var h = cast[int](key) and t.max while true: var x = t.data[h] @@ -147,7 +147,7 @@ proc cellSetPut(t: var TCellSet, key: TAddress): PPageDesc = # ---------- slightly higher level procs -------------------------------------- proc contains(s: TCellSet, cell: PCell): bool = - var u = cast[TAddress](cell) + var u = cast[ByteAddress](cell) var t = cellSetGet(s, u shr PageShift) if t != nil: u = (u %% PageSize) /% MemAlign @@ -156,13 +156,13 @@ proc contains(s: TCellSet, cell: PCell): bool = result = false proc incl(s: var TCellSet, cell: PCell) {.noinline.} = - var u = cast[TAddress](cell) + var u = cast[ByteAddress](cell) var t = cellSetPut(s, u shr PageShift) u = (u %% PageSize) /% MemAlign t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask)) proc excl(s: var TCellSet, cell: PCell) = - var u = cast[TAddress](cell) + var u = cast[ByteAddress](cell) var t = cellSetGet(s, u shr PageShift) if t != nil: u = (u %% PageSize) /% MemAlign @@ -170,7 +170,7 @@ proc excl(s: var TCellSet, cell: PCell) = not (1 shl (u and IntMask))) proc containsOrIncl(s: var TCellSet, cell: PCell): bool = - var u = cast[TAddress](cell) + var u = cast[ByteAddress](cell) var t = cellSetGet(s, u shr PageShift) if t != nil: u = (u %% PageSize) /% MemAlign diff --git a/lib/system/cgprocs.nim b/lib/system/cgprocs.nim index d483c61bd..d46e715f1 100644 --- a/lib/system/cgprocs.nim +++ b/lib/system/cgprocs.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/system/channels.nim b/lib/system/channels.nim index df46922e4..d7ec2c4af 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,9 +13,9 @@ ## ## **Note:** The current implementation of message passing is slow and does ## not work with cyclic data structures. - -when not declared(NimString): - {.error: "You must not import this module explicitly".} + +when not declared(NimString): + {.error: "You must not import this module explicitly".} type pbytes = ptr array[0.. 0xffff, byte] @@ -53,8 +53,8 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel, mode: TLoadStoreMode) {.gcsafe.} = var - d = cast[TAddress](dest) - s = cast[TAddress](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) case n.kind of nkSlot: storeAux(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset), n.typ, t, mode) @@ -70,14 +70,14 @@ proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel, proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, mode: TLoadStoreMode) = var - d = cast[TAddress](dest) - s = cast[TAddress](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) sysAssert(mt != nil, "mt == nil") - case mt.Kind + case mt.kind of tyString: if mode == mStore: - var x = cast[ppointer](dest) - var s2 = cast[ppointer](s)[] + var x = cast[PPointer](dest) + var s2 = cast[PPointer](s)[] if s2 == nil: x[] = nil else: @@ -86,17 +86,17 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, copyMem(ns, ss, ss.len+1 + GenericSeqSize) x[] = ns else: - var x = cast[ppointer](dest) - var s2 = cast[ppointer](s)[] + var x = cast[PPointer](dest) + var s2 = cast[PPointer](s)[] if s2 == nil: unsureAsgnRef(x, s2) else: unsureAsgnRef(x, copyString(cast[NimString](s2))) dealloc(t.region, s2) of tySequence: - var s2 = cast[ppointer](src)[] + var s2 = cast[PPointer](src)[] var seq = cast[PGenericSeq](s2) - var x = cast[ppointer](dest) + var x = cast[PPointer](dest) if s2 == nil: if mode == mStore: x[] = nil @@ -108,13 +108,13 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, x[] = alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize) else: unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize)) - var dst = cast[taddress](cast[ppointer](dest)[]) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) for i in 0..seq.len-1: storeAux( cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), - cast[pointer](cast[TAddress](s2) +% i *% mt.base.size +% + cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% GenericSeqSize), - mt.Base, t, mode) + mt.base, t, mode) var dstseq = cast[PGenericSeq](dst) dstseq.len = seq.len dstseq.reserved = seq.len @@ -123,8 +123,8 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, # copy type field: var pint = cast[ptr PNimType](dest) # XXX use dynamic type here! - pint[] = mt - if mt.base != nil: + pint[] = mt + if mt.base != nil: storeAux(dest, src, mt.base, t, mode) storeAux(dest, src, mt.node, t, mode) of tyTuple: @@ -134,8 +134,8 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel, storeAux(cast[pointer](d +% i*% mt.base.size), cast[pointer](s +% i*% mt.base.size), mt.base, t, mode) of tyRef: - var s = cast[ppointer](src)[] - var x = cast[ppointer](dest) + var s = cast[PPointer](src)[] + var x = cast[PPointer](dest) if s == nil: if mode == mStore: x[] = nil @@ -192,7 +192,7 @@ template lockChannel(q: expr, action: stmt) {.immediate.} = template sendImpl(q: expr) {.immediate.} = if q.mask == ChannelDeadMask: - sysFatal(EDeadThread, "cannot send message; thread died") + sysFatal(DeadThreadError, "cannot send message; thread died") acquireSys(q.lock) var m: TMsg shallowCopy(m, msg) @@ -215,7 +215,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) = q.ready = false if typ != q.elemType: releaseSys(q.lock) - sysFatal(EInvalidValue, "cannot receive message of wrong type") + sysFatal(ValueError, "cannot receive message of wrong type") rawRecv(q, res, typ) proc recv*[TMsg](c: var TChannel[TMsg]): TMsg = @@ -225,20 +225,20 @@ proc recv*[TMsg](c: var TChannel[TMsg]): TMsg = acquireSys(q.lock) llRecv(q, addr(result), cast[PNimType](getTypeInfo(result))) releaseSys(q.lock) - -proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvaliable: bool, - msg: TMsg] = - ## try to receives a message from the channel `c` if available. Otherwise - ## it returns ``(false, default(msg))``. + +proc tryRecv*[TMsg](c: var TChannel[TMsg]): tuple[dataAvaliable: bool, + msg: TMsg] = + ## try to receives a message from the channel `c` if available. Otherwise + ## it returns ``(false, default(msg))``. var q = cast[PRawChannel](addr(c)) if q.mask != ChannelDeadMask: lockChannel(q): - llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg))) + llRecv(q, addr(result.msg), cast[PNimType](getTypeInfo(result.msg))) result.dataAvaliable = true proc peek*[TMsg](c: var TChannel[TMsg]): int = ## returns the current number of messages in the channel `c`. Returns -1 - ## if the channel has been closed. **Note**: This is dangerous to use + ## if the channel has been closed. **Note**: This is dangerous to use ## as it encourages races. It's much better to use ``tryRecv`` instead. var q = cast[PRawChannel](addr(c)) if q.mask != ChannelDeadMask: diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim index 387b54ef1..5c32a307a 100644 --- a/lib/system/chcks.nim +++ b/lib/system/chcks.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,13 +13,13 @@ proc raiseRangeError(val: BiggestInt) {.compilerproc, noreturn, noinline.} = when hostOS == "standalone": sysFatal(EOutOfRange, "value out of range") else: - sysFatal(EOutOfRange, "value out of range: ", $val) + sysFatal(RangeError, "value out of range: ", $val) proc raiseIndexError() {.compilerproc, noreturn, noinline.} = - sysFatal(EInvalidIndex, "index out of bounds") + sysFatal(IndexError, "index out of bounds") proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} = - sysFatal(EInvalidField, f, " is not accessible") + sysFatal(FieldError, f, " is not accessible") proc chckIndx(i, a, b: int): int = if i >= a and i <= b: @@ -46,11 +46,11 @@ proc chckRangeF(x, a, b: float): float = when hostOS == "standalone": sysFatal(EOutOfRange, "value out of range") else: - sysFatal(EOutOfRange, "value out of range: ", $x) + sysFatal(RangeError, "value out of range: ", $x) proc chckNil(p: pointer) = if p == nil: - sysFatal(EInvalidValue, "attempt to write to a nil address") + sysFatal(ValueError, "attempt to write to a nil address") #c_raise(SIGSEGV) proc chckObj(obj, subclass: PNimType) {.compilerproc.} = @@ -59,13 +59,13 @@ proc chckObj(obj, subclass: PNimType) {.compilerproc.} = if x == subclass: return # optimized fast path while x != subclass: if x == nil: - sysFatal(EInvalidObjectConversion, "invalid object conversion") + sysFatal(ObjectConversionError, "invalid object conversion") break x = x.base proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} = if a != b: - sysFatal(EInvalidObjectAssignment, "invalid object assignment") + sysFatal(ObjectAssignmentError, "invalid object assignment") type ObjCheckCache = array[0..1, PNimType] diff --git a/lib/system/debugger.nim b/lib/system/debugger.nim index af7b6d515..7b5169344 100644 --- a/lib/system/debugger.nim +++ b/lib/system/debugger.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -157,8 +157,8 @@ type oldValue: THash var - Watchpoints: array [0..99, TWatchpoint] - WatchpointsLen: int + watchpoints: array [0..99, TWatchpoint] + watchpointsLen: int proc `!&`(h: THash, val: int): THash {.inline.} = result = h +% val @@ -189,7 +189,7 @@ proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool, h: THash): THash proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool, h: THash): THash = - var d = cast[TAddress](dest) + var d = cast[ByteAddress](dest) case n.kind of nkSlot: result = genericHashAux(cast[pointer](d +% n.offset), n.typ, shallow, h) @@ -206,9 +206,9 @@ proc genericHashAux(dest: pointer, n: ptr TNimNode, shallow: bool, proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool, h: THash): THash = sysAssert(mt != nil, "genericHashAux 2") - case mt.Kind + case mt.kind of tyString: - var x = cast[ppointer](dest)[] + var x = cast[PPointer](dest)[] result = h if x != nil: let s = cast[NimString](x) @@ -217,29 +217,29 @@ proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool, else: result = result !& hash(x, s.len) of tySequence: - var x = cast[ppointer](dest) - var dst = cast[taddress](cast[ppointer](dest)[]) + var x = cast[PPointer](dest) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) result = h if dst != 0: when defined(trackGcHeaders): - result = result !& hashGcHeader(cast[ppointer](dest)[]) + result = result !& hashGcHeader(cast[PPointer](dest)[]) else: - for i in 0..cast[pgenericseq](dst).len-1: + for i in 0..cast[PGenericSeq](dst).len-1: result = result !& genericHashAux( cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), - mt.Base, shallow, result) + mt.base, shallow, result) of tyObject, tyTuple: # we don't need to copy m_type field for tyObject, as they are equal anyway result = genericHashAux(dest, mt.node, shallow, h) of tyArray, tyArrayConstr: - let d = cast[TAddress](dest) + let d = cast[ByteAddress](dest) result = h for i in 0..(mt.size div mt.base.size)-1: result = result !& genericHashAux(cast[pointer](d +% i*% mt.base.size), mt.base, shallow, result) of tyRef: when defined(trackGcHeaders): - var s = cast[ppointer](dest)[] + var s = cast[PPointer](dest)[] if s != nil: result = result !& hashGcHeader(s) else: @@ -247,7 +247,7 @@ proc genericHashAux(dest: pointer, mt: PNimType, shallow: bool, result = h !& hash(dest, mt.size) else: result = h - var s = cast[ppointer](dest)[] + var s = cast[PPointer](dest)[] if s != nil: result = result !& genericHashAux(s, mt.base, shallow, result) else: @@ -258,23 +258,23 @@ proc genericHash(dest: pointer, mt: PNimType): int = proc dbgRegisterWatchpoint(address: pointer, name: cstring, typ: PNimType) {.compilerproc.} = - let L = WatchpointsLen + let L = watchPointsLen for i in 0.. <L: - if Watchpoints[i].name == name: + if watchPoints[i].name == name: # address may have changed: - Watchpoints[i].address = address + watchPoints[i].address = address return if L >= watchPoints.high: #debugOut("[Warning] cannot register watchpoint") return - Watchpoints[L].name = name - Watchpoints[L].address = address - Watchpoints[L].typ = typ - Watchpoints[L].oldValue = genericHash(address, typ) - inc WatchpointsLen + watchPoints[L].name = name + watchPoints[L].address = address + watchPoints[L].typ = typ + watchPoints[L].oldValue = genericHash(address, typ) + inc watchPointsLen proc dbgUnregisterWatchpoints*() = - WatchpointsLen = 0 + watchPointsLen = 0 var dbgLineHook*: proc () {.nimcall.} @@ -285,15 +285,15 @@ var dbgWatchpointHook*: proc (watchpointName: cstring) {.nimcall.} proc checkWatchpoints = - let L = WatchpointsLen + let L = watchPointsLen for i in 0.. <L: - let newHash = genericHash(Watchpoints[i].address, Watchpoints[i].typ) - if newHash != Watchpoints[i].oldValue: - dbgWatchpointHook(Watchpoints[i].name) - Watchpoints[i].oldValue = newHash + let newHash = genericHash(watchPoints[i].address, watchPoints[i].typ) + if newHash != watchPoints[i].oldValue: + dbgWatchpointHook(watchPoints[i].name) + watchPoints[i].oldValue = newHash proc endb(line: int, file: cstring) {.compilerproc, noinline.} = - # This proc is called before every Nimrod code line! + # This proc is called before every Nim code line! if framePtr == nil: return if dbgWatchpointHook != nil: checkWatchpoints() framePtr.line = line # this is done here for smaller code size! diff --git a/lib/system/deepcopy.nim b/lib/system/deepcopy.nim index e7eb1cdb4..e4356a25d 100644 --- a/lib/system/deepcopy.nim +++ b/lib/system/deepcopy.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -10,8 +10,8 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) {.gcsafe.} proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.gcsafe.} = var - d = cast[TAddress](dest) - s = cast[TAddress](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) case n.kind of nkSlot: genericDeepCopyAux(cast[pointer](d +% n.offset), @@ -40,8 +40,8 @@ proc copyDeepString(src: NimString): NimString {.inline.} = proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) = var - d = cast[TAddress](dest) - s = cast[TAddress](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) sysAssert(mt != nil, "genericDeepCopyAux 2") case mt.kind of tyString: @@ -60,11 +60,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) = return sysAssert(dest != nil, "genericDeepCopyAux 3") unsureAsgnRef(x, newSeq(mt, seq.len)) - var dst = cast[TAddress](cast[PPointer](dest)[]) + var dst = cast[ByteAddress](cast[PPointer](dest)[]) for i in 0..seq.len-1: genericDeepCopyAux( cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize), - cast[pointer](cast[TAddress](s2) +% i *% mt.base.size +% + cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +% GenericSeqSize), mt.base) of tyObject: @@ -82,17 +82,16 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) = genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size), cast[pointer](s +% i*% mt.base.size), mt.base) of tyRef: - if mt.base.deepCopy != nil: - let z = mt.base.deepCopy(cast[PPointer](src)[]) + let s2 = cast[PPointer](src)[] + if s2 == nil: + unsureAsgnRef(cast[PPointer](dest), s2) + elif mt.base.deepcopy != nil: + let z = mt.base.deepcopy(s2) unsureAsgnRef(cast[PPointer](dest), z) else: # we modify the header of the cell temporarily; instead of the type # field we store a forwarding pointer. XXX This is bad when the cloning # fails due to OOM etc. - let s2 = cast[PPointer](src)[] - if s2 == nil: - unsureAsgnRef(cast[PPointer](dest), s2) - return when declared(usrToCell): # unfortunately we only have cycle detection for our native GCs. let x = usrToCell(s2) @@ -116,10 +115,11 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) = genericDeepCopyAux(z, s2, realType.base) of tyPtr: # no cycle check here, but also not really required - if mt.base.deepCopy != nil: - cast[PPointer](dest)[] = mt.base.deepCopy(cast[PPointer](s)[]) + let s2 = cast[PPointer](src)[] + if s2 != nil and mt.base.deepcopy != nil: + cast[PPointer](dest)[] = mt.base.deepcopy(s2) else: - cast[PPointer](dest)[] = cast[PPointer](s)[] + cast[PPointer](dest)[] = s2 else: copyMem(dest, src, mt.size) @@ -134,8 +134,8 @@ proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} = proc genericDeepCopyOpenArray(dest, src: pointer, len: int, mt: PNimType) {.compilerproc.} = var - d = cast[TAddress](dest) - s = cast[TAddress](src) + d = cast[ByteAddress](dest) + s = cast[ByteAddress](src) for i in 0..len-1: genericDeepCopy(cast[pointer](d +% i*% mt.base.size), cast[pointer](s +% i*% mt.base.size), mt.base) diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim index 9ef1a99ca..e0d99cf88 100644 --- a/lib/system/dyncalls.nim +++ b/lib/system/dyncalls.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -17,7 +17,7 @@ const NilLibHandle: TLibHandle = nil -proc rawWrite(f: TFile, s: string) = +proc rawWrite(f: File, s: string) = # we cannot throw an exception here! discard writeBuffer(f, cstring(s), s.len) diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim index 661992e81..9bb25b8dd 100644 --- a/lib/system/embedded.nim +++ b/lib/system/embedded.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -21,7 +21,7 @@ proc popFrame {.compilerRtl, inl.} = discard proc setFrame(s: PFrame) {.compilerRtl, inl.} = discard proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = discard proc popSafePoint {.compilerRtl, inl.} = discard -proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} = discard +proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} = discard proc popCurrentException {.compilerRtl, inl.} = discard # some platforms have native support for stack traces: @@ -32,7 +32,7 @@ const proc quitOrDebug() {.inline.} = quit(1) -proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} = +proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = sysFatal(ENoExceptionToReraise, "exception handling is not available") proc reraiseException() {.compilerRtl.} = diff --git a/lib/system/endb.nim b/lib/system/endb.nim index f7e95e216..003698421 100644 --- a/lib/system/endb.nim +++ b/lib/system/endb.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ # with the application. Mostly we do not use dynamic memory here as that # would interfere with the GC and trigger ON/OFF errors if the # user program corrupts memory. Unfortunately, for dispaying -# variables we use the ``system.repr()`` proc which uses Nimrod +# variables we use the ``system.repr()`` proc which uses Nim # strings and thus allocates memory from the heap. Pity, but # I do not want to implement ``repr()`` twice. @@ -152,7 +152,7 @@ proc debugOut(msg: cstring) = proc dbgFatal(msg: cstring) = debugOut(msg) - dbgAborting = True # the debugger wants to abort + dbgAborting = true # the debugger wants to abort quit(1) proc dbgShowCurrentProc(dbgFramePointer: PFrame) = @@ -176,7 +176,7 @@ proc scanAndAppendWord(src: cstring, a: var TStaticStr, start: int): int = result = start # skip whitespace: while src[result] in {'\t', ' '}: inc(result) - while True: + while true: case src[result] of 'a'..'z', '0'..'9': add(a, src[result]) of '_': discard # just skip it @@ -280,7 +280,7 @@ proc breakpointToggle(s: cstring, start: int) = else: debugOut("[Warning] unknown breakpoint ") proc dbgEvaluate(stream: TFile, s: cstring, start: int, f: PFrame) = - var dbgTemp: tstaticstr + var dbgTemp: TStaticStr var i = scanWord(s, dbgTemp, start) while s[i] in {' ', '\t'}: inc(i) var v: TVarSlot @@ -299,10 +299,10 @@ proc dbgEvaluate(stream: TFile, s: cstring, start: int, f: PFrame) = writeVariable(stream, v) proc dbgOut(s: cstring, start: int, currFrame: PFrame) = - var dbgTemp: tstaticstr + var dbgTemp: TStaticStr var i = scanFilename(s, dbgTemp, start) if dbgTemp.len == 0: - InvalidCommand() + invalidCommand() return var stream = openAppend(dbgTemp.data) if stream == nil: @@ -326,7 +326,7 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) = close(stream) proc readLine(f: TFile, line: var TStaticStr): bool = - while True: + while true: var c = fgetc(f) if c < 0'i32: if line.len > 0: break @@ -355,7 +355,7 @@ proc dbgWriteStackTrace(f: PFrame) proc commandPrompt() = # if we return from this routine, user code executes again var - again = True + again = true dbgFramePtr = framePtr # for going down and up the stack dbgDown = 0 # how often we did go down dbgTemp: TStaticStr @@ -390,7 +390,7 @@ proc commandPrompt() = dbgHelp() elif ?"q" or ?"quit": dbgState = dbQuiting - dbgAborting = True + dbgAborting = true again = false quit(1) # BUGFIX: quit with error code > 0 elif ?"e" or ?"eval": @@ -402,9 +402,9 @@ proc commandPrompt() = elif ?"w" or ?"where": dbgShowExecutionPoint() elif ?"l" or ?"locals": - ListLocals(stdout, dbgFramePtr) + listLocals(stdout, dbgFramePtr) elif ?"g" or ?"globals": - ListGlobals(stdout) + listGlobals(stdout) elif ?"u" or ?"up": if dbgDown <= 0: debugOut("[Warning] cannot go up any further ") diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 3c5436afb..c0e99a5e2 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -11,7 +11,7 @@ # use the heap (and nor exceptions) do not include the GC or memory allocator. var - errorMessageWriter*: (proc(msg: string) {.tags: [FWriteIO], gcsafe.}) + errorMessageWriter*: (proc(msg: string) {.tags: [WriteIOEffect], gcsafe.}) ## Function that will be called ## instead of stdmsg.write when printing stacktrace. ## Unstable API. @@ -42,7 +42,7 @@ var excHandler {.threadvar.}: PSafePoint # list of exception handlers # a global variable for the root of all try blocks - currException {.threadvar.}: ref E_Base + currException {.threadvar.}: ref Exception proc popFrame {.compilerRtl, inl.} = framePtr = framePtr.prev @@ -58,7 +58,7 @@ proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} = proc popSafePoint {.compilerRtl, inl.} = excHandler = excHandler.prev -proc pushCurrentException(e: ref E_Base) {.compilerRtl, inl.} = +proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} = e.parent = currException currException = e @@ -68,8 +68,8 @@ proc popCurrentException {.compilerRtl, inl.} = # some platforms have native support for stack traces: const nativeStackTraceSupported* = (defined(macosx) or defined(linux)) and - not nimrodStackTrace - hasSomeStackTrace = nimrodStackTrace or + not NimStackTrace + hasSomeStackTrace = NimStackTrace or defined(nativeStackTrace) and nativeStackTraceSupported when defined(nativeStacktrace) and nativeStackTraceSupported: @@ -177,7 +177,7 @@ proc auxWriteStackTrace(f: PFrame, s: var string) = when hasSomeStackTrace: proc rawWriteStackTrace(s: var string) = - when nimrodStackTrace: + when NimStackTrace: if framePtr == nil: add(s, "No stack traceback available\n") else: @@ -195,7 +195,7 @@ proc quitOrDebug() {.inline.} = else: endbStep() # call the debugger -proc raiseExceptionAux(e: ref E_Base) = +proc raiseExceptionAux(e: ref Exception) = if localRaiseHook != nil: if not localRaiseHook(e): return if globalRaiseHook != nil: @@ -204,7 +204,7 @@ proc raiseExceptionAux(e: ref E_Base) = if not excHandler.hasRaiseAction or excHandler.raiseAction(e): pushCurrentException(e) c_longjmp(excHandler.context, 1) - elif e[] of EOutOfMemory: + elif e[] of OutOfMemError: showErrorMessage(e.name) quitOrDebug() else: @@ -236,7 +236,7 @@ proc raiseExceptionAux(e: ref E_Base) = showErrorMessage(buf) quitOrDebug() -proc raiseException(e: ref E_Base, ename: cstring) {.compilerRtl.} = +proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} = e.name = ename when hasSomeStackTrace: e.trace = "" @@ -245,7 +245,7 @@ proc raiseException(e: ref E_Base, ename: cstring) {.compilerRtl.} = proc reraiseException() {.compilerRtl.} = if currException == nil: - sysFatal(ENoExceptionToReraise, "no exception to reraise") + sysFatal(ReraiseError, "no exception to reraise") else: raiseExceptionAux(currException) @@ -264,7 +264,7 @@ proc getStackTrace(): string = else: result = "No stack traceback available\n" -proc getStackTrace(e: ref E_Base): string = +proc getStackTrace(e: ref Exception): string = if not isNil(e) and not isNil(e.trace): result = e.trace else: @@ -318,7 +318,7 @@ when not defined(noSignalHandler): GC_disable() var buf = newStringOfCap(2000) rawWriteStackTrace(buf) - processSignal(sig, buf.add) # nice hu? currying a la nimrod :-) + processSignal(sig, buf.add) # nice hu? currying a la Nim :-) showErrorMessage(buf) GC_enable() else: @@ -326,7 +326,7 @@ when not defined(noSignalHandler): template asgn(y: expr) = msg = y processSignal(sig, asgn) showErrorMessage(msg) - when defined(endb): dbgAborting = True + when defined(endb): dbgAborting = true quit(1) # always quit when SIGABRT proc registerSignalHandler() = diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 0c1fc7748..c4b3a4928 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -111,11 +111,11 @@ proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} = 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 @@ -312,7 +312,7 @@ proc cellsetReset(s: var TCellSet) = init(s) proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.gcsafe.} = - 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: @@ -332,7 +332,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.gcsafe.} = of nkNone: sysAssert(false, "forAllSlotsAux") proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) = - var d = cast[TAddress](dest) + var d = cast[ByteAddress](dest) if dest == nil: return # nothing to do if ntfNoRefs notin mt.flags: case mt.kind @@ -358,7 +358,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) = 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: for i in 0..s.len-1: @@ -424,7 +424,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer = gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") collectCT(gch) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell))) - gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2") + gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ when leakDetector and not hasThreadSupport: @@ -470,7 +470,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} = var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell))) sysAssert(allocInv(gch.region), "newObjRC1 after rawAlloc") - sysAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2") + sysAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ when leakDetector and not hasThreadSupport: @@ -511,9 +511,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize 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") #if res.refcount <% rcIncrement: # add(gch.zct, res) @@ -728,7 +728,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)) @@ -778,8 +778,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)) @@ -854,9 +854,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 template forEachStackSlot(gch, gcMark: expr) {.immediate, dirty.} = @@ -866,8 +866,8 @@ else: type PStackSlice = ptr array [0..7, pointer] var registers {.noinit.}: 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)) + var max = cast[ByteAddress](gch.stackBottom) + var sp = cast[ByteAddress](addr(registers)) # loop unrolled: while sp <% max - 8*sizeof(pointer): gcMark(gch, cast[PStackSlice](sp)[0]) @@ -1040,7 +1040,7 @@ when not defined(useNimRtl): else: dec(gch.recGcLock) - proc GC_setStrategy(strategy: TGC_Strategy) = + proc GC_setStrategy(strategy: GC_Strategy) = discard proc GC_enableMarkAndSweep() = diff --git a/lib/system/gc2.nim b/lib/system/gc2.nim index 132da9885..ee52b54f5 100644 --- a/lib/system/gc2.nim +++ b/lib/system/gc2.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/system/gc_ms.nim b/lib/system/gc_ms.nim index 05bcdcc82..f90000a1c 100644 --- a/lib/system/gc_ms.nim +++ b/lib/system/gc_ms.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# A simple mark&sweep garbage collector for Nimrod. Define the +# A simple mark&sweep garbage collector for Nim. Define the # symbol ``gcUseBitvectors`` to generate a variant of this GC. {.push profiler:off.} @@ -80,11 +80,11 @@ template gcAssert(cond: bool, msg: string) = 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 @@ -169,7 +169,7 @@ proc initGC() = init(gch.marked) proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.gcsafe.} = - 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: @@ -181,7 +181,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) {.gcsafe.} = of nkNone: sysAssert(false, "forAllSlotsAux") proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) = - var d = cast[TAddress](dest) + var d = cast[ByteAddress](dest) if dest == nil: return # nothing to do if ntfNoRefs notin mt.flags: case mt.kind @@ -206,7 +206,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) = 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: for i in 0..s.len-1: @@ -220,7 +220,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer = gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1") collectCT(gch) var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell))) - gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2") + gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2") # now it is buffered in the ZCT res.typ = typ when leakDetector and not hasThreadSupport: @@ -280,9 +280,9 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer = var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize 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") when withBitvectors: excl(gch.allocated, ol) when reallyDealloc: rawDealloc(gch.region, ol) else: @@ -379,7 +379,7 @@ proc markGlobals(gch: var TGcHeap) = proc gcMark(gch: var TGcHeap, p: pointer) {.inline.} = # the addresses are not as cells on the stack, so turn them to cells: 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)) @@ -404,8 +404,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)) @@ -421,9 +421,9 @@ 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.} = @@ -440,7 +440,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".} @@ -452,9 +452,9 @@ 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 var @@ -465,8 +465,8 @@ elif stackIncreases: 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: @@ -480,9 +480,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.} = @@ -492,8 +492,8 @@ else: type PStackSlice = ptr array [0..7, pointer] var registers {.noinit.}: 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)) + var max = cast[ByteAddress](gch.stackBottom) + var sp = cast[ByteAddress](addr(registers)) # loop unrolled: while sp <% max - 8*sizeof(pointer): gcMark(gch, cast[PStackSlice](sp)[0]) @@ -546,7 +546,7 @@ when not defined(useNimRtl): else: dec(gch.recGcLock) - proc GC_setStrategy(strategy: TGC_Strategy) = discard + proc GC_setStrategy(strategy: GC_Strategy) = discard proc GC_enableMarkAndSweep() = gch.cycleThreshold = InitialThreshold diff --git a/lib/system/hti.nim b/lib/system/hti.nim index ef8f50831..4a8ab2485 100644 --- a/lib/system/hti.nim +++ b/lib/system/hti.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index 5c82db4da..a975bb7c2 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 423f63e2a..f76c0e515 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -18,7 +18,7 @@ type PSafePoint = ptr TSafePoint TSafePoint {.compilerproc, final.} = object prev: PSafePoint # points to next safe point - exc: ref E_Base + exc: ref Exception PCallFrame = ptr TCallFrame TCallFrame {.importc, nodecl, final.} = object @@ -97,13 +97,13 @@ proc rawWriteStackTrace(): string = else: result = "No stack traceback available\n" -proc raiseException(e: ref E_Base, ename: cstring) {. +proc raiseException(e: ref Exception, ename: cstring) {. compilerproc, asmNoStackFrame.} = e.name = ename if excHandler != nil: excHandler.exc = e else: - when nimrodStackTrace: + when NimStackTrace: var buf = rawWriteStackTrace() else: var buf = "" @@ -120,24 +120,24 @@ proc raiseException(e: ref E_Base, ename: cstring) {. proc reraiseException() {.compilerproc, asmNoStackFrame.} = if excHandler == nil: - raise newException(ENoExceptionToReraise, "no exception to reraise") + raise newException(ReraiseError, "no exception to reraise") else: asm """throw excHandler.exc;""" proc raiseOverflow {.exportc: "raiseOverflow", noreturn.} = - raise newException(EOverflow, "over- or underflow") + raise newException(OverflowError, "over- or underflow") proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn.} = - raise newException(EDivByZero, "divison by zero") + raise newException(DivByZeroError, "divison by zero") proc raiseRangeError() {.compilerproc, noreturn.} = - raise newException(EOutOfRange, "value out of range") + raise newException(RangeError, "value out of range") proc raiseIndexError() {.compilerproc, noreturn.} = - raise newException(EInvalidIndex, "index out of bounds") + raise newException(IndexError, "index out of bounds") proc raiseFieldError(f: string) {.compilerproc, noreturn.} = - raise newException(EInvalidField, f & " is not accessible") + raise newException(FieldError, f & " is not accessible") proc SetConstr() {.varargs, asmNoStackFrame, compilerproc.} = asm """ @@ -260,7 +260,7 @@ proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} = """ type - TDocument {.importc.} = object of TObject + TDocument {.importc.} = object of RootObj write: proc (text: cstring) {.nimcall.} writeln: proc (text: cstring) {.nimcall.} createAttribute: proc (identifier: cstring): ref TNode {.nimcall.} @@ -283,7 +283,7 @@ type DocumentTypeNode, DocumentFragmentNode, NotationNode - TNode* {.importc.} = object of TObject + TNode* {.importc.} = object of RootObj attributes*: seq[ref TNode] childNodes*: seq[ref TNode] data*: cstring @@ -621,7 +621,7 @@ proc chckObj(obj, subclass: PNimType) {.compilerproc.} = if x == subclass: return # optimized fast path while x != subclass: if x == nil: - raise newException(EInvalidObjectConversion, "invalid object conversion") + raise newException(ObjectConversionError, "invalid object conversion") x = x.base proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = diff --git a/lib/system/mmdisp.nim b/lib/system/mmdisp.nim index 606743f51..e091c0889 100644 --- a/lib/system/mmdisp.nim +++ b/lib/system/mmdisp.nim @@ -1,14 +1,14 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# Nimrod high-level memory manager: It supports Boehm's GC, no GC and the -# native Nimrod GC. The native Nimrod GC is the default. +# Nim high-level memory manager: It supports Boehm's GC, no GC and the +# native Nim GC. The native Nim GC is the default. #{.push checks:on, assertions:on.} {.push checks:off.} @@ -34,7 +34,7 @@ const type PPointer = ptr pointer - TByteArray = array[0..1000_0000, Byte] + TByteArray = array[0..1000_0000, byte] PByte = ptr TByteArray PString = ptr string @@ -267,7 +267,7 @@ elif defined(nogc) and defined(useMalloc): elif defined(nogc): # Even though we don't want the GC, we cannot simply use C's memory manager - # because Nimrod's runtime wants ``realloc`` to zero out the additional + # because Nim's runtime wants ``realloc`` to zero out the additional # space which C's ``realloc`` does not. And we cannot get the old size of an # object, because C does not support this operation... Even though every # possible implementation has to have a way to determine the object's size. @@ -308,7 +308,7 @@ elif defined(nogc): dest[] = src var allocator {.rtlThreadVar.}: TMemRegion - InstantiateForRegion(allocator) + instantiateForRegion(allocator) include "system/cellsets" diff --git a/lib/system/profiler.nim b/lib/system/profiler.nim index 8e4c51dd9..96ab6abc7 100644 --- a/lib/system/profiler.nim +++ b/lib/system/profiler.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# This file implements the Nimrod profiler. The profiler needs support by the +# This file implements the Nim profiler. The profiler needs support by the # code generator. The idea is to inject the instruction stream # with 'nimProfile()' calls. These calls are injected at every loop end # (except perhaps loops that have no side-effects). At every Nth call a diff --git a/lib/system/repr.nim b/lib/system/repr.nim index 8e1bc5f26..2de603cea 100644 --- a/lib/system/repr.nim +++ b/lib/system/repr.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -155,7 +155,7 @@ when not defined(useNimRtl): var bs = typ.base.size for i in 0..typ.size div bs - 1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl) + reprAux(result, cast[pointer](cast[ByteAddress](p) + i*bs), typ.base, cl) add result, "]" proc reprSequence(result: var string, p: pointer, typ: PNimType, @@ -167,7 +167,7 @@ when not defined(useNimRtl): var bs = typ.base.size for i in 0..cast[PGenericSeq](p).len-1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs), + reprAux(result, cast[pointer](cast[ByteAddress](p) + GenericSeqSize + i*bs), typ.base, cl) add result, "]" @@ -178,14 +178,14 @@ when not defined(useNimRtl): of nkSlot: add result, $n.name add result, " = " - reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl) + reprAux(result, cast[pointer](cast[ByteAddress](p) + n.offset), n.typ, cl) of nkList: for i in 0..n.len-1: if i > 0: add result, ",\n" reprRecordAux(result, p, n.sons[i], cl) of nkCase: var m = selectBranch(p, n) - reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl) + reprAux(result, cast[pointer](cast[ByteAddress](p) + n.offset), n.typ, cl) if m != nil: reprRecordAux(result, p, m, cl) proc reprRecord(result: var string, p: pointer, typ: PNimType, @@ -265,7 +265,7 @@ proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {. var bs = elemtyp.size for i in 0..length - 1: if i > 0: add result, ", " - reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), elemtyp, cl) + reprAux(result, cast[pointer](cast[ByteAddress](p) + i*bs), elemtyp, cl) add result, "]" deinitReprClosure(cl) diff --git a/lib/system/reprjs.nim b/lib/system/reprjs.nim index fd1cb5c8b..57237cfff 100644 --- a/lib/system/reprjs.nim +++ b/lib/system/reprjs.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/system/sets.nim b/lib/system/sets.nim index 794c65cb8..626d43c33 100644 --- a/lib/system/sets.nim +++ b/lib/system/sets.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 32d4c3e91..7908fbe4d 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -8,7 +8,7 @@ # -# Nimrod's standard IO library. It contains high-performance +# Nim's standard IO library. It contains high-performance # routines for reading and writing data to (buffered) files or # TTYs. @@ -16,33 +16,33 @@ # of the standard library! -proc fputs(c: cstring, f: TFile) {.importc: "fputs", header: "<stdio.h>", - tags: [FWriteIO].} -proc fgets(c: cstring, n: int, f: TFile): cstring {. - importc: "fgets", header: "<stdio.h>", tags: [FReadIO].} -proc fgetc(stream: TFile): cint {.importc: "fgetc", header: "<stdio.h>", - tags: [FReadIO].} -proc ungetc(c: cint, f: TFile) {.importc: "ungetc", header: "<stdio.h>", +proc fputs(c: cstring, f: File) {.importc: "fputs", header: "<stdio.h>", + tags: [WriteIOEffect].} +proc fgets(c: cstring, n: int, f: File): cstring {. + importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].} +proc fgetc(stream: File): cint {.importc: "fgetc", header: "<stdio.h>", + tags: [ReadIOEffect].} +proc ungetc(c: cint, f: File) {.importc: "ungetc", header: "<stdio.h>", tags: [].} -proc putc(c: char, stream: TFile) {.importc: "putc", header: "<stdio.h>", - tags: [FWriteIO].} -proc fprintf(f: TFile, frmt: cstring) {.importc: "fprintf", - header: "<stdio.h>", varargs, tags: [FWriteIO].} +proc putc(c: char, stream: File) {.importc: "putc", header: "<stdio.h>", + tags: [WriteIOEffect].} +proc fprintf(f: File, frmt: cstring) {.importc: "fprintf", + header: "<stdio.h>", varargs, tags: [WriteIOEffect].} proc strlen(c: cstring): int {. importc: "strlen", header: "<string.h>", tags: [].} # C routine that is used here: -proc fread(buf: pointer, size, n: int, f: TFile): int {. - importc: "fread", header: "<stdio.h>", tags: [FReadIO].} -proc fseek(f: TFile, offset: clong, whence: int): int {. +proc fread(buf: pointer, size, n: int, f: File): int {. + importc: "fread", header: "<stdio.h>", tags: [ReadIOEffect].} +proc fseek(f: File, offset: clong, whence: int): int {. importc: "fseek", header: "<stdio.h>", tags: [].} -proc ftell(f: TFile): int {.importc: "ftell", header: "<stdio.h>", tags: [].} -proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {. +proc ftell(f: File): int {.importc: "ftell", header: "<stdio.h>", tags: [].} +proc setvbuf(stream: File, buf: pointer, typ, size: cint): cint {. importc, header: "<stdio.h>", tags: [].} {.push stackTrace:off, profiler:off.} -proc write(f: TFile, c: cstring) = fputs(c, f) +proc write(f: File, c: cstring) = fputs(c, f) {.pop.} when NoFakeVars: @@ -65,9 +65,9 @@ const BufSize = 4000 proc raiseEIO(msg: string) {.noinline, noreturn.} = - sysFatal(EIO, msg) + sysFatal(IOError, msg) -proc readLine(f: TFile, line: var TaintedString): bool = +proc readLine(f: File, line: var TaintedString): bool = # of course this could be optimized a bit; but IO is slow anyway... # and it was difficult to get this CORRECT with Ansi C's methods setLen(line.string, 0) # reuse the buffer! @@ -84,34 +84,34 @@ proc readLine(f: TFile, line: var TaintedString): bool = add line.string, chr(int(c)) result = true -proc readLine(f: TFile): TaintedString = +proc readLine(f: File): TaintedString = result = TaintedString(newStringOfCap(80)) if not readLine(f, result): raiseEIO("EOF reached") -proc write(f: TFile, i: int) = +proc write(f: File, i: int) = when sizeof(int) == 8: fprintf(f, "%lld", i) else: fprintf(f, "%ld", i) -proc write(f: TFile, i: BiggestInt) = +proc write(f: File, i: BiggestInt) = when sizeof(BiggestInt) == 8: fprintf(f, "%lld", i) else: fprintf(f, "%ld", i) -proc write(f: TFile, b: bool) = +proc write(f: File, b: bool) = if b: write(f, "true") else: write(f, "false") -proc write(f: TFile, r: float32) = fprintf(f, "%g", r) -proc write(f: TFile, r: BiggestFloat) = fprintf(f, "%g", r) +proc write(f: File, r: float32) = fprintf(f, "%g", r) +proc write(f: File, r: BiggestFloat) = fprintf(f, "%g", r) -proc write(f: TFile, c: char) = putc(c, f) -proc write(f: TFile, a: varargs[string, `$`]) = +proc write(f: File, c: char) = putc(c, f) +proc write(f: File, a: varargs[string, `$`]) = for x in items(a): write(f, x) -proc readAllBuffer(file: TFile): string = - # This proc is for TFile we want to read but don't know how many +proc readAllBuffer(file: File): string = + # This proc is for File we want to read but don't know how many # bytes we need to read before the buffer is empty. result = "" var buffer = newString(BufSize) @@ -124,27 +124,27 @@ proc readAllBuffer(file: TFile): string = result.add(buffer) break -proc rawFileSize(file: TFile): int = +proc rawFileSize(file: File): int = # this does not raise an error opposed to `getFileSize` var oldPos = ftell(file) discard fseek(file, 0, 2) # seek the end of the file result = ftell(file) discard fseek(file, clong(oldPos), 0) -proc readAllFile(file: TFile, len: int): string = +proc readAllFile(file: File, len: int): string = # We aquire 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: raiseEIO("error while reading from file") -proc readAllFile(file: TFile): string = +proc readAllFile(file: File): string = var len = rawFileSize(file) result = readAllFile(file, len) -proc readAll(file: TFile): TaintedString = +proc readAll(file: File): TaintedString = # Separate handling needed because we need to buffer when we - # don't know the overall length of the TFile. + # don't know the overall length of the File. var len = rawFileSize(file) if len >= 0: result = readAllFile(file, len).TaintedString @@ -165,13 +165,13 @@ proc writeFile(filename, content: string) = finally: close(f) -proc endOfFile(f: TFile): bool = +proc endOfFile(f: File): bool = # do not blame me; blame the ANSI C standard this is so brain-damaged var c = fgetc(f) ungetc(c, f) return c < 0'i32 -proc writeln[Ty](f: TFile, x: varargs[Ty, `$`]) = +proc writeln[Ty](f: File, x: varargs[Ty, `$`]) = for i in items(x): write(f, i) write(f, "\n") @@ -186,7 +186,7 @@ when (defined(windows) and not defined(useWinAnsi)) or defined(nimdoc): when defined(windows) and not defined(useWinAnsi): proc wfopen(filename, mode: WideCString): pointer {. importc: "_wfopen", nodecl.} - proc wfreopen(filename, mode: WideCString, stream: TFile): TFile {. + proc wfreopen(filename, mode: WideCString, stream: File): File {. importc: "_wfreopen", nodecl.} proc fopen(filename, mode: cstring): pointer = @@ -194,82 +194,82 @@ when defined(windows) and not defined(useWinAnsi): var m = newWideCString(mode) result = wfopen(f, m) - proc freopen(filename, mode: cstring, stream: TFile): TFile = + proc freopen(filename, mode: cstring, stream: File): File = var f = newWideCString(filename) var m = newWideCString(mode) result = wfreopen(f, m, stream) else: proc fopen(filename, mode: cstring): pointer {.importc: "fopen", noDecl.} - proc freopen(filename, mode: cstring, stream: TFile): TFile {. + proc freopen(filename, mode: cstring, stream: File): File {. importc: "freopen", nodecl.} const - FormatOpen: array [TFileMode, string] = ["rb", "wb", "w+b", "r+b", "ab"] + FormatOpen: array [FileMode, string] = ["rb", "wb", "w+b", "r+b", "ab"] #"rt", "wt", "w+t", "r+t", "at" - # we always use binary here as for Nimrod the OS line ending + # we always use binary here as for Nim the OS line ending # should not be translated. -proc open(f: var TFile, filename: string, - mode: TFileMode = fmRead, +proc open(f: var File, filename: string, + mode: FileMode = fmRead, bufSize: int = -1): bool = var p: pointer = fopen(filename, FormatOpen[mode]) - result = (p != nil) - f = cast[TFile](p) - if bufSize > 0 and bufSize <= high(cint).int: - if setvbuf(f, nil, IOFBF, bufSize.cint) != 0'i32: - sysFatal(EOutOfMemory, "out of memory") - elif bufSize == 0: - discard setvbuf(f, nil, IONBF, 0) - -proc reopen(f: TFile, filename: string, mode: TFileMode = fmRead): bool = + if p != nil: + result = true + f = cast[File](p) + if bufSize > 0 and bufSize <= high(cint).int: + discard setvbuf(f, nil, IOFBF, bufSize.cint) + elif bufSize == 0: + discard setvbuf(f, nil, IONBF, 0) + +proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool = var p: pointer = freopen(filename, FormatOpen[mode], f) result = p != nil -proc fdopen(filehandle: TFileHandle, mode: cstring): TFile {. +proc fdopen(filehandle: FileHandle, mode: cstring): File {. importc: pccHack & "fdopen", header: "<stdio.h>".} -proc open(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool = +proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool = f = fdopen(filehandle, FormatOpen[mode]) result = f != nil -proc fwrite(buf: pointer, size, n: int, f: TFile): int {. +proc fwrite(buf: pointer, size, n: int, f: File): int {. importc: "fwrite", noDecl.} -proc readBuffer(f: TFile, buffer: pointer, len: int): int = +proc readBuffer(f: File, buffer: pointer, len: int): int = result = fread(buffer, 1, len, f) -proc readBytes(f: TFile, a: var openArray[int8], start, len: int): int = +proc readBytes(f: File, a: var openArray[int8], start, len: int): int = result = readBuffer(f, addr(a[start]), len) -proc readChars(f: TFile, a: var openArray[char], start, len: int): int = +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: TFile, a: openArray[int8], start, len: int): int = +proc writeBytes(f: File, a: openArray[int8], 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: TFile, a: openArray[char], start, len: int): int = +proc writeChars(f: File, a: openArray[char], start, len: int): int = var x = cast[ptr array[0..1000_000_000, int8]](a) result = writeBuffer(f, addr(x[start]), len) -proc writeBuffer(f: TFile, buffer: pointer, len: int): int = +proc writeBuffer(f: File, buffer: pointer, len: int): int = result = fwrite(buffer, 1, len, f) -proc write(f: TFile, s: string) = +proc write(f: File, s: string) = if writeBuffer(f, cstring(s), s.len) != s.len: raiseEIO("cannot write string to file") {.pop.} -proc setFilePos(f: TFile, pos: int64) = +proc setFilePos(f: File, pos: int64) = if fseek(f, clong(pos), 0) != 0: raiseEIO("cannot set file position") -proc getFilePos(f: TFile): int64 = +proc getFilePos(f: File): int64 = result = ftell(f) if result < 0: raiseEIO("cannot retrieve file position") -proc getFileSize(f: TFile): int64 = +proc getFileSize(f: File): int64 = var oldPos = getFilePos(f) discard fseek(f, 0, 2) # seek the end of the file result = getFilePos(f) diff --git a/lib/system/syslocks.nim b/lib/system/syslocks.nim index b8ed29cfc..8b38f34f3 100644 --- a/lib/system/syslocks.nim +++ b/lib/system/syslocks.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -31,7 +31,7 @@ when defined(Windows): ## Tries to acquire the lock `L`. proc tryAcquireSys(L: var TSysLock): bool {.inline.} = - result = TryAcquireSysAux(L) != 0'i32 + result = tryAcquireSysAux(L) != 0'i32 proc acquireSys(L: var TSysLock) {.stdcall, noSideEffect, dynlib: "kernel32", importc: "EnterCriticalSection".} diff --git a/lib/system/sysspawn.nim b/lib/system/sysspawn.nim index 5161104a9..04f30872d 100644 --- a/lib/system/sysspawn.nim +++ b/lib/system/sysspawn.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## Implements Nimrod's 'spawn'. +## Implements Nim's 'spawn'. when not declared(NimString): {.error: "You must not import this module explicitly".} diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim index bc79bb254..ba973e9b5 100644 --- a/lib/system/sysstr.nim +++ b/lib/system/sysstr.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -119,7 +119,7 @@ proc addChar(s: NimString, c: char): NimString = inc(result.len) # These routines should be used like following: -# <Nimrod code> +# <Nim code> # s &= "Hello " & name & ", how do you feel?" # # <generated C code> @@ -130,7 +130,7 @@ proc addChar(s: NimString, c: char): NimString = # appendString(s, strLit3); # } # -# <Nimrod code> +# <Nim code> # s = "Hello " & name & ", how do you feel?" # # <generated C code> @@ -143,7 +143,7 @@ proc addChar(s: NimString, c: char): NimString = # s = tmp0; # } # -# <Nimrod code> +# <Nim code> # s = "" # # <generated C code> @@ -217,7 +217,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. gch.tempStack.len = len0 else: for i in newLen..result.len-1: - forAllChildrenAux(cast[pointer](cast[TAddress](result) +% + forAllChildrenAux(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% (i*%elemSize)), extGetCellType(result).base, waZctDecRef) @@ -227,7 +227,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {. # presense 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[TAddress](result) +% GenericSeqSize +% + zeroMem(cast[pointer](cast[ByteAddress](result) +% GenericSeqSize +% (newLen*%elemSize)), (result.len-%newLen) *% elemSize) result.len = newLen diff --git a/lib/system/threads.nim b/lib/system/threads.nim index c30c57fb9..7dac9d9aa 100644 --- a/lib/system/threads.nim +++ b/lib/system/threads.nim @@ -353,8 +353,7 @@ when hostOS == "windows": t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg], addr(t), 0'i32, dummyThreadId) if t.sys <= 0: - raise newException(EResourceExhausted, "cannot create thread") - + raise newException(ResourceExhaustedError, "cannot create thread") else: proc createThread*[TArg](t: var TThread[TArg], tp: proc (arg: TArg) {.thread.}, @@ -369,7 +368,7 @@ else: pthread_attr_init(a) pthread_attr_setstacksize(a, ThreadStackSize) if pthread_create(t.sys, a, threadProcWrapper[TArg], addr(t)) != 0: - raise newException(EResourceExhausted, "cannot create thread") + raise newException(ResourceExhaustedError, "cannot create thread") proc threadId*[TArg](t: var TThread[TArg]): TThreadId[TArg] {.inline.} = ## returns the thread ID of `t`. diff --git a/lib/system/timers.nim b/lib/system/timers.nim index fa1a13a5f..e58ff7adc 100644 --- a/lib/system/timers.nim +++ b/lib/system/timers.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/system/widestrs.nim b/lib/system/widestrs.nim index cd64ff410..1e8bc6791 100644 --- a/lib/system/widestrs.nim +++ b/lib/system/widestrs.nim @@ -1,13 +1,13 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -# Nimrod support for C/C++'s `wide strings`:idx:. This is part of the system +# Nim support for C/C++'s `wide strings`:idx:. This is part of the system # module! Do not import it directly! when not declared(NimString): diff --git a/lib/windows/mmsystem.nim b/lib/windows/mmsystem.nim index 91279a5ef..45613d8e2 100644 --- a/lib/windows/mmsystem.nim +++ b/lib/windows/mmsystem.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2006 Andreas Rumpf # # See the file "copying.txt", included in this @@ -27,15 +27,15 @@ import windows type - MMRESULT* = UINT - MMVERSION* = UINT + MMRESULT* = uint32 + MMVERSION* = uint32 HWAVEOUT* = THandle LPHWAVEOUT* = ptr HWAVEOUT HWAVEIN* = THandle LPHWAVEIN* = ptr HWAVEOUT HWAVE* = THandle LPHWAVE* = ptr THandle - LPUINT* = ptr UINT + LPUINT* = ptr uint32 const MAXPNAMELEN* = 32 @@ -178,18 +178,18 @@ const DRV_MCI_LAST* = (DRV_RESERVED + 0x00000FFF) type - PDRVCALLBACK* = proc (hdrvr: tHandle, uMsg: UINT, dwUser, dw1, dw2: DWORD){. + PDRVCALLBACK* = proc (hdrvr: THandle, uMsg: uint32, dwUser, dw1, dw2: DWORD){. stdcall.} -proc sndPlaySoundA*(Name: LPCSTR, flags: UINT): BOOL{.stdcall, +proc sndPlaySoundA*(Name: LPCSTR, flags: uint32): bool{.stdcall, dynlib: "winmm.dll", importc: "sndPlaySoundA".} -proc sndPlaySoundW*(Name: LPCWSTR, flags: UINT): BOOL{.stdcall, +proc sndPlaySoundW*(Name: LPCWSTR, flags: uint32): bool{.stdcall, dynlib: "winmm.dll", importc: "sndPlaySoundW".} when defined(winUNICODE): - proc sndPlaySound*(Name: cstring, flags: UINT): BOOL{.stdcall, + proc sndPlaySound*(Name: cstring, flags: uint32): bool{.stdcall, dynlib: "winmm.dll", importc: "sndPlaySoundW".} else: - proc sndPlaySound*(Name: cstring, flags: UINT): BOOL{.stdcall, + proc sndPlaySound*(Name: cstring, flags: uint32): bool{.stdcall, dynlib: "winmm.dll", importc: "sndPlaySoundA".} const SND_NODEFAULT* = 2 @@ -225,12 +225,12 @@ const WIM_OPEN* = MM_WIM_OPEN WIM_CLOSE* = MM_WIM_CLOSE WIM_DATA* = MM_WIM_DATA - WAVE_MAPPER* = UINT(- 1) + WAVE_MAPPER* = uint32(- 1) WAVE_FORMAT_QUERY* = 1 WAVE_ALLOWSYNC* = 2 WAVE_MAPPED* = 4 WAVE_FORMAT_DIRECT* = 8 - WAVE_FORMAT_DIRECT_QUERY* = (WAVE_FORMAT_QUERY Or WAVE_FORMAT_DIRECT) + WAVE_FORMAT_DIRECT_QUERY* = (WAVE_FORMAT_QUERY or WAVE_FORMAT_DIRECT) MIM_OPEN* = MM_MIM_OPEN MIM_CLOSE* = MM_MIM_CLOSE MIM_DATA* = MM_MIM_DATA @@ -242,7 +242,7 @@ const MOM_DONE* = MM_MOM_DONE MIM_MOREDATA* = MM_MIM_MOREDATA MOM_POSITIONCB* = MM_MOM_POSITIONCB - MIDIMAPPER* = UINT(- 1) + MIDIMAPPER* = uint32(- 1) MIDI_IO_STATUS* = 32 MIDI_CACHE_ALL* = 1 MIDI_CACHE_BESTFIT* = 2 @@ -364,53 +364,53 @@ const MIXERCONTROL_CT_UNITS_DECIBELS* = 0x00040000 MIXERCONTROL_CT_UNITS_PERCENT* = 0x00050000 MIXERCONTROL_CONTROLTYPE_CUSTOM* = ( - MIXERCONTROL_CT_CLASS_CUSTOM Or MIXERCONTROL_CT_UNITS_CUSTOM) - MIXERCONTROL_CONTROLTYPE_BOOLEANMETER* = (MIXERCONTROL_CT_CLASS_METER Or - MIXERCONTROL_CT_SC_METER_POLLED Or MIXERCONTROL_CT_UNITS_BOOLEAN) - MIXERCONTROL_CONTROLTYPE_SIGNEDMETER* = (MIXERCONTROL_CT_CLASS_METER Or - MIXERCONTROL_CT_SC_METER_POLLED Or MIXERCONTROL_CT_UNITS_SIGNED) + MIXERCONTROL_CT_CLASS_CUSTOM or MIXERCONTROL_CT_UNITS_CUSTOM) + MIXERCONTROL_CONTROLTYPE_BOOLEANMETER* = (MIXERCONTROL_CT_CLASS_METER or + MIXERCONTROL_CT_SC_METER_POLLED or MIXERCONTROL_CT_UNITS_BOOLEAN) + MIXERCONTROL_CONTROLTYPE_SIGNEDMETER* = (MIXERCONTROL_CT_CLASS_METER or + MIXERCONTROL_CT_SC_METER_POLLED or MIXERCONTROL_CT_UNITS_SIGNED) MIXERCONTROL_CONTROLTYPE_PEAKMETER* = ( MIXERCONTROL_CONTROLTYPE_SIGNEDMETER + 1) - MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER* = (MIXERCONTROL_CT_CLASS_METER Or - MIXERCONTROL_CT_SC_METER_POLLED Or MIXERCONTROL_CT_UNITS_UNSIGNED) - MIXERCONTROL_CONTROLTYPE_BOOLEAN* = (MIXERCONTROL_CT_CLASS_SWITCH Or - MIXERCONTROL_CT_SC_SWITCH_BOOLEAN Or MIXERCONTROL_CT_UNITS_BOOLEAN) + MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER* = (MIXERCONTROL_CT_CLASS_METER or + MIXERCONTROL_CT_SC_METER_POLLED or MIXERCONTROL_CT_UNITS_UNSIGNED) + MIXERCONTROL_CONTROLTYPE_BOOLEAN* = (MIXERCONTROL_CT_CLASS_SWITCH or + MIXERCONTROL_CT_SC_SWITCH_BOOLEAN or MIXERCONTROL_CT_UNITS_BOOLEAN) MIXERCONTROL_CONTROLTYPE_ONOFF* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 1) MIXERCONTROL_CONTROLTYPE_MUTE* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 2) MIXERCONTROL_CONTROLTYPE_MONO* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 3) MIXERCONTROL_CONTROLTYPE_LOUDNESS* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 4) MIXERCONTROL_CONTROLTYPE_STEREOENH* = (MIXERCONTROL_CONTROLTYPE_BOOLEAN + 5) - MIXERCONTROL_CONTROLTYPE_BUTTON* = (MIXERCONTROL_CT_CLASS_SWITCH Or - MIXERCONTROL_CT_SC_SWITCH_BUTTON Or MIXERCONTROL_CT_UNITS_BOOLEAN) + MIXERCONTROL_CONTROLTYPE_BUTTON* = (MIXERCONTROL_CT_CLASS_SWITCH or + MIXERCONTROL_CT_SC_SWITCH_BUTTON or MIXERCONTROL_CT_UNITS_BOOLEAN) MIXERCONTROL_CONTROLTYPE_DECIBELS* = ( - MIXERCONTROL_CT_CLASS_NUMBER Or MIXERCONTROL_CT_UNITS_DECIBELS) + MIXERCONTROL_CT_CLASS_NUMBER or MIXERCONTROL_CT_UNITS_DECIBELS) MIXERCONTROL_CONTROLTYPE_SIGNED* = ( - MIXERCONTROL_CT_CLASS_NUMBER Or MIXERCONTROL_CT_UNITS_SIGNED) + MIXERCONTROL_CT_CLASS_NUMBER or MIXERCONTROL_CT_UNITS_SIGNED) MIXERCONTROL_CONTROLTYPE_UNSIGNED* = ( - MIXERCONTROL_CT_CLASS_NUMBER Or MIXERCONTROL_CT_UNITS_UNSIGNED) + MIXERCONTROL_CT_CLASS_NUMBER or MIXERCONTROL_CT_UNITS_UNSIGNED) MIXERCONTROL_CONTROLTYPE_PERCENT* = ( - MIXERCONTROL_CT_CLASS_NUMBER Or MIXERCONTROL_CT_UNITS_PERCENT) + MIXERCONTROL_CT_CLASS_NUMBER or MIXERCONTROL_CT_UNITS_PERCENT) MIXERCONTROL_CONTROLTYPE_SLIDER* = ( - MIXERCONTROL_CT_CLASS_SLIDER Or MIXERCONTROL_CT_UNITS_SIGNED) + MIXERCONTROL_CT_CLASS_SLIDER or MIXERCONTROL_CT_UNITS_SIGNED) MIXERCONTROL_CONTROLTYPE_PAN* = (MIXERCONTROL_CONTROLTYPE_SLIDER + 1) MIXERCONTROL_CONTROLTYPE_QSOUNDPAN* = (MIXERCONTROL_CONTROLTYPE_SLIDER + 2) MIXERCONTROL_CONTROLTYPE_FADER* = ( - MIXERCONTROL_CT_CLASS_FADER Or MIXERCONTROL_CT_UNITS_UNSIGNED) + MIXERCONTROL_CT_CLASS_FADER or MIXERCONTROL_CT_UNITS_UNSIGNED) MIXERCONTROL_CONTROLTYPE_VOLUME* = (MIXERCONTROL_CONTROLTYPE_FADER + 1) MIXERCONTROL_CONTROLTYPE_BASS* = (MIXERCONTROL_CONTROLTYPE_FADER + 2) MIXERCONTROL_CONTROLTYPE_TREBLE* = (MIXERCONTROL_CONTROLTYPE_FADER + 3) MIXERCONTROL_CONTROLTYPE_EQUALIZER* = (MIXERCONTROL_CONTROLTYPE_FADER + 4) - MIXERCONTROL_CONTROLTYPE_SINGLESELECT* = (MIXERCONTROL_CT_CLASS_LIST Or - MIXERCONTROL_CT_SC_LIST_SINGLE Or MIXERCONTROL_CT_UNITS_BOOLEAN) + MIXERCONTROL_CONTROLTYPE_SINGLESELECT* = (MIXERCONTROL_CT_CLASS_LIST or + MIXERCONTROL_CT_SC_LIST_SINGLE or MIXERCONTROL_CT_UNITS_BOOLEAN) MIXERCONTROL_CONTROLTYPE_MUX* = (MIXERCONTROL_CONTROLTYPE_SINGLESELECT + 1) - MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT* = (MIXERCONTROL_CT_CLASS_LIST Or - MIXERCONTROL_CT_SC_LIST_MULTIPLE Or MIXERCONTROL_CT_UNITS_BOOLEAN) + MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT* = (MIXERCONTROL_CT_CLASS_LIST or + MIXERCONTROL_CT_SC_LIST_MULTIPLE or MIXERCONTROL_CT_UNITS_BOOLEAN) MIXERCONTROL_CONTROLTYPE_MIXER* = (MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT + 1) - MIXERCONTROL_CONTROLTYPE_MICROTIME* = (MIXERCONTROL_CT_CLASS_TIME Or - MIXERCONTROL_CT_SC_TIME_MICROSECS Or MIXERCONTROL_CT_UNITS_UNSIGNED) - MIXERCONTROL_CONTROLTYPE_MILLITIME* = (MIXERCONTROL_CT_CLASS_TIME Or - MIXERCONTROL_CT_SC_TIME_MILLISECS Or MIXERCONTROL_CT_UNITS_UNSIGNED) + MIXERCONTROL_CONTROLTYPE_MICROTIME* = (MIXERCONTROL_CT_CLASS_TIME or + MIXERCONTROL_CT_SC_TIME_MICROSECS or MIXERCONTROL_CT_UNITS_UNSIGNED) + MIXERCONTROL_CONTROLTYPE_MILLITIME* = (MIXERCONTROL_CT_CLASS_TIME or + MIXERCONTROL_CT_SC_TIME_MILLISECS or MIXERCONTROL_CT_UNITS_UNSIGNED) MIXER_SHORT_NAME_CHARS* = 16 MIXER_LONG_NAME_CHARS* = 64 MIXERR_INVALLINE* = (MIXERR_BASE + 0) @@ -419,15 +419,15 @@ const MIXERR_LASTERROR* = (MIXERR_BASE + 2) MIXER_OBJECTF_HANDLE* = 0x80000000 MIXER_OBJECTF_MIXER* = 0 - MIXER_OBJECTF_HMIXER* = (MIXER_OBJECTF_HANDLE Or MIXER_OBJECTF_MIXER) + MIXER_OBJECTF_HMIXER* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_MIXER) MIXER_OBJECTF_WAVEOUT* = 0x10000000 - MIXER_OBJECTF_HWAVEOUT* = (MIXER_OBJECTF_HANDLE Or MIXER_OBJECTF_WAVEOUT) + MIXER_OBJECTF_HWAVEOUT* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_WAVEOUT) MIXER_OBJECTF_WAVEIN* = 0x20000000 - MIXER_OBJECTF_HWAVEIN* = (MIXER_OBJECTF_HANDLE Or MIXER_OBJECTF_WAVEIN) + MIXER_OBJECTF_HWAVEIN* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_WAVEIN) MIXER_OBJECTF_MIDIOUT* = 0x30000000 - MIXER_OBJECTF_HMIDIOUT* = (MIXER_OBJECTF_HANDLE Or MIXER_OBJECTF_MIDIOUT) + MIXER_OBJECTF_HMIDIOUT* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_MIDIOUT) MIXER_OBJECTF_MIDIIN* = 0x40000000 - MIXER_OBJECTF_HMIDIIN* = (MIXER_OBJECTF_HANDLE Or MIXER_OBJECTF_MIDIIN) + MIXER_OBJECTF_HMIDIIN* = (MIXER_OBJECTF_HANDLE or MIXER_OBJECTF_MIDIIN) MIXER_OBJECTF_AUX* = 0x50000000 MIXER_GETCONTROLDETAILSF_VALUE* = 0 MIXER_GETCONTROLDETAILSF_LISTTEXT* = 1 @@ -492,8 +492,8 @@ const JOY_RETURNPOVCTS* = 512 JOY_RETURNCENTERED* = 0x00000400 JOY_USEDEADZONE* = 0x00000800 - JOY_RETURNALL* = (JOY_RETURNX Or JOY_RETURNY Or JOY_RETURNZ Or JOY_RETURNR Or - JOY_RETURNU Or JOY_RETURNV Or JOY_RETURNPOV Or JOY_RETURNBUTTONS) + JOY_RETURNALL* = (JOY_RETURNX or JOY_RETURNY or JOY_RETURNZ or JOY_RETURNR or + JOY_RETURNU or JOY_RETURNV or JOY_RETURNPOV or JOY_RETURNBUTTONS) JOY_CAL_READALWAYS* = 0x00010000 JOY_CAL_READXYONLY* = 0x00020000 JOY_CAL_READ3* = 0x00040000 @@ -982,17 +982,17 @@ const #///////////////////////////////////////////////////////// type - mmtime* {.final.} = object - wType*: UINT + MMTIME* {.final.} = object + wType*: uint32 hour*, min*, sec*, frame*, fps*, dummy*: int8 pad*: array[0..1, int8] - PMMTIME* = ptr mmtime - NPMMTIME* = ptr mmtime - LPMMTIME* = ptr mmtime - PWAVEHDR* = ptr wavehdr - TMMTime* = mmtime - wavehdr* {.final.} = object + PMMTIME* = ptr MMTIME + NPMMTIME* = ptr MMTIME + LPMMTIME* = ptr MMTIME + PWAVEHDR* = ptr WAVEHDR + TMMTime* = MMTIME + WAVEHDR* {.final.} = object lpData*: cstring dwBufferLength*: DWORD dwBytesRecorded*: DWORD @@ -1003,13 +1003,13 @@ type reserved*: DWORD TWAVEHDR* = WAVEHDR - NPWAVEHDR* = ptr wavehdr - LPWAVEHDR* = ptr wavehdr + NPWAVEHDR* = ptr WAVEHDR + LPWAVEHDR* = ptr WAVEHDR WAVEOUTCAPSA* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), CHAR] + szPname*: array[0..pred(MAXPNAMELEN), char] dwFormats*: DWORD wChannels*: int16 wReserved1*: int16 @@ -1023,7 +1023,7 @@ type wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), WCHAR] + szPname*: array[0..pred(MAXPNAMELEN), WCHAR] dwFormats*: DWORD wChannels*: int16 wReserved1*: int16 @@ -1052,7 +1052,7 @@ type wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), CHAR] + szPname*: array[0..pred(MAXPNAMELEN), char] dwFormats*: DWORD wChannels*: int16 wReserved1*: int16 @@ -1065,7 +1065,7 @@ type wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), WCHAR] + szPname*: array[0..pred(MAXPNAMELEN), WCHAR] dwFormats*: DWORD wChannels*: int16 wReserved1*: int16 @@ -1089,29 +1089,29 @@ else: LPWAVEINCAPS* = LPWAVEINCAPSA type TWAVEINCAPS* = WAVEINCAPS - waveformat* {.final.} = object + WAVEFORMAT* {.final.} = object wFormatTag*: int16 nChannels*: int16 nSamplesPerSec*: DWORD nAvgBytesPerSec*: DWORD nBlockAlign*: int16 - PWAVEFORMAT* = ptr waveformat - NPWAVEFORMAT* = ptr waveformat - LPWAVEFORMAT* = ptr waveformat - TWAVEFORMAT* = waveformat + PWAVEFORMAT* = ptr WAVEFORMAT + NPWAVEFORMAT* = ptr WAVEFORMAT + LPWAVEFORMAT* = ptr WAVEFORMAT + TWAVEFORMAT* = WAVEFORMAT const WAVE_FORMAT_PCM* = 1 type - pcmwaveformat* {.final.} = object + PCMWAVEFORMAT* {.final.} = object wf*: WAVEFORMAT wBitsPerSample*: int16 - PPCMWAVEFORMAT* = ptr pcmwaveformat - NPPCMWAVEFORMAT* = ptr pcmwaveformat - LPPCMWAVEFORMAT* = ptr pcmwaveformat + PPCMWAVEFORMAT* = ptr PCMWAVEFORMAT + NPPCMWAVEFORMAT* = ptr PCMWAVEFORMAT + LPPCMWAVEFORMAT* = ptr PCMWAVEFORMAT TPCMWAVEFORMAT* = PCMWAVEFORMAT WAVEFORMATEX* {.final.} = object wFormatTag*: int16 @@ -1141,15 +1141,15 @@ const MIDIPATCHSIZE* = 128 type - PATCHARRAY* = array[0..Pred(MIDIPATCHSIZE), int16] + PATCHARRAY* = array[0..pred(MIDIPATCHSIZE), int16] LPPATCHARRAY* = ptr int16 - KEYARRAY* = array[0..Pred(MIDIPATCHSIZE), int16] + KEYARRAY* = array[0..pred(MIDIPATCHSIZE), int16] LPKEYARRAY* = ptr int16 MIDIOUTCAPSA* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), CHAR] + szPname*: array[0..pred(MAXPNAMELEN), char] wTechnology*: int16 wVoices*: int16 wNotes*: int16 @@ -1164,7 +1164,7 @@ type wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), WCHAR] + szPname*: array[0..pred(MAXPNAMELEN), Wchar] wTechnology*: int16 wVoices*: int16 wNotes*: int16 @@ -1179,7 +1179,7 @@ type wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), CHAR] + szPname*: array[0..pred(MAXPNAMELEN), char] dwSupport*: DWORD PMIDIINCAPSA* = ptr MIDIINCAPSA @@ -1190,7 +1190,7 @@ type wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), WCHAR] + szPname*: array[0..pred(MAXPNAMELEN), Wchar] dwSupport*: DWORD PMIDIINCAPSW* = ptr MIDIINCAPSW @@ -1220,8 +1220,8 @@ else: LPMIDIINCAPS* = LPMIDIINCAPSA type TMIDIINCAPS* = MIDIINCAPS - PMIDIHDR* = ptr midihdr - midihdr* {.final.} = object + PMIDIHDR* = ptr MIDIHDR + MIDIHDR* {.final.} = object lpData*: cstring dwBufferLength*: DWORD dwBytesRecorded*: DWORD @@ -1230,19 +1230,19 @@ type lpNext*: PMIDIHDR reserved*: DWORD dwOffset*: DWORD - dwReserved*: array[0..Pred(8), DWORD] + dwReserved*: array[0..pred(8), DWORD] - NPMIDIHDR* = ptr midihdr - LPMIDIHDR* = ptr midihdr + NPMIDIHDR* = ptr MIDIHDR + LPMIDIHDR* = ptr MIDIHDR TMIDIHDR* = MIDIHDR - midievent* {.final.} = object + MIDIEVENT* {.final.} = object dwDeltaTime*: DWORD dwStreamID*: DWORD dwEvent*: DWORD - dwParms*: array[0..Pred(1), DWORD] + dwParms*: array[0..pred(1), DWORD] TMIDIEVENT* = MIDIEVENT - midistrmbuffver* {.final.} = object + MIDISTRMBUFFVER* {.final.} = object dwVersion*: DWORD dwMid*: DWORD dwOEMVersion*: DWORD @@ -1262,7 +1262,7 @@ type wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), CHAR] + szPname*: array[0..pred(MAXPNAMELEN), char] wTechnology*: int16 wReserved1*: int16 dwSupport*: DWORD @@ -1275,7 +1275,7 @@ type wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), WCHAR] + szPname*: array[0..pred(MAXPNAMELEN), Wchar] wTechnology*: int16 wReserved1*: int16 dwSupport*: DWORD @@ -1304,14 +1304,14 @@ type HMIXER* = THandle LPHMIXER* = ptr HMIXER -proc mixerGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll", +proc mixerGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll", importc: "mixerGetNumDevs".} type MIXERCAPSA* {.final.} = object wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), CHAR] + szPname*: array[0..pred(MAXPNAMELEN), char] fdwSupport*: DWORD cDestinations*: DWORD @@ -1322,7 +1322,7 @@ type wMid*: int16 wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..Pred(MAXPNAMELEN), WCHAR] + szPname*: array[0..pred(MAXPNAMELEN), Wchar] fdwSupport*: DWORD cDestinations*: DWORD @@ -1353,12 +1353,12 @@ type cChannels*: DWORD cConnections*: DWORD cControls*: DWORD - szShortName*: array[0..Pred(MIXER_SHORT_NAME_CHARS), CHAR] - szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), CHAR] + szShortName*: array[0..pred(MIXER_SHORT_NAME_CHARS), char] + szName*: array[0..pred(MIXER_LONG_NAME_CHARS), char] dwType*, dwDeviceID*: DWORD wMid*, wPid*: int16 vDriverVersion*: MMVERSION - szPname*: array[0..pred(MAXPNAMELEN), Char] + szPname*: array[0..pred(MAXPNAMELEN), char] PMIXERLINEA* = ptr MIXERLINEA LPMIXERLINEA* = ptr MIXERLINEA @@ -1374,8 +1374,8 @@ type cChannels*: DWORD cConnections*: DWORD cControls*: DWORD - szShortName*: array[0..Pred(MIXER_SHORT_NAME_CHARS), WCHAR] - szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), WCHAR] + szShortName*: array[0..pred(MIXER_SHORT_NAME_CHARS), WCHAR] + szName*: array[0..pred(MIXER_LONG_NAME_CHARS), WCHAR] dwType*, dwDeviceID*: DWORD wMid*, wPid*: int16 vDriverVersion*: MMVERSION @@ -1403,8 +1403,8 @@ type dwControlType*: DWORD fdwControl*: DWORD cMultipleItems*: DWORD - szShortName*: array[0..Pred(MIXER_SHORT_NAME_CHARS), CHAR] - szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), CHAR] + szShortName*: array[0..pred(MIXER_SHORT_NAME_CHARS), char] + szName*: array[0..pred(MIXER_LONG_NAME_CHARS), char] dwMinimum*, dwMaximum*: DWORD dwReserved*: array[0..3, DWORD] cSteps*: DWORD @@ -1419,8 +1419,8 @@ type dwControlType*: DWORD fdwControl*: DWORD cMultipleItems*: DWORD - szShortName*: array[0..Pred(MIXER_SHORT_NAME_CHARS), WCHAR] - szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), WCHAR] + szShortName*: array[0..pred(MIXER_SHORT_NAME_CHARS), WCHAR] + szName*: array[0..pred(MIXER_LONG_NAME_CHARS), WCHAR] dwMinimum*, dwMaximum*: DWORD dwReserved*: array[0..3, DWORD] cSteps*: DWORD @@ -1478,15 +1478,15 @@ type dwControlID*: DWORD cChannels*: DWORD cMultipleItems*, cbDetails*: DWORD - paDetails*: Pointer + paDetails*: pointer - MIXERCONTROLDETAILS* = tMIXERCONTROLDETAILS - PMIXERCONTROLDETAILS* = ptr tMIXERCONTROLDETAILS - LPMIXERCONTROLDETAILS* = ptr tMIXERCONTROLDETAILS + MIXERCONTROLDETAILS* = TMIXERCONTROLDETAILS + PMIXERCONTROLDETAILS* = ptr TMIXERCONTROLDETAILS + LPMIXERCONTROLDETAILS* = ptr TMIXERCONTROLDETAILS MIXERCONTROLDETAILS_LISTTEXTA* {.final.} = object dwParam1*: DWORD dwParam2*: DWORD - szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), CHAR] + szName*: array[0..pred(MIXER_LONG_NAME_CHARS), char] PMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA LPMIXERCONTROLDETAILS_LISTTEXTA* = ptr MIXERCONTROLDETAILS_LISTTEXTA @@ -1494,7 +1494,7 @@ type MIXERCONTROLDETAILS_LISTTEXTW* {.final.} = object dwParam1*: DWORD dwParam2*: DWORD - szName*: array[0..Pred(MIXER_LONG_NAME_CHARS), WCHAR] + szName*: array[0..pred(MIXER_LONG_NAME_CHARS), WCHAR] PMIXERCONTROLDETAILS_LISTTEXTW* = ptr MIXERCONTROLDETAILS_LISTTEXTW LPMIXERCONTROLDETAILS_LISTTEXTW* = ptr MIXERCONTROLDETAILS_LISTTEXTW @@ -1530,42 +1530,42 @@ type PMIXERCONTROLDETAILS_UNSIGNED* = ptr MIXERCONTROLDETAILS_UNSIGNED LPMIXERCONTROLDETAILS_UNSIGNED* = ptr MIXERCONTROLDETAILS_UNSIGNED TMIXERCONTROLDETAILS_UNSIGNED* = MIXERCONTROLDETAILS_UNSIGNED - LPTIMECALLBACK* = proc (uTimerID, uMsg: UINT, dwUser, dw1, dw2: DWORD){. + LPTIMECALLBACK* = proc (uTimerID, uMsg: uint32, dwUser, dw1, dw2: DWORD){. stdcall.} TTIMECALLBACK* = LPTIMECALLBACK - timecaps* {.final.} = object - wPeriodMin*: UINT - wPeriodMax*: UINT + TIMECAPS* {.final.} = object + wPeriodMin*: uint32 + wPeriodMax*: uint32 - PTIMECAPS* = ptr timecaps - NPTIMECAPS* = ptr timecaps - LPTIMECAPS* = ptr timecaps + PTIMECAPS* = ptr TIMECAPS + NPTIMECAPS* = ptr TIMECAPS + LPTIMECAPS* = ptr TIMECAPS TTIMECAS* = TIMECAPS JOYCAPSA* {.final.} = object wMid*: int16 wPid*: int16 - szPname*: array[0..Pred(MAXPNAMELEN), CHAR] - wXmin*: UINT - wXmax*: UINT - wYmin*: UINT - wYmax*: UINT - wZmin*: UINT - wZmax*: UINT - wNumButtons*: UINT - wPeriodMin*: UINT - wPeriodMax*: UINT - wRmin*: UINT - wRmax*: UINT - wUmin*: UINT - wUmax*: UINT - wVmin*: UINT - wVmax*: UINT - wCaps*: UINT - wMaxAxes*: UINT - wNumAxes*: UINT - wMaxButtons*: UINT - szRegKey*: array[0..Pred(MAXPNAMELEN), CHAR] - szOEMVxD*: array[0..Pred(MAX_JOYSTICKOEMVXDNAME), CHAR] + szPname*: array[0..pred(MAXPNAMELEN), char] + wXmin*: uint32 + wXmax*: uint32 + wYmin*: uint32 + wYmax*: uint32 + wZmin*: uint32 + wZmax*: uint32 + wNumButtons*: uint32 + wPeriodMin*: uint32 + wPeriodMax*: uint32 + wRmin*: uint32 + wRmax*: uint32 + wUmin*: uint32 + wUmax*: uint32 + wVmin*: uint32 + wVmax*: uint32 + wCaps*: uint32 + wMaxAxes*: uint32 + wNumAxes*: uint32 + wMaxButtons*: uint32 + szRegKey*: array[0..pred(MAXPNAMELEN), char] + szOEMVxD*: array[0..pred(MAX_JOYSTICKOEMVXDNAME), char] PJOYCAPSA* = ptr JOYCAPSA NPJOYCAPSA* = ptr JOYCAPSA @@ -1574,28 +1574,28 @@ type JOYCAPSW* {.final.} = object wMid*: int16 wPid*: int16 - szPname*: array[0..Pred(MAXPNAMELEN), WCHAR] - wXmin*: UINT - wXmax*: UINT - wYmin*: UINT - wYmax*: UINT - wZmin*: UINT - wZmax*: UINT - wNumButtons*: UINT - wPeriodMin*: UINT - wPeriodMax*: UINT - wRmin*: UINT - wRmax*: UINT - wUmin*: UINT - wUmax*: UINT - wVmin*: UINT - wVmax*: UINT - wCaps*: UINT - wMaxAxes*: UINT - wNumAxes*: UINT - wMaxButtons*: UINT - szRegKey*: array[0..Pred(MAXPNAMELEN), WCHAR] - szOEMVxD*: array[0..Pred(MAX_JOYSTICKOEMVXDNAME), WCHAR] + szPname*: array[0..pred(MAXPNAMELEN), WCHAR] + wXmin*: uint32 + wXmax*: uint32 + wYmin*: uint32 + wYmax*: uint32 + wZmin*: uint32 + wZmax*: uint32 + wNumButtons*: uint32 + wPeriodMin*: uint32 + wPeriodMax*: uint32 + wRmin*: uint32 + wRmax*: uint32 + wUmin*: uint32 + wUmax*: uint32 + wVmin*: uint32 + wVmax*: uint32 + wCaps*: uint32 + wMaxAxes*: uint32 + wNumAxes*: uint32 + wMaxButtons*: uint32 + szRegKey*: array[0..pred(MAXPNAMELEN), WCHAR] + szOEMVxD*: array[0..pred(MAX_JOYSTICKOEMVXDNAME), WCHAR] PJOYCAPSW* = ptr JOYCAPSW NPJOYCAPSW* = ptr JOYCAPSW @@ -1616,45 +1616,45 @@ else: LPJOYCAPS* = LPJOYCAPSA type TJOYCAPS* = JOYCAPS - joyinfo* {.final.} = object - wXpos*: UINT - wYpos*: UINT - wZpos*: UINT - wButtons*: UINT - - PJOYINFO* = ptr joyinfo - NPJOYINFO* = ptr joyinfo - LPJOYINFO* = ptr joyinfo + JOYINFO* {.final.} = object + wXpos*: uint32 + wYpos*: uint32 + wZpos*: uint32 + wButtons*: uint32 + + PJOYINFO* = ptr JOYINFO + NPJOYINFO* = ptr JOYINFO + LPJOYINFO* = ptr JOYINFO TJOYINFO* = JOYINFO - joyinfoex* {.final.} = object + JOYINFOEX* {.final.} = object dwSize*: DWORD dwFlags*: DWORD - wXpos*: UINT - wYpos*: UINT - wZpos*: UINT + wXpos*: uint32 + wYpos*: uint32 + wZpos*: uint32 dwRpos*: DWORD dwUpos*: DWORD dwVpos*: DWORD - wButtons*: UINT + wButtons*: uint32 dwButtonNumber*: DWORD dwPOV*: DWORD dwReserved1*: DWORD dwReserved2*: DWORD - PJOYINFOEX* = ptr joyinfoex - NPJOYINFOEX* = ptr joyinfoex - LPJOYINFOEX* = ptr joyinfoex + PJOYINFOEX* = ptr JOYINFOEX + NPJOYINFOEX* = ptr JOYINFOEX + LPJOYINFOEX* = ptr JOYINFOEX TJOYINFOEX* = JOYINFOEX FOURCC* = DWORD HPSTR* = cstring HMMIO* = THandle - LPMMIOPROC* = proc (x1: LPSTR, x2: UINT, x3, x4: LPARAM): LRESULT{.stdcall.} + LPMMIOPROC* = proc (x1: LPSTR, x2: uint32, x3, x4: LPARAM): LRESULT{.stdcall.} TMMIOPROC* = LPMMIOPROC MMIOINFO* {.final.} = object dwFlags*: DWORD fccIOProc*: FOURCC pIOProc*: LPMMIOPROC - wErrorRet*: UINT + wErrorRet*: uint32 htask*: HTASK cchBuffer*: int32 pchBuffer*: HPSTR @@ -1663,7 +1663,7 @@ type pchEndWrite*: HPSTR lBufOffset*: int32 lDiskOffset*: int32 - adwInfo*: array[0..Pred(3), DWORD] + adwInfo*: array[0..pred(3), DWORD] dwReserved1*: DWORD dwReserved2*: DWORD hmmio*: HMMIO @@ -1686,8 +1686,8 @@ type LPCMMCKINFO* = ptr MMCKINFO TMMCKINFO* = MMCKINFO MCIERROR* = DWORD - MCIDEVICEID* = UINT - YIELDPROC* = proc (mciId: MCIDEVICEID, dwYieldData: DWORD): UINT{.stdcall.} + MCIDEVICEID* = uint32 + YIELDPROC* = proc (mciId: MCIDEVICEID, dwYieldData: DWORD): uint32{.stdcall.} TYIELDPROC* = YIELDPROC MCI_GENERIC_PARMS* {.final.} = object dwCallback*: DWORD @@ -1790,7 +1790,7 @@ type lpstrReturn*: cstring dwRetSize*: DWORD dwNumber*: DWORD - wDeviceType*: UINT + wDeviceType*: uint32 PMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA LPMCI_SYSINFO_PARMSA* = ptr MCI_SYSINFO_PARMSA @@ -1800,7 +1800,7 @@ type lpstrReturn*: LPWSTR dwRetSize*: DWORD dwNumber*: DWORD - wDeviceType*: UINT + wDeviceType*: uint32 PMCI_SYSINFO_PARMSW* = ptr MCI_SYSINFO_PARMSW LPMCI_SYSINFO_PARMSW* = ptr MCI_SYSINFO_PARMSW @@ -1984,8 +1984,8 @@ type dwCallback*: DWORD dwTimeFormat*: DWORD dwAudio*: DWORD - wInput*: UINT - wOutput*: UINT + wInput*: uint32 + wOutput*: uint32 wFormatTag*: int16 wReserved2*: int16 nChannels*: int16 @@ -2052,7 +2052,7 @@ type MCI_ANIM_WINDOW_PARMSW* {.final.} = object dwCallback*: DWORD hWnd*: HWND - nCmdShow*: UINT + nCmdShow*: uint32 lpstrText*: LPCWSTR PMCI_ANIM_WINDOW_PARMSW* = ptr MCI_ANIM_WINDOW_PARMSW @@ -2068,7 +2068,7 @@ type MCI_ANIM_WINDOW_PARMSA* {.final.} = object dwCallback*: DWORD hWnd*: HWND - nCmdShow*: UINT + nCmdShow*: uint32 lpstrText*: LPCSTR PMCI_ANIM_WINDOW_PARMSA* = ptr MCI_ANIM_WINDOW_PARMSA @@ -2149,7 +2149,7 @@ type MCI_OVLY_WINDOW_PARMSA* {.final.} = object dwCallback*: DWORD hWnd*: HWND - nCmdShow*: UINT + nCmdShow*: uint32 lpstrText*: LPCSTR PMCI_OVLY_WINDOW_PARMSA* = ptr MCI_OVLY_WINDOW_PARMSA @@ -2158,7 +2158,7 @@ type MCI_OVLY_WINDOW_PARMSW* {.final.} = object dwCallback*: DWORD hWnd*: HWND - nCmdShow*: UINT + nCmdShow*: uint32 lpstrText*: LPCWSTR PMCI_OVLY_WINDOW_PARMSW* = ptr MCI_OVLY_WINDOW_PARMSW @@ -2243,14 +2243,11 @@ else: type TMCI_OVLY_LOAD_PARMS* = MCI_OVLY_LOAD_PARMS -type - pcmwaveformat_tag* = PCMWAVEFORMAT - -proc mmioStringToFOURCCA*(x1: LPCSTR, x2: UINT): FOURCC{.stdcall, +proc mmioStringToFOURCCA*(x1: LPCSTR, x2: uint32): FOURCC{.stdcall, dynlib: "winmm.dll", importc: "mmioStringToFOURCCA".} -proc mmioStringToFOURCCW*(x1: LPCWSTR, x2: UINT): FOURCC{.stdcall, +proc mmioStringToFOURCCW*(x1: LPCWSTR, x2: uint32): FOURCC{.stdcall, dynlib: "winmm.dll", importc: "mmioStringToFOURCCW".} -proc mmioStringToFOURCC*(x1: cstring, x2: UINT): FOURCC{.stdcall, +proc mmioStringToFOURCC*(x1: cstring, x2: uint32): FOURCC{.stdcall, dynlib: "winmm.dll", importc: "mmioStringToFOURCCA".} proc mmioInstallIOProcA*(x1: FOURCC, x2: LPMMIOPROC, x3: DWORD): LPMMIOPROC{. stdcall, dynlib: "winmm.dll", importc: "mmioInstallIOProcA".} @@ -2270,7 +2267,7 @@ proc mmioRenameW*(x1: LPCWSTR, x2: LPCWSTR, x3: LPCMMIOINFO, x4: DWORD): MMRESUL stdcall, dynlib: "winmm.dll", importc: "mmioRenameW".} proc mmioRename*(x1: cstring, x2: cstring, x3: LPCMMIOINFO, x4: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mmioRenameA".} -proc mmioClose*(x1: HMMIO, x2: UINT): MMRESULT{.stdcall, dynlib: "winmm.dll", +proc mmioClose*(x1: HMMIO, x2: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mmioClose".} proc mmioRead*(x1: HMMIO, x2: HPSTR, x3: LONG): LONG{.stdcall, dynlib: "winmm.dll", importc: "mmioRead".} @@ -2278,35 +2275,35 @@ proc mmioWrite*(x1: HMMIO, x2: cstring, x3: LONG): LONG{.stdcall, dynlib: "winmm.dll", importc: "mmioWrite".} proc mmioSeek*(x1: HMMIO, x2: LONG, x3: WINT): LONG{.stdcall, dynlib: "winmm.dll", importc: "mmioSeek".} -proc mmioGetInfo*(x1: HMMIO, x2: LPMMIOINFO, x3: UINT): MMRESULT{.stdcall, +proc mmioGetInfo*(x1: HMMIO, x2: LPMMIOINFO, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mmioGetInfo".} -proc mmioSetInfo*(x1: HMMIO, x2: LPCMMIOINFO, x3: UINT): MMRESULT{.stdcall, +proc mmioSetInfo*(x1: HMMIO, x2: LPCMMIOINFO, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mmioSetInfo".} -proc mmioSetBuffer*(x1: HMMIO, x2: LPSTR, x3: LONG, x4: UINT): MMRESULT{. +proc mmioSetBuffer*(x1: HMMIO, x2: LPSTR, x3: LONG, x4: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mmioSetBuffer".} -proc mmioFlush*(x1: HMMIO, x2: UINT): MMRESULT{.stdcall, dynlib: "winmm.dll", +proc mmioFlush*(x1: HMMIO, x2: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mmioFlush".} -proc mmioAdvance*(x1: HMMIO, x2: LPMMIOINFO, x3: UINT): MMRESULT{.stdcall, +proc mmioAdvance*(x1: HMMIO, x2: LPMMIOINFO, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mmioAdvance".} -proc mmioSendMessage*(x1: HMMIO, x2: UINT, x3: LPARAM, x4: LPARAM): LRESULT{. +proc mmioSendMessage*(x1: HMMIO, x2: uint32, x3: LPARAM, x4: LPARAM): LRESULT{. stdcall, dynlib: "winmm.dll", importc: "mmioSendMessage".} -proc mmioDescend*(x1: HMMIO, x2: LPMMCKINFO, x3: PMMCKINFO, x4: UINT): MMRESULT{. +proc mmioDescend*(x1: HMMIO, x2: LPMMCKINFO, x3: PMMCKINFO, x4: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mmioDescend".} -proc mmioAscend*(x1: HMMIO, x2: LPMMCKINFO, x3: UINT): MMRESULT{.stdcall, +proc mmioAscend*(x1: HMMIO, x2: LPMMCKINFO, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mmioAscend".} -proc mmioCreateChunk*(x1: HMMIO, x2: LPMMCKINFO, x3: UINT): MMRESULT{.stdcall, +proc mmioCreateChunk*(x1: HMMIO, x2: LPMMCKINFO, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mmioCreateChunk".} -proc mciSendCommandA*(x1: MCIDEVICEID, x2: UINT, x3: DWORD, x4: DWORD): MCIERROR{. +proc mciSendCommandA*(x1: MCIDEVICEID, x2: uint32, x3: DWORD, x4: DWORD): MCIERROR{. stdcall, dynlib: "winmm.dll", importc: "mciSendCommandA".} -proc mciSendCommandW*(x1: MCIDEVICEID, x2: UINT, x3: DWORD, x4: DWORD): MCIERROR{. +proc mciSendCommandW*(x1: MCIDEVICEID, x2: uint32, x3: DWORD, x4: DWORD): MCIERROR{. stdcall, dynlib: "winmm.dll", importc: "mciSendCommandW".} -proc mciSendCommand*(x1: MCIDEVICEID, x2: UINT, x3: DWORD, x4: DWORD): MCIERROR{. +proc mciSendCommand*(x1: MCIDEVICEID, x2: uint32, x3: DWORD, x4: DWORD): MCIERROR{. stdcall, dynlib: "winmm.dll", importc: "mciSendCommandA".} -proc mciSendStringA*(x1: LPCSTR, x2: LPSTR, x3: UINT, x4: HWND): MCIERROR{. +proc mciSendStringA*(x1: LPCSTR, x2: LPSTR, x3: uint32, x4: HWND): MCIERROR{. stdcall, dynlib: "winmm.dll", importc: "mciSendStringA".} -proc mciSendStringW*(x1: LPCWSTR, x2: LPWSTR, x3: UINT, x4: HWND): MCIERROR{. +proc mciSendStringW*(x1: LPCWSTR, x2: LPWSTR, x3: uint32, x4: HWND): MCIERROR{. stdcall, dynlib: "winmm.dll", importc: "mciSendStringW".} -proc mciSendString*(x1: cstring, x2: cstring, x3: UINT, x4: HWND): MCIERROR{. +proc mciSendString*(x1: cstring, x2: cstring, x3: uint32, x4: HWND): MCIERROR{. stdcall, dynlib: "winmm.dll", importc: "mciSendStringA".} proc mciGetDeviceIDA*(x1: LPCSTR): MCIDEVICEID{.stdcall, dynlib: "winmm.dll", importc: "mciGetDeviceIDA".} @@ -2320,60 +2317,60 @@ proc mciGetDeviceIDFromElementIDW*(x1: DWORD, x2: LPCWSTR): MCIDEVICEID{. stdcall, dynlib: "winmm.dll", importc: "mciGetDeviceIDFromElementIDW".} proc mciGetDeviceIDFromElementID*(x1: DWORD, x2: cstring): MCIDEVICEID{.stdcall, dynlib: "winmm.dll", importc: "mciGetDeviceIDFromElementIDA".} -proc mciGetErrorStringA*(x1: MCIERROR, x2: LPSTR, x3: UINT): BOOL{.stdcall, +proc mciGetErrorStringA*(x1: MCIERROR, x2: LPSTR, x3: uint32): bool{.stdcall, dynlib: "winmm.dll", importc: "mciGetErrorStringA".} -proc mciGetErrorStringW*(x1: MCIERROR, x2: LPWSTR, x3: UINT): BOOL{.stdcall, +proc mciGetErrorStringW*(x1: MCIERROR, x2: LPWSTR, x3: uint32): bool{.stdcall, dynlib: "winmm.dll", importc: "mciGetErrorStringW".} -proc mciGetErrorString*(x1: MCIERROR, x2: cstring, x3: UINT): BOOL{.stdcall, +proc mciGetErrorString*(x1: MCIERROR, x2: cstring, x3: uint32): bool{.stdcall, dynlib: "winmm.dll", importc: "mciGetErrorStringA".} -proc mciSetYieldProc*(x1: MCIDEVICEID, x2: YIELDPROC, x3: DWORD): BOOL{.stdcall, +proc mciSetYieldProc*(x1: MCIDEVICEID, x2: YIELDPROC, x3: DWORD): bool{.stdcall, dynlib: "winmm.dll", importc: "mciSetYieldProc".} proc mciGetCreatorTask*(x1: MCIDEVICEID): HTASK{.stdcall, dynlib: "winmm.dll", importc: "mciGetCreatorTask".} proc mciGetYieldProc*(x1: MCIDEVICEID, x2: LPDWORD): YIELDPROC{.stdcall, dynlib: "winmm.dll", importc: "mciGetYieldProc".} -proc mciExecute*(x1: LPCSTR): BOOL{.stdcall, dynlib: "winmm.dll", +proc mciExecute*(x1: LPCSTR): bool{.stdcall, dynlib: "winmm.dll", importc: "mciExecute".} -proc joyGetPos*(x1: UINT, x2: LPJOYINFO): MMRESULT{.stdcall, +proc joyGetPos*(x1: uint32, x2: LPJOYINFO): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "joyGetPos".} -proc joyGetPosEx*(x1: UINT, x2: LPJOYINFOEX): MMRESULT{.stdcall, +proc joyGetPosEx*(x1: uint32, x2: LPJOYINFOEX): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "joyGetPosEx".} -proc joyGetThreshold*(x1: UINT, x2: LPUINT): MMRESULT{.stdcall, +proc joyGetThreshold*(x1: uint32, x2: LPUINT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "joyGetThreshold".} -proc joyReleaseCapture*(x1: UINT): MMRESULT{.stdcall, dynlib: "winmm.dll", +proc joyReleaseCapture*(x1: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "joyReleaseCapture".} -proc joySetCapture*(x1: HWND, x2: UINT, x3: UINT, x4: BOOL): MMRESULT{.stdcall, +proc joySetCapture*(x1: HWND, x2: uint32, x3: uint32, x4: bool): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "joySetCapture".} -proc joySetThreshold*(x1: UINT, x2: UINT): MMRESULT{.stdcall, +proc joySetThreshold*(x1: uint32, x2: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "joySetThreshold".} -proc waveOutGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll", +proc waveOutGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll", importc: "waveOutGetNumDevs".} -proc waveOutGetDevCapsA*(x1: UINT, x2: LPWAVEOUTCAPSA, x3: UINT): MMRESULT{. +proc waveOutGetDevCapsA*(x1: uint32, x2: LPWAVEOUTCAPSA, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutGetDevCapsA".} -proc waveOutGetDevCapsW*(x1: UINT, x2: LPWAVEOUTCAPSW, x3: UINT): MMRESULT{. +proc waveOutGetDevCapsW*(x1: uint32, x2: LPWAVEOUTCAPSW, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutGetDevCapsW".} -proc waveOutGetDevCaps*(x1: UINT, x2: LPWAVEOUTCAPS, x3: UINT): MMRESULT{. +proc waveOutGetDevCaps*(x1: uint32, x2: LPWAVEOUTCAPS, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutGetDevCapsA".} proc waveOutGetVolume*(x1: HWAVEOUT, x2: LPDWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutGetVolume".} proc waveOutSetVolume*(x1: HWAVEOUT, x2: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutSetVolume".} -proc waveOutGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: UINT): MMRESULT{. +proc waveOutGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutGetErrorTextA".} -proc waveOutGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: UINT): MMRESULT{. +proc waveOutGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutGetErrorTextW".} -proc waveOutGetErrorText*(x1: MMRESULT, x2: cstring, x3: UINT): MMRESULT{. +proc waveOutGetErrorText*(x1: MMRESULT, x2: cstring, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutGetErrorTextA".} -proc waveOutOpen*(x1: LPHWAVEOUT, x2: UINT, x3: LPCWAVEFORMATEX, x4: DWORD, +proc waveOutOpen*(x1: LPHWAVEOUT, x2: uint32, x3: LPCWAVEFORMATEX, x4: DWORD, x5: DWORD, x6: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutOpen".} proc waveOutClose*(x1: HWAVEOUT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutClose".} -proc waveOutPrepareHeader*(x1: HWAVEOUT, x2: LPWAVEHDR, x3: UINT): MMRESULT{. +proc waveOutPrepareHeader*(x1: HWAVEOUT, x2: LPWAVEHDR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutPrepareHeader".} -proc waveOutUnprepareHeader*(x1: HWAVEOUT, x2: LPWAVEHDR, x3: UINT): MMRESULT{. +proc waveOutUnprepareHeader*(x1: HWAVEOUT, x2: LPWAVEHDR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutUnprepareHeader".} -proc waveOutWrite*(x1: HWAVEOUT, x2: LPWAVEHDR, x3: UINT): MMRESULT{.stdcall, +proc waveOutWrite*(x1: HWAVEOUT, x2: LPWAVEHDR, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutWrite".} proc waveOutPause*(x1: HWAVEOUT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutPause".} @@ -2383,7 +2380,7 @@ proc waveOutReset*(x1: HWAVEOUT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutReset".} proc waveOutBreakLoop*(x1: HWAVEOUT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutBreakLoop".} -proc waveOutGetPosition*(x1: HWAVEOUT, x2: LPMMTIME, x3: UINT): MMRESULT{. +proc waveOutGetPosition*(x1: HWAVEOUT, x2: LPMMTIME, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutGetPosition".} proc waveOutGetPitch*(x1: HWAVEOUT, x2: LPDWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutGetPitch".} @@ -2395,32 +2392,32 @@ proc waveOutSetPlaybackRate*(x1: HWAVEOUT, x2: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutSetPlaybackRate".} proc waveOutGetID*(x1: HWAVEOUT, x2: LPUINT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveOutGetID".} -proc waveOutMessage*(x1: HWAVEOUT, x2: UINT, x3: DWORD, x4: DWORD): MMRESULT{. +proc waveOutMessage*(x1: HWAVEOUT, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveOutMessage".} -proc waveInGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll", +proc waveInGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll", importc: "waveInGetNumDevs".} -proc waveInGetDevCapsA*(x1: UINT, x2: LPWAVEINCAPSA, x3: UINT): MMRESULT{. +proc waveInGetDevCapsA*(x1: uint32, x2: LPWAVEINCAPSA, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveInGetDevCapsA".} -proc waveInGetDevCapsW*(x1: UINT, x2: LPWAVEINCAPSW, x3: UINT): MMRESULT{. +proc waveInGetDevCapsW*(x1: uint32, x2: LPWAVEINCAPSW, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveInGetDevCapsW".} -proc waveInGetDevCaps*(x1: UINT, x2: LPWAVEINCAPS, x3: UINT): MMRESULT{.stdcall, +proc waveInGetDevCaps*(x1: uint32, x2: LPWAVEINCAPS, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInGetDevCapsA".} -proc waveInGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: UINT): MMRESULT{.stdcall, +proc waveInGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInGetErrorTextA".} -proc waveInGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: UINT): MMRESULT{. +proc waveInGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveInGetErrorTextW".} -proc waveInGetErrorText*(x1: MMRESULT, x2: cstring, x3: UINT): MMRESULT{. +proc waveInGetErrorText*(x1: MMRESULT, x2: cstring, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveInGetErrorTextA".} -proc waveInOpen*(x1: LPHWAVEIN, x2: UINT, x3: LPCWAVEFORMATEX, x4: DWORD, +proc waveInOpen*(x1: LPHWAVEIN, x2: uint32, x3: LPCWAVEFORMATEX, x4: DWORD, x5: DWORD, x6: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInOpen".} proc waveInClose*(x1: HWAVEIN): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInClose".} -proc waveInPrepareHeader*(x1: HWAVEIN, x2: LPWAVEHDR, x3: UINT): MMRESULT{. +proc waveInPrepareHeader*(x1: HWAVEIN, x2: LPWAVEHDR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveInPrepareHeader".} -proc waveInUnprepareHeader*(x1: HWAVEIN, x2: LPWAVEHDR, x3: UINT): MMRESULT{. +proc waveInUnprepareHeader*(x1: HWAVEIN, x2: LPWAVEHDR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveInUnprepareHeader".} -proc waveInAddBuffer*(x1: HWAVEIN, x2: LPWAVEHDR, x3: UINT): MMRESULT{.stdcall, +proc waveInAddBuffer*(x1: HWAVEIN, x2: LPWAVEHDR, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInAddBuffer".} proc waveInStart*(x1: HWAVEIN): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInStart".} @@ -2428,11 +2425,11 @@ proc waveInStop*(x1: HWAVEIN): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInStop".} proc waveInReset*(x1: HWAVEIN): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInReset".} -proc waveInGetPosition*(x1: HWAVEIN, x2: LPMMTIME, x3: UINT): MMRESULT{.stdcall, +proc waveInGetPosition*(x1: HWAVEIN, x2: LPMMTIME, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInGetPosition".} proc waveInGetID*(x1: HWAVEIN, x2: LPUINT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "waveInGetID".} -proc waveInMessage*(x1: HWAVEIN, x2: UINT, x3: DWORD, x4: DWORD): MMRESULT{. +proc waveInMessage*(x1: HWAVEIN, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "waveInMessage".} proc mixerGetLineControlsA*(x1: HMIXEROBJ, x2: LPMIXERLINECONTROLSA, x3: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mixerGetLineControlsA".} @@ -2440,13 +2437,13 @@ proc mixerGetLineControlsW*(x1: HMIXEROBJ, x2: LPMIXERLINECONTROLSW, x3: DWORD): stdcall, dynlib: "winmm.dll", importc: "mixerGetLineControlsW".} proc mixerGetLineControls*(x1: HMIXEROBJ, x2: LPMIXERLINECONTROLS, x3: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mixerGetLineControlsA".} -proc joyGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll", +proc joyGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll", importc: "joyGetNumDevs".} -proc joyGetDevCapsA*(x1: UINT, x2: LPJOYCAPSA, x3: UINT): MMRESULT{.stdcall, +proc joyGetDevCapsA*(x1: uint32, x2: LPJOYCAPSA, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "joyGetDevCapsA".} -proc joyGetDevCapsW*(x1: UINT, x2: LPJOYCAPSW, x3: UINT): MMRESULT{.stdcall, +proc joyGetDevCapsW*(x1: uint32, x2: LPJOYCAPSW, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "joyGetDevCapsW".} -proc joyGetDevCaps*(x1: UINT, x2: LPJOYCAPS, x3: UINT): MMRESULT{.stdcall, +proc joyGetDevCaps*(x1: uint32, x2: LPJOYCAPS, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "joyGetDevCapsA".} proc mixerGetControlDetailsA*(x1: HMIXEROBJ, x2: LPMIXERCONTROLDETAILS, x3: DWORD): MMRESULT{.stdcall, @@ -2456,46 +2453,46 @@ proc mixerGetControlDetailsW*(x1: HMIXEROBJ, x2: LPMIXERCONTROLDETAILS, dynlib: "winmm.dll", importc: "mixerGetControlDetailsW".} proc mixerGetControlDetails*(x1: HMIXEROBJ, x2: LPMIXERCONTROLDETAILS, x3: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mixerGetControlDetailsA".} -proc timeGetSystemTime*(x1: LPMMTIME, x2: UINT): MMRESULT{.stdcall, +proc timeGetSystemTime*(x1: LPMMTIME, x2: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "timeGetSystemTime".} proc timeGetTime*(): DWORD{.stdcall, dynlib: "winmm.dll", importc: "timeGetTime".} -proc timeSetEvent*(x1: UINT, x2: UINT, x3: LPTIMECALLBACK, x4: DWORD, x5: UINT): MMRESULT{. +proc timeSetEvent*(x1: uint32, x2: uint32, x3: LPTIMECALLBACK, x4: DWORD, x5: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "timeSetEvent".} -proc timeKillEvent*(x1: UINT): MMRESULT{.stdcall, dynlib: "winmm.dll", +proc timeKillEvent*(x1: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "timeKillEvent".} -proc timeGetDevCaps*(x1: LPTIMECAPS, x2: UINT): MMRESULT{.stdcall, +proc timeGetDevCaps*(x1: LPTIMECAPS, x2: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "timeGetDevCaps".} -proc timeBeginPeriod*(x1: UINT): MMRESULT{.stdcall, dynlib: "winmm.dll", +proc timeBeginPeriod*(x1: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "timeBeginPeriod".} -proc timeEndPeriod*(x1: UINT): MMRESULT{.stdcall, dynlib: "winmm.dll", +proc timeEndPeriod*(x1: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "timeEndPeriod".} -proc mixerGetDevCapsA*(x1: UINT, x2: LPMIXERCAPSA, x3: UINT): MMRESULT{.stdcall, +proc mixerGetDevCapsA*(x1: uint32, x2: LPMIXERCAPSA, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mixerGetDevCapsA".} -proc mixerGetDevCapsW*(x1: UINT, x2: LPMIXERCAPSW, x3: UINT): MMRESULT{.stdcall, +proc mixerGetDevCapsW*(x1: uint32, x2: LPMIXERCAPSW, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mixerGetDevCapsW".} -proc mixerGetDevCaps*(x1: UINT, x2: LPMIXERCAPS, x3: UINT): MMRESULT{.stdcall, +proc mixerGetDevCaps*(x1: uint32, x2: LPMIXERCAPS, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mixerGetDevCapsA".} -proc mixerOpen*(x1: LPHMIXER, x2: UINT, x3: DWORD, x4: DWORD, x5: DWORD): MMRESULT{. +proc mixerOpen*(x1: LPHMIXER, x2: uint32, x3: DWORD, x4: DWORD, x5: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mixerOpen".} proc mixerClose*(x1: HMIXER): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mixerClose".} -proc mixerMessage*(x1: HMIXER, x2: UINT, x3: DWORD, x4: DWORD): DWORD{.stdcall, +proc mixerMessage*(x1: HMIXER, x2: uint32, x3: DWORD, x4: DWORD): DWORD{.stdcall, dynlib: "winmm.dll", importc: "mixerMessage".} -proc auxGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll", +proc auxGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll", importc: "auxGetNumDevs".} -proc auxGetDevCapsA*(x1: UINT, x2: LPAUXCAPSA, x3: UINT): MMRESULT{.stdcall, +proc auxGetDevCapsA*(x1: uint32, x2: LPAUXCAPSA, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "auxGetDevCapsA".} -proc auxGetDevCapsW*(x1: UINT, x2: LPAUXCAPSW, x3: UINT): MMRESULT{.stdcall, +proc auxGetDevCapsW*(x1: uint32, x2: LPAUXCAPSW, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "auxGetDevCapsW".} -proc auxGetDevCaps*(x1: UINT, x2: LPAUXCAPS, x3: UINT): MMRESULT{.stdcall, +proc auxGetDevCaps*(x1: uint32, x2: LPAUXCAPS, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "auxGetDevCapsA".} -proc auxSetVolume*(x1: UINT, x2: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", +proc auxSetVolume*(x1: uint32, x2: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "auxSetVolume".} -proc auxGetVolume*(x1: UINT, x2: LPDWORD): MMRESULT{.stdcall, +proc auxGetVolume*(x1: uint32, x2: LPDWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "auxGetVolume".} -proc auxOutMessage*(x1: UINT, x2: UINT, x3: DWORD, x4: DWORD): MMRESULT{. +proc auxOutMessage*(x1: uint32, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "auxOutMessage".} -proc midiOutGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll", +proc midiOutGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll", importc: "midiOutGetNumDevs".} proc midiStreamOpen*(x1: LPHMIDISTRM, x2: LPUINT, x3: DWORD, x4: DWORD, x5: DWORD, x6: DWORD): MMRESULT{.stdcall, @@ -2504,9 +2501,9 @@ proc midiStreamClose*(x1: HMIDISTRM): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiStreamClose".} proc midiStreamProperty*(x1: HMIDISTRM, x2: LPBYTE, x3: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiStreamProperty".} -proc midiStreamPosition*(x1: HMIDISTRM, x2: LPMMTIME, x3: UINT): MMRESULT{. +proc midiStreamPosition*(x1: HMIDISTRM, x2: LPMMTIME, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiStreamPosition".} -proc midiStreamOut*(x1: HMIDISTRM, x2: LPMIDIHDR, x3: UINT): MMRESULT{.stdcall, +proc midiStreamOut*(x1: HMIDISTRM, x2: LPMIDIHDR, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiStreamOut".} proc midiStreamPause*(x1: HMIDISTRM): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiStreamPause".} @@ -2518,67 +2515,67 @@ proc midiConnect*(x1: HMIDI, x2: HMIDIOUT, x3: pointer): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiConnect".} proc midiDisconnect*(x1: HMIDI, x2: HMIDIOUT, x3: pointer): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiDisconnect".} -proc midiOutGetDevCapsA*(x1: UINT, x2: LPMIDIOUTCAPSA, x3: UINT): MMRESULT{. +proc midiOutGetDevCapsA*(x1: uint32, x2: LPMIDIOUTCAPSA, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutGetDevCapsA".} -proc midiOutGetDevCapsW*(x1: UINT, x2: LPMIDIOUTCAPSW, x3: UINT): MMRESULT{. +proc midiOutGetDevCapsW*(x1: uint32, x2: LPMIDIOUTCAPSW, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutGetDevCapsW".} -proc midiOutGetDevCaps*(x1: UINT, x2: LPMIDIOUTCAPS, x3: UINT): MMRESULT{. +proc midiOutGetDevCaps*(x1: uint32, x2: LPMIDIOUTCAPS, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutGetDevCapsA".} proc midiOutGetVolume*(x1: HMIDIOUT, x2: LPDWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiOutGetVolume".} proc midiOutSetVolume*(x1: HMIDIOUT, x2: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiOutSetVolume".} -proc midiOutGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: UINT): MMRESULT{. +proc midiOutGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutGetErrorTextA".} -proc midiOutGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: UINT): MMRESULT{. +proc midiOutGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutGetErrorTextW".} -proc midiOutGetErrorText*(x1: MMRESULT, x2: cstring, x3: UINT): MMRESULT{. +proc midiOutGetErrorText*(x1: MMRESULT, x2: cstring, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutGetErrorTextA".} -proc midiOutOpen*(x1: LPHMIDIOUT, x2: UINT, x3: DWORD, x4: DWORD, x5: DWORD): MMRESULT{. +proc midiOutOpen*(x1: LPHMIDIOUT, x2: uint32, x3: DWORD, x4: DWORD, x5: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutOpen".} proc midiOutClose*(x1: HMIDIOUT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiOutClose".} -proc midiOutPrepareHeader*(x1: HMIDIOUT, x2: LPMIDIHDR, x3: UINT): MMRESULT{. +proc midiOutPrepareHeader*(x1: HMIDIOUT, x2: LPMIDIHDR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutPrepareHeader".} -proc midiOutUnprepareHeader*(x1: HMIDIOUT, x2: LPMIDIHDR, x3: UINT): MMRESULT{. +proc midiOutUnprepareHeader*(x1: HMIDIOUT, x2: LPMIDIHDR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutUnprepareHeader".} proc midiOutShortMsg*(x1: HMIDIOUT, x2: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiOutShortMsg".} -proc midiOutLongMsg*(x1: HMIDIOUT, x2: LPMIDIHDR, x3: UINT): MMRESULT{.stdcall, +proc midiOutLongMsg*(x1: HMIDIOUT, x2: LPMIDIHDR, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiOutLongMsg".} proc midiOutReset*(x1: HMIDIOUT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiOutReset".} -proc midiOutCachePatches*(x1: HMIDIOUT, x2: UINT, x3: LPWORD, x4: UINT): MMRESULT{. +proc midiOutCachePatches*(x1: HMIDIOUT, x2: uint32, x3: LPWORD, x4: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutCachePatches".} -proc midiOutCacheDrumPatches*(x1: HMIDIOUT, x2: UINT, x3: LPWORD, x4: UINT): MMRESULT{. +proc midiOutCacheDrumPatches*(x1: HMIDIOUT, x2: uint32, x3: LPWORD, x4: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutCacheDrumPatches".} proc midiOutGetID*(x1: HMIDIOUT, x2: LPUINT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiOutGetID".} -proc midiOutMessage*(x1: HMIDIOUT, x2: UINT, x3: DWORD, x4: DWORD): MMRESULT{. +proc midiOutMessage*(x1: HMIDIOUT, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiOutMessage".} -proc midiInGetNumDevs*(): UINT{.stdcall, dynlib: "winmm.dll", +proc midiInGetNumDevs*(): uint32{.stdcall, dynlib: "winmm.dll", importc: "midiInGetNumDevs".} -proc midiInGetDevCapsA*(x1: UINT, x2: LPMIDIINCAPSA, x3: UINT): MMRESULT{. +proc midiInGetDevCapsA*(x1: uint32, x2: LPMIDIINCAPSA, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiInGetDevCapsA".} -proc midiInGetDevCapsW*(x1: UINT, x2: LPMIDIINCAPSW, x3: UINT): MMRESULT{. +proc midiInGetDevCapsW*(x1: uint32, x2: LPMIDIINCAPSW, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiInGetDevCapsW".} -proc midiInGetDevCaps*(x1: UINT, x2: LPMIDIINCAPS, x3: UINT): MMRESULT{.stdcall, +proc midiInGetDevCaps*(x1: uint32, x2: LPMIDIINCAPS, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiInGetDevCapsA".} -proc midiInGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: UINT): MMRESULT{.stdcall, +proc midiInGetErrorTextA*(x1: MMRESULT, x2: LPSTR, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiInGetErrorTextA".} -proc midiInGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: UINT): MMRESULT{. +proc midiInGetErrorTextW*(x1: MMRESULT, x2: LPWSTR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiInGetErrorTextW".} -proc midiInGetErrorText*(x1: MMRESULT, x2: cstring, x3: UINT): MMRESULT{. +proc midiInGetErrorText*(x1: MMRESULT, x2: cstring, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiInGetErrorTextA".} -proc midiInOpen*(x1: LPHMIDIIN, x2: UINT, x3: DWORD, x4: DWORD, x5: DWORD): MMRESULT{. +proc midiInOpen*(x1: LPHMIDIIN, x2: uint32, x3: DWORD, x4: DWORD, x5: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiInOpen".} proc midiInClose*(x1: HMIDIIN): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiInClose".} -proc midiInPrepareHeader*(x1: HMIDIIN, x2: LPMIDIHDR, x3: UINT): MMRESULT{. +proc midiInPrepareHeader*(x1: HMIDIIN, x2: LPMIDIHDR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiInPrepareHeader".} -proc midiInUnprepareHeader*(x1: HMIDIIN, x2: LPMIDIHDR, x3: UINT): MMRESULT{. +proc midiInUnprepareHeader*(x1: HMIDIIN, x2: LPMIDIHDR, x3: uint32): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiInUnprepareHeader".} -proc midiInAddBuffer*(x1: HMIDIIN, x2: LPMIDIHDR, x3: UINT): MMRESULT{.stdcall, +proc midiInAddBuffer*(x1: HMIDIIN, x2: LPMIDIHDR, x3: uint32): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiInAddBuffer".} proc midiInStart*(x1: HMIDIIN): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiInStart".} @@ -2588,7 +2585,7 @@ proc midiInReset*(x1: HMIDIIN): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiInReset".} proc midiInGetID*(x1: HMIDIIN, x2: LPUINT): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "midiInGetID".} -proc midiInMessage*(x1: HMIDIIN, x2: UINT, x3: DWORD, x4: DWORD): MMRESULT{. +proc midiInMessage*(x1: HMIDIIN, x2: uint32, x3: DWORD, x4: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "midiInMessage".} proc mixerGetLineInfoA*(x1: HMIXEROBJ, x2: LPMIXERLINEA, x3: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mixerGetLineInfoA".} @@ -2596,13 +2593,13 @@ proc mixerGetLineInfoW*(x1: HMIXEROBJ, x2: LPMIXERLINEW, x3: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mixerGetLineInfoW".} proc mixerGetLineInfo*(x1: HMIXEROBJ, x2: LPMIXERLINE, x3: DWORD): MMRESULT{. stdcall, dynlib: "winmm.dll", importc: "mixerGetLineInfoA".} -proc mixerGetID*(x1: HMIXEROBJ, x2: var UINT, x3: DWORD): MMRESULT{.stdcall, +proc mixerGetID*(x1: HMIXEROBJ, x2: var uint32, x3: DWORD): MMRESULT{.stdcall, dynlib: "winmm.dll", importc: "mixerGetID".} -proc PlaySoundA*(x1: LPCSTR, x2: HMODULE, x3: DWORD): BOOL{.stdcall, +proc PlaySoundA*(x1: LPCSTR, x2: HMODULE, x3: DWORD): bool{.stdcall, dynlib: "winmm.dll", importc: "PlaySoundA".} -proc PlaySoundW*(x1: LPCWSTR, x2: HMODULE, x3: DWORD): BOOL{.stdcall, +proc PlaySoundW*(x1: LPCWSTR, x2: HMODULE, x3: DWORD): bool{.stdcall, dynlib: "winmm.dll", importc: "PlaySoundW".} -proc PlaySound*(x1: cstring, x2: HMODULE, x3: DWORD): BOOL{.stdcall, +proc PlaySound*(x1: cstring, x2: HMODULE, x3: DWORD): bool{.stdcall, dynlib: "winmm.dll", importc: "PlaySoundA".} # implementation @@ -2610,7 +2607,7 @@ proc MEVT_EVENTTYPE(x: int8): int8 = result = toU8(x shr 24) proc MEVT_EVENTPARM(x: DWORD): DWORD = - result = x And 0x00FFFFFF + result = x and 0x00FFFFFF proc MCI_MSF_MINUTE(msf: int32): int8 = result = toU8(msf and 0xff) @@ -2648,8 +2645,8 @@ proc MCI_MAKE_HMS(h, m, s: int8): int32 = proc MCI_TMSF_FRAME(tmsf: int32): int8 = result = toU8(tmsf shr 24) -proc mci_Make_TMSF(t, m, s, f: int8): int32 = +proc MCI_MAKE_TMSF(t, m, s, f: int8): int32 = result = (ze(t) or ze(m) shl 8 or ze(s) shl 16 or ze(f) shl 24).int32 proc DIBINDEX(n: int32): int32 = - result = n Or 0x000010FF'i32 shl 16'i32 + result = n or 0x000010FF'i32 shl 16'i32 diff --git a/lib/windows/nb30.nim b/lib/windows/nb30.nim index a7fd526aa..2e0c679ae 100644 --- a/lib/windows/nb30.nim +++ b/lib/windows/nb30.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2006 Andreas Rumpf # # See the file "copying.txt", included in this @@ -13,7 +13,7 @@ {.deadCodeElim: on.} import # Data structure templates - Windows + windows const NCBNAMSZ* = 16 # absolute length of a net name @@ -24,20 +24,20 @@ type # Network Control Block TNCBPostProc* = proc (P: PNCB) {.stdcall.} TNCB* {.final.} = object # Structure returned to the NCB command NCBASTAT is ADAPTER_STATUS followed # by an array of NAME_BUFFER structures. - ncb_command*: Char # command code - ncb_retcode*: Char # return code - ncb_lsn*: Char # local session number - ncb_num*: Char # number of our network name + ncb_command*: char # command code + ncb_retcode*: char # return code + ncb_lsn*: char # local session number + ncb_num*: char # number of our network name ncb_buffer*: cstring # address of message buffer ncb_length*: int16 # size of message buffer ncb_callname*: array[0..NCBNAMSZ - 1, char] # blank-padded name of remote ncb_name*: array[0..NCBNAMSZ - 1, char] # our blank-padded netname - ncb_rto*: Char # rcv timeout/retry count - ncb_sto*: Char # send timeout/sys timeout + ncb_rto*: char # rcv timeout/retry count + ncb_sto*: char # send timeout/sys timeout ncb_post*: TNCBPostProc # POST routine address - ncb_lana_num*: Char # lana (adapter) number - ncb_cmd_cplt*: Char # 0xff => commmand pending - ncb_reserve*: array[0..9, Char] # reserved, used by BIOS + ncb_lana_num*: char # lana (adapter) number + ncb_cmd_cplt*: char # 0xff => commmand pending + ncb_reserve*: array[0..9, char] # reserved, used by BIOS ncb_event*: THandle # HANDLE to Win32 event which # will be set to the signalled # state when an ASYNCH command @@ -45,11 +45,11 @@ type # Network Control Block PAdapterStatus* = ptr TAdapterStatus TAdapterStatus* {.final.} = object - adapter_address*: array[0..5, Char] - rev_major*: Char - reserved0*: Char - adapter_type*: Char - rev_minor*: Char + adapter_address*: array[0..5, char] + rev_major*: char + reserved0*: char + adapter_type*: char + rev_minor*: char duration*: int16 frmr_recv*: int16 frmr_xmit*: int16 @@ -75,9 +75,9 @@ type # Network Control Block PNameBuffer* = ptr TNameBuffer TNameBuffer* {.final.} = object - name*: array[0..NCBNAMSZ - 1, Char] - name_num*: Char - name_flags*: Char + name*: array[0..NCBNAMSZ - 1, char] + name_num*: char + name_flags*: char const # values for name_flags bits. @@ -96,19 +96,19 @@ type # Structure returned to the NCB command NCBSSTAT is SESSION_HEADER followed # status for all names. PSessionHeader* = ptr TSessionHeader TSessionHeader* {.final.} = object - sess_name*: Char - num_sess*: Char - rcv_dg_outstanding*: Char - rcv_any_outstanding*: Char + sess_name*: char + num_sess*: char + rcv_dg_outstanding*: char + rcv_any_outstanding*: char PSessionBuffer* = ptr TSessionBuffer TSessionBuffer* {.final.} = object - lsn*: Char - state*: Char - local_name*: array[0..NCBNAMSZ - 1, Char] - remote_name*: array[0..NCBNAMSZ - 1, Char] - rcvs_outstanding*: Char - sends_outstanding*: Char + lsn*: char + state*: char + local_name*: array[0..NCBNAMSZ - 1, char] + remote_name*: array[0..NCBNAMSZ - 1, char] + rcvs_outstanding*: char + sends_outstanding*: char const # Values for state @@ -125,24 +125,24 @@ type # Structure returned to the NCB command NCBENUM. PLanaEnum* = ptr TLanaEnum TLanaEnum* {.final.} = object # Structure returned to the NCB command NCBFINDNAME is FIND_NAME_HEADER followed # by an array of FIND_NAME_BUFFER structures. - len*: Char # Number of valid entries in lana[] - lana*: array[0..MAX_LANA, Char] + len*: char # Number of valid entries in lana[] + lana*: array[0..MAX_LANA, char] PFindNameHeader* = ptr TFindNameHeader TFindNameHeader* {.final.} = object node_count*: int16 - reserved*: Char - unique_group*: Char + reserved*: char + unique_group*: char PFindNameBuffer* = ptr TFindNameBuffer TFindNameBuffer* {.final.} = object # Structure provided with NCBACTION. The purpose of NCBACTION is to provide # transport specific extensions to netbios. - len*: Char - access_control*: Char - frame_control*: Char - destination_addr*: array[0..5, Char] - source_addr*: array[0..5, Char] - routing_info*: array[0..17, Char] + len*: char + access_control*: char + frame_control*: char + destination_addr*: array[0..5, char] + source_addr*: array[0..5, char] + routing_info*: array[0..17, char] PActionHeader* = ptr TActionHeader TActionHeader* {.final.} = object @@ -227,6 +227,6 @@ const # NCB Command codes # main user entry point for NetBIOS 3.0 # Usage: Result = Netbios( pncb ); -proc Netbios*(P: PNCB): Char{.stdcall, dynlib: "netapi32.dll", +proc Netbios*(P: PNCB): char{.stdcall, dynlib: "netapi32.dll", importc: "Netbios".} # implementation diff --git a/lib/windows/psapi.nim b/lib/windows/psapi.nim index 7d53cf7ca..fd1dcada8 100644 --- a/lib/windows/psapi.nim +++ b/lib/windows/psapi.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2009 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/windows/shellapi.nim b/lib/windows/shellapi.nim index 41f2a60d5..079257680 100644 --- a/lib/windows/shellapi.nim +++ b/lib/windows/shellapi.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2006 Andreas Rumpf # # See the file "copying.txt", included in this @@ -28,14 +28,14 @@ # Copyright (c) Microsoft Corporation. All rights reserved. import - Windows + windows type HDROP* = THandle - UINT_PTR* = ptr UINT + UINT_PTR* = ptr uint32 DWORD_PTR* = ptr DWORD - pHICON* = ptr HICON - pBool* = ptr BOOL + PHICON* = ptr HICON + PBool* = ptr bool STARTUPINFOW* {.final.} = object # a guess. Omission should get fixed in Windows. cb*: DWORD lpReserved*: LPTSTR @@ -60,27 +60,27 @@ type TSTARTUPINFOW* = STARTUPINFOW PSTARTUPINFOW* = ptr STARTUPINFOW #unicode -proc DragQueryFileA*(arg1: HDROP, arg2: UINT, arg3: LPSTR, arg4: UINT): UINT{. +proc DragQueryFileA*(arg1: HDROP, arg2: uint32, arg3: LPSTR, arg4: uint32): uint32{. stdcall, dynlib: "shell32.dll", importc: "DragQueryFileA".} -proc DragQueryFileW*(arg1: HDROP, arg2: UINT, arg3: LPWSTR, arg4: UINT): UINT{. +proc DragQueryFileW*(arg1: HDROP, arg2: uint32, arg3: LPWSTR, arg4: uint32): uint32{. stdcall, dynlib: "shell32.dll", importc: "DragQueryFileW".} -proc DragQueryFile*(arg1: HDROP, arg2: UINT, arg3: LPSTR, arg4: UINT): UINT{. +proc DragQueryFile*(arg1: HDROP, arg2: uint32, arg3: LPSTR, arg4: uint32): uint32{. stdcall, dynlib: "shell32.dll", importc: "DragQueryFileA".} -proc DragQueryFile*(arg1: HDROP, arg2: UINT, arg3: LPWSTR, arg4: UINT): UINT{. +proc DragQueryFile*(arg1: HDROP, arg2: uint32, arg3: LPWSTR, arg4: uint32): uint32{. stdcall, dynlib: "shell32.dll", importc: "DragQueryFileW".} -proc DragQueryPoint*(arg1: HDROP, arg2: LPPOINT): BOOL{.stdcall, +proc DragQueryPoint*(arg1: HDROP, arg2: LPPOINT): bool{.stdcall, dynlib: "shell32.dll", importc: "DragQueryPoint".} proc DragFinish*(arg1: HDROP){.stdcall, dynlib: "shell32.dll", importc: "DragFinish".} -proc DragAcceptFiles*(hwnd: HWND, arg2: BOOL){.stdcall, dynlib: "shell32.dll", +proc DragAcceptFiles*(hwnd: HWND, arg2: bool){.stdcall, dynlib: "shell32.dll", importc: "DragAcceptFiles".} -proc ShellExecuteA*(HWND: hwnd, lpOperation: LPCSTR, lpFile: LPCSTR, +proc ShellExecuteA*(hwnd: HWND, lpOperation: LPCSTR, lpFile: LPCSTR, lpParameters: LPCSTR, lpDirectory: LPCSTR, nShowCmd: int32): HInst{. stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".} proc ShellExecuteW*(hwnd: HWND, lpOperation: LPCWSTR, lpFile: LPCWSTR, lpParameters: LPCWSTR, lpDirectory: LPCWSTR, nShowCmd: int32): HInst{. stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW".} -proc ShellExecute*(HWND: hwnd, lpOperation: LPCSTR, lpFile: LPCSTR, +proc ShellExecute*(hwnd: HWND, lpOperation: LPCSTR, lpFile: LPCSTR, lpParameters: LPCSTR, lpDirectory: LPCSTR, nShowCmd: int32): HInst{. stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".} proc ShellExecute*(hwnd: HWND, lpOperation: LPCWSTR, lpFile: LPCWSTR, @@ -94,16 +94,16 @@ proc FindExecutable*(lpFile: LPCSTR, lpDirectory: LPCSTR, lpResult: LPSTR): HIns stdcall, dynlib: "shell32.dll", importc: "FindExecutableA".} proc FindExecutable*(lpFile: LPCWSTR, lpDirectory: LPCWSTR, lpResult: LPWSTR): HInst{. stdcall, dynlib: "shell32.dll", importc: "FindExecutableW".} -proc CommandLineToArgvW*(lpCmdLine: LPCWSTR, pNumArgs: ptr int32): pLPWSTR{. +proc CommandLineToArgvW*(lpCmdLine: LPCWSTR, pNumArgs: ptr int32): PLPWSTR{. stdcall, dynlib: "shell32.dll", importc: "CommandLineToArgvW".} -proc ShellAboutA*(HWND: hWnd, szApp: LPCSTR, szOtherStuff: LPCSTR, HICON: hIcon): int32{. +proc ShellAboutA*(hwnd: HWND, szApp: LPCSTR, szOtherStuff: LPCSTR, hIcon: HICON): int32{. stdcall, dynlib: "shell32.dll", importc: "ShellAboutA".} -proc ShellAboutW*(HWND: hWnd, szApp: LPCWSTR, szOtherStuff: LPCWSTR, - HICON: hIcon): int32{.stdcall, dynlib: "shell32.dll", +proc ShellAboutW*(hwnd: HWND, szApp: LPCWSTR, szOtherStuff: LPCWSTR, + hIcon: HICON): int32{.stdcall, dynlib: "shell32.dll", importc: "ShellAboutW".} -proc ShellAbout*(HWND: hWnd, szApp: LPCSTR, szOtherStuff: LPCSTR, HICON: hIcon): int32{. +proc ShellAbout*(hwnd: HWND, szApp: LPCSTR, szOtherStuff: LPCSTR, hIcon: HICON): int32{. stdcall, dynlib: "shell32.dll", importc: "ShellAboutA".} -proc ShellAbout*(HWND: hWnd, szApp: LPCWSTR, szOtherStuff: LPCWSTR, HICON: hIcon): int32{. +proc ShellAbout*(hwnd: HWND, szApp: LPCWSTR, szOtherStuff: LPCWSTR, hIcon: HICON): int32{. stdcall, dynlib: "shell32.dll", importc: "ShellAboutW".} proc DuplicateIcon*(inst: HINST, icon: HICON): HIcon{.stdcall, dynlib: "shell32.dll", importc: "DuplicateIcon".} @@ -115,29 +115,29 @@ proc ExtractAssociatedIcon*(hInst: HINST, lpIconPath: LPSTR, lpiIcon: LPWORD): H stdcall, dynlib: "shell32.dll", importc: "ExtractAssociatedIconA".} proc ExtractAssociatedIcon*(hInst: HINST, lpIconPath: LPWSTR, lpiIcon: LPWORD): HICON{. stdcall, dynlib: "shell32.dll", importc: "ExtractAssociatedIconW".} -proc ExtractIconA*(hInst: HINST, lpszExeFileName: LPCSTR, nIconIndex: UINT): HICON{. +proc ExtractIconA*(hInst: HINST, lpszExeFileName: LPCSTR, nIconIndex: uint32): HICON{. stdcall, dynlib: "shell32.dll", importc: "ExtractIconA".} -proc ExtractIconW*(hInst: HINST, lpszExeFileName: LPCWSTR, nIconIndex: UINT): HICON{. +proc ExtractIconW*(hInst: HINST, lpszExeFileName: LPCWSTR, nIconIndex: uint32): HICON{. stdcall, dynlib: "shell32.dll", importc: "ExtractIconW".} -proc ExtractIcon*(hInst: HINST, lpszExeFileName: LPCSTR, nIconIndex: UINT): HICON{. +proc ExtractIcon*(hInst: HINST, lpszExeFileName: LPCSTR, nIconIndex: uint32): HICON{. stdcall, dynlib: "shell32.dll", importc: "ExtractIconA".} -proc ExtractIcon*(hInst: HINST, lpszExeFileName: LPCWSTR, nIconIndex: UINT): HICON{. +proc ExtractIcon*(hInst: HINST, lpszExeFileName: LPCWSTR, nIconIndex: uint32): HICON{. stdcall, dynlib: "shell32.dll", importc: "ExtractIconW".} # if(WINVER >= 0x0400) type # init with sizeof(DRAGINFO) DRAGINFOA* {.final.} = object - uSize*: UINT + uSize*: uint32 pt*: POINT - fNC*: BOOL + fNC*: bool lpFileList*: LPSTR grfKeyState*: DWORD TDRAGINFOA* = DRAGINFOA LPDRAGINFOA* = ptr DRAGINFOA # init with sizeof(DRAGINFO) DRAGINFOW* {.final.} = object - uSize*: UINT + uSize*: uint32 pt*: POINT - fNC*: BOOL + fNC*: bool lpFileList*: LPWSTR grfKeyState*: DWORD @@ -184,8 +184,8 @@ type AppBarData* {.final.} = object cbSize*: DWORD hWnd*: HWND - uCallbackMessage*: UINT - uEdge*: UINT + uCallbackMessage*: uint32 + uEdge*: uint32 rc*: RECT lParam*: LPARAM # message specific @@ -197,41 +197,41 @@ proc SHAppBarMessage*(dwMessage: DWORD, pData: APPBARDATA): UINT_PTR{.stdcall, # # EndAppBar # -proc DoEnvironmentSubstA*(szString: LPSTR, cchString: UINT): DWORD{.stdcall, +proc DoEnvironmentSubstA*(szString: LPSTR, cchString: uint32): DWORD{.stdcall, dynlib: "shell32.dll", importc: "DoEnvironmentSubstA".} -proc DoEnvironmentSubstW*(szString: LPWSTR, cchString: UINT): DWORD{.stdcall, +proc DoEnvironmentSubstW*(szString: LPWSTR, cchString: uint32): DWORD{.stdcall, dynlib: "shell32.dll", importc: "DoEnvironmentSubstW".} -proc DoEnvironmentSubst*(szString: LPSTR, cchString: UINT): DWORD{.stdcall, +proc DoEnvironmentSubst*(szString: LPSTR, cchString: uint32): DWORD{.stdcall, dynlib: "shell32.dll", importc: "DoEnvironmentSubstA".} -proc DoEnvironmentSubst*(szString: LPWSTR, cchString: UINT): DWORD{.stdcall, +proc DoEnvironmentSubst*(szString: LPWSTR, cchString: uint32): DWORD{.stdcall, dynlib: "shell32.dll", importc: "DoEnvironmentSubstW".} #Macro proc EIRESID*(x: int32): int32 -proc ExtractIconExA*(lpszFile: LPCSTR, nIconIndex: int32, phiconLarge: pHICON, - phiconSmall: pHIcon, nIcons: UINT): UINT{.stdcall, +proc ExtractIconExA*(lpszFile: LPCSTR, nIconIndex: int32, phiconLarge: PHICON, + phiconSmall: PHICON, nIcons: uint32): uint32{.stdcall, dynlib: "shell32.dll", importc: "ExtractIconExA".} -proc ExtractIconExW*(lpszFile: LPCWSTR, nIconIndex: int32, phiconLarge: pHICON, - phiconSmall: pHIcon, nIcons: UINT): UINT{.stdcall, +proc ExtractIconExW*(lpszFile: LPCWSTR, nIconIndex: int32, phiconLarge: PHICON, + phiconSmall: PHICON, nIcons: uint32): uint32{.stdcall, dynlib: "shell32.dll", importc: "ExtractIconExW".} proc ExtractIconExA*(lpszFile: LPCSTR, nIconIndex: int32, phiconLarge: var HICON, phiconSmall: var HIcon, - nIcons: UINT): UINT{.stdcall, dynlib: "shell32.dll", + nIcons: uint32): uint32{.stdcall, dynlib: "shell32.dll", importc: "ExtractIconExA".} proc ExtractIconExW*(lpszFile: LPCWSTR, nIconIndex: int32, phiconLarge: var HICON, phiconSmall: var HIcon, - nIcons: UINT): UINT{.stdcall, dynlib: "shell32.dll", + nIcons: uint32): uint32{.stdcall, dynlib: "shell32.dll", importc: "ExtractIconExW".} -proc ExtractIconEx*(lpszFile: LPCSTR, nIconIndex: int32, phiconLarge: pHICON, - phiconSmall: pHIcon, nIcons: UINT): UINT{.stdcall, +proc ExtractIconEx*(lpszFile: LPCSTR, nIconIndex: int32, phiconLarge: PHICON, + phiconSmall: PHICON, nIcons: uint32): uint32{.stdcall, dynlib: "shell32.dll", importc: "ExtractIconExA".} -proc ExtractIconEx*(lpszFile: LPCWSTR, nIconIndex: int32, phiconLarge: pHICON, - phiconSmall: pHIcon, nIcons: UINT): UINT{.stdcall, +proc ExtractIconEx*(lpszFile: LPCWSTR, nIconIndex: int32, phiconLarge: PHICON, + phiconSmall: PHICON, nIcons: uint32): uint32{.stdcall, dynlib: "shell32.dll", importc: "ExtractIconExW".} proc ExtractIconEx*(lpszFile: LPCSTR, nIconIndex: int32, phiconLarge: var HICON, - phiconSmall: var HIcon, nIcons: UINT): UINT{.stdcall, + phiconSmall: var HIcon, nIcons: uint32): uint32{.stdcall, dynlib: "shell32.dll", importc: "ExtractIconExA".} proc ExtractIconEx*(lpszFile: LPCWSTR, nIconIndex: int32, - phiconLarge: var HICON, phiconSmall: var HIcon, nIcons: UINT): UINT{. + phiconLarge: var HICON, phiconSmall: var HIcon, nIcons: uint32): uint32{. stdcall, dynlib: "shell32.dll", importc: "ExtractIconExW".} # # Shell File Operations @@ -291,11 +291,11 @@ type type SHFILEOPSTRUCTA* {.final.} = object hwnd*: HWND - wFunc*: UINT + wFunc*: uint32 pFrom*: LPCSTR pTo*: LPCSTR fFlags*: FILEOP_FLAGS - fAnyOperationsAborted*: BOOL + fAnyOperationsAborted*: bool hNameMappings*: LPVOID lpszProgressTitle*: LPCSTR # only used if FOF_SIMPLEPROGRESS @@ -303,11 +303,11 @@ type LPSHFILEOPSTRUCTA* = ptr SHFILEOPSTRUCTA SHFILEOPSTRUCTW* {.final.} = object hwnd*: HWND - wFunc*: UINT + wFunc*: uint32 pFrom*: LPCWSTR pTo*: LPCWSTR fFlags*: FILEOP_FLAGS - fAnyOperationsAborted*: BOOL + fAnyOperationsAborted*: bool hNameMappings*: LPVOID lpszProgressTitle*: LPCWSTR @@ -430,10 +430,10 @@ type cbSize*: DWORD fMask*: ULONG hwnd*: HWND - lpVerb*: lpcwstr - lpFile*: lpcwstr - lpParameters*: lpcwstr - lpDirectory*: lpcwstr + lpVerb*: LPCWSTR + lpFile*: LPCWSTR + lpParameters*: LPCWSTR + lpDirectory*: LPCWSTR nShow*: int32 hInstApp*: HINST lpIDList*: LPVOID @@ -456,24 +456,24 @@ else: SHELLEXECUTEINFO* = SHELLEXECUTEINFOA TSHELLEXECUTEINFO* = SHELLEXECUTEINFOA LPSHELLEXECUTEINFO* = LPSHELLEXECUTEINFOA -proc ShellExecuteExA*(lpExecInfo: LPSHELLEXECUTEINFOA): Bool{.stdcall, +proc ShellExecuteExA*(lpExecInfo: LPSHELLEXECUTEINFOA): bool{.stdcall, dynlib: "shell32.dll", importc: "ShellExecuteExA".} -proc ShellExecuteExW*(lpExecInfo: LPSHELLEXECUTEINFOW): Bool{.stdcall, +proc ShellExecuteExW*(lpExecInfo: LPSHELLEXECUTEINFOW): bool{.stdcall, dynlib: "shell32.dll", importc: "ShellExecuteExW".} -proc ShellExecuteEx*(lpExecInfo: LPSHELLEXECUTEINFOA): Bool{.stdcall, +proc ShellExecuteEx*(lpExecInfo: LPSHELLEXECUTEINFOA): bool{.stdcall, dynlib: "shell32.dll", importc: "ShellExecuteExA".} -proc ShellExecuteEx*(lpExecInfo: LPSHELLEXECUTEINFOW): Bool{.stdcall, +proc ShellExecuteEx*(lpExecInfo: LPSHELLEXECUTEINFOW): bool{.stdcall, dynlib: "shell32.dll", importc: "ShellExecuteExW".} -proc WinExecErrorA*(HWND: hwnd, error: int32, lpstrFileName: LPCSTR, +proc WinExecErrorA*(hwnd: HWND, error: int32, lpstrFileName: LPCSTR, lpstrTitle: LPCSTR){.stdcall, dynlib: "shell32.dll", importc: "WinExecErrorA".} -proc WinExecErrorW*(HWND: hwnd, error: int32, lpstrFileName: LPCWSTR, +proc WinExecErrorW*(hwnd: HWND, error: int32, lpstrFileName: LPCWSTR, lpstrTitle: LPCWSTR){.stdcall, dynlib: "shell32.dll", importc: "WinExecErrorW".} -proc WinExecError*(HWND: hwnd, error: int32, lpstrFileName: LPCSTR, +proc WinExecError*(hwnd: HWND, error: int32, lpstrFileName: LPCSTR, lpstrTitle: LPCSTR){.stdcall, dynlib: "shell32.dll", importc: "WinExecErrorA".} -proc WinExecError*(HWND: hwnd, error: int32, lpstrFileName: LPCWSTR, +proc WinExecError*(hwnd: HWND, error: int32, lpstrFileName: LPCWSTR, lpstrTitle: LPCWSTR){.stdcall, dynlib: "shell32.dll", importc: "WinExecErrorW".} type @@ -487,7 +487,7 @@ type hUserToken*: HANDLE lpProcessAttributes*: LPSECURITY_ATTRIBUTES lpThreadAttributes*: LPSECURITY_ATTRIBUTES - bInheritHandles*: BOOL + bInheritHandles*: bool dwCreationFlags*: DWORD lpStartupInfo*: LPSTARTUPINFOW lpProcessInformation*: LPPROCESS_INFORMATION @@ -495,7 +495,7 @@ type TSHCREATEPROCESSINFOW* = SHCREATEPROCESSINFOW PSHCREATEPROCESSINFOW* = ptr SHCREATEPROCESSINFOW -proc SHCreateProcessAsUserW*(pscpi: PSHCREATEPROCESSINFOW): Bool{.stdcall, +proc SHCreateProcessAsUserW*(pscpi: PSHCREATEPROCESSINFOW): bool{.stdcall, dynlib: "shell32.dll", importc: "SHCreateProcessAsUserW".} # # End ShellExecuteEx and family } @@ -544,16 +544,16 @@ type NOTIFYICONDATAA* {.final.} = object cbSize*: DWORD hWnd*: HWND - uID*: UINT - uFlags*: UINT - uCallbackMessage*: UINT + uID*: uint32 + uFlags*: uint32 + uCallbackMessage*: uint32 hIcon*: HICON - szTip*: array[0..127, CHAR] + szTip*: array[0..127, char] dwState*: DWORD dwStateMask*: DWORD - szInfo*: array[0..255, CHAR] - uTimeout*: UINT # also: uVersion - szInfoTitle*: array[0..63, CHAR] + szInfo*: array[0..255, char] + uTimeout*: uint32 # also: uVersion + szInfoTitle*: array[0..63, char] dwInfoFlags*: DWORD guidItem*: TGUID @@ -562,16 +562,16 @@ type NOTIFYICONDATAW* {.final.} = object cbSize*: DWORD hWnd*: HWND - uID*: UINT - uFlags*: UINT - uCallbackMessage*: UINT + uID*: uint32 + uFlags*: uint32 + uCallbackMessage*: uint32 hIcon*: HICON - szTip*: array[0..127, WCHAR] + szTip*: array[0..127, Wchar] dwState*: DWORD dwStateMask*: DWORD - szInfo*: array[0..255, WCHAR] - uTimeout*: UINT # also uVersion : UINT - szInfoTitle*: array[0..63, CHAR] + szInfo*: array[0..255, Wchar] + uTimeout*: uint32 # also uVersion : UINT + szInfoTitle*: array[0..63, char] dwInfoFlags*: DWORD guidItem*: TGUID @@ -619,13 +619,13 @@ const NIIF_ICON_MASK* = 0x0000000F NIIF_NOSOUND* = 0x00000010 -proc Shell_NotifyIconA*(dwMessage: Dword, lpData: PNOTIFYICONDATAA): Bool{. +proc Shell_NotifyIconA*(dwMessage: Dword, lpData: PNOTIFYICONDATAA): bool{. stdcall, dynlib: "shell32.dll", importc: "Shell_NotifyIconA".} -proc Shell_NotifyIconW*(dwMessage: Dword, lpData: PNOTIFYICONDATAW): Bool{. +proc Shell_NotifyIconW*(dwMessage: Dword, lpData: PNOTIFYICONDATAW): bool{. stdcall, dynlib: "shell32.dll", importc: "Shell_NotifyIconW".} -proc Shell_NotifyIcon*(dwMessage: Dword, lpData: PNOTIFYICONDATAA): Bool{. +proc Shell_NotifyIcon*(dwMessage: Dword, lpData: PNOTIFYICONDATAA): bool{. stdcall, dynlib: "shell32.dll", importc: "Shell_NotifyIconA".} -proc Shell_NotifyIcon*(dwMessage: Dword, lpData: PNOTIFYICONDATAW): Bool{. +proc Shell_NotifyIcon*(dwMessage: Dword, lpData: PNOTIFYICONDATAW): bool{. stdcall, dynlib: "shell32.dll", importc: "Shell_NotifyIconW".} # # The SHGetFileInfo API provides an easy way to get attributes @@ -652,20 +652,20 @@ type hIcon*: HICON # out: icon iIcon*: int32 # out: icon index dwAttributes*: DWORD # out: SFGAO_ flags - szDisplayName*: array[0..(MAX_PATH) - 1, CHAR] # out: display name (or path) - szTypeName*: array[0..79, CHAR] # out: type name + szDisplayName*: array[0..(MAX_PATH) - 1, char] # out: display name (or path) + szTypeName*: array[0..79, char] # out: type name TSHFILEINFOA* = SHFILEINFOA - pSHFILEINFOA* = ptr SHFILEINFOA + PSHFILEINFOA* = ptr SHFILEINFOA SHFILEINFOW* {.final.} = object hIcon*: HICON # out: icon iIcon*: int32 # out: icon index dwAttributes*: DWORD # out: SFGAO_ flags - szDisplayName*: array[0..(MAX_PATH) - 1, WCHAR] # out: display name (or path) - szTypeName*: array[0..79, WCHAR] # out: type name + szDisplayName*: array[0..(MAX_PATH) - 1, Wchar] # out: display name (or path) + szTypeName*: array[0..79, Wchar] # out: type name TSHFILEINFOW* = SHFILEINFOW - pSHFILEINFOW* = ptr SHFILEINFOW + PSHFILEINFOW* = ptr SHFILEINFOW when defined(UNICODE): type @@ -701,67 +701,67 @@ const # in the upper 8 bits of the iIcon proc SHGetFileInfoA*(pszPath: LPCSTR, dwFileAttributes: DWORD, - psfi: pSHFILEINFOA, cbFileInfo, UFlags: UINT): DWORD{. + psfi: PSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{. stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".} proc SHGetFileInfoW*(pszPath: LPCWSTR, dwFileAttributes: DWORD, - psfi: pSHFILEINFOW, cbFileInfo, UFlags: UINT): DWORD{. + psfi: PSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{. stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".} proc SHGetFileInfo*(pszPath: LPCSTR, dwFileAttributes: DWORD, - psfi: pSHFILEINFOA, cbFileInfo, UFlags: UINT): DWORD{. + psfi: PSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{. stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".} proc SHGetFileInfoA*(pszPath: LPCSTR, dwFileAttributes: DWORD, - psfi: var TSHFILEINFOA, cbFileInfo, UFlags: UINT): DWORD{. + psfi: var TSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{. stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".} proc SHGetFileInfoW*(pszPath: LPCWSTR, dwFileAttributes: DWORD, - psfi: var TSHFILEINFOW, cbFileInfo, UFlags: UINT): DWORD{. + psfi: var TSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{. stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".} proc SHGetFileInfo*(pszPath: LPCSTR, dwFileAttributes: DWORD, - psfi: var TSHFILEINFOA, cbFileInfo, UFlags: UINT): DWORD{. + psfi: var TSHFILEINFOA, cbFileInfo, UFlags: uint32): DWORD{. stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoA".} proc SHGetFileInfo*(pszPath: LPCWSTR, dwFileAttributes: DWORD, - psfi: var TSHFILEINFOW, cbFileInfo, UFlags: UINT): DWORD{. + psfi: var TSHFILEINFOW, cbFileInfo, UFlags: uint32): DWORD{. stdcall, dynlib: "shell32.dll", importc: "SHGetFileInfoW".} proc SHGetDiskFreeSpaceExA*(pszDirectoryName: LPCSTR, - pulFreeBytesAvailableToCaller: pULARGE_INTEGER, - pulTotalNumberOfBytes: pULARGE_INTEGER, - pulTotalNumberOfFreeBytes: pULARGE_INTEGER): Bool{. + pulFreeBytesAvailableToCaller: PULARGE_INTEGER, + pulTotalNumberOfBytes: PULARGE_INTEGER, + pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{. stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExA".} proc SHGetDiskFreeSpaceExW*(pszDirectoryName: LPCWSTR, - pulFreeBytesAvailableToCaller: pULARGE_INTEGER, - pulTotalNumberOfBytes: pULARGE_INTEGER, - pulTotalNumberOfFreeBytes: pULARGE_INTEGER): Bool{. + pulFreeBytesAvailableToCaller: PULARGE_INTEGER, + pulTotalNumberOfBytes: PULARGE_INTEGER, + pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{. stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExW".} proc SHGetDiskFreeSpaceEx*(pszDirectoryName: LPCSTR, - pulFreeBytesAvailableToCaller: pULARGE_INTEGER, - pulTotalNumberOfBytes: pULARGE_INTEGER, - pulTotalNumberOfFreeBytes: pULARGE_INTEGER): Bool{. + pulFreeBytesAvailableToCaller: PULARGE_INTEGER, + pulTotalNumberOfBytes: PULARGE_INTEGER, + pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{. stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExA".} proc SHGetDiskFreeSpace*(pszDirectoryName: LPCSTR, - pulFreeBytesAvailableToCaller: pULARGE_INTEGER, - pulTotalNumberOfBytes: pULARGE_INTEGER, - pulTotalNumberOfFreeBytes: pULARGE_INTEGER): Bool{. + pulFreeBytesAvailableToCaller: PULARGE_INTEGER, + pulTotalNumberOfBytes: PULARGE_INTEGER, + pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{. stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExA".} proc SHGetDiskFreeSpaceEx*(pszDirectoryName: LPCWSTR, - pulFreeBytesAvailableToCaller: pULARGE_INTEGER, - pulTotalNumberOfBytes: pULARGE_INTEGER, - pulTotalNumberOfFreeBytes: pULARGE_INTEGER): Bool{. + pulFreeBytesAvailableToCaller: PULARGE_INTEGER, + pulTotalNumberOfBytes: PULARGE_INTEGER, + pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{. stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExW".} proc SHGetDiskFreeSpace*(pszDirectoryName: LPCWSTR, - pulFreeBytesAvailableToCaller: pULARGE_INTEGER, - pulTotalNumberOfBytes: pULARGE_INTEGER, - pulTotalNumberOfFreeBytes: pULARGE_INTEGER): Bool{. + pulFreeBytesAvailableToCaller: PULARGE_INTEGER, + pulTotalNumberOfBytes: PULARGE_INTEGER, + pulTotalNumberOfFreeBytes: PULARGE_INTEGER): bool{. stdcall, dynlib: "shell32.dll", importc: "SHGetDiskFreeSpaceExW".} proc SHGetNewLinkInfoA*(pszLinkTo: LPCSTR, pszDir: LPCSTR, pszName: LPSTR, - pfMustCopy: pBool, uFlags: UINT): Bool{.stdcall, + pfMustCopy: PBool, uFlags: uint32): bool{.stdcall, dynlib: "shell32.dll", importc: "SHGetNewLinkInfoA".} proc SHGetNewLinkInfoW*(pszLinkTo: LPCWSTR, pszDir: LPCWSTR, pszName: LPWSTR, - pfMustCopy: pBool, uFlags: UINT): Bool{.stdcall, + pfMustCopy: PBool, uFlags: uint32): bool{.stdcall, dynlib: "shell32.dll", importc: "SHGetNewLinkInfoW".} proc SHGetNewLinkInfo*(pszLinkTo: LPCSTR, pszDir: LPCSTR, pszName: LPSTR, - pfMustCopy: pBool, uFlags: UINT): Bool{.stdcall, + pfMustCopy: PBool, uFlags: uint32): bool{.stdcall, dynlib: "shell32.dll", importc: "SHGetNewLinkInfoA".} proc SHGetNewLinkInfo*(pszLinkTo: LPCWSTR, pszDir: LPCWSTR, pszName: LPWSTR, - pfMustCopy: pBool, uFlags: UINT): Bool{.stdcall, + pfMustCopy: PBool, uFlags: uint32): bool{.stdcall, dynlib: "shell32.dll", importc: "SHGetNewLinkInfoW".} const SHGNLI_PIDL* = 0x00000001 # pszLinkTo is a pidl @@ -777,17 +777,17 @@ const PRINTACTION_DOCUMENTDEFAULTS* = 6 PRINTACTION_SERVERPROPERTIES* = 7 -proc SHInvokePrinterCommandA*(HWND: hwnd, uAction: UINT, lpBuf1: LPCSTR, - lpBuf2: LPCSTR, fModal: Bool): Bool{.stdcall, +proc SHInvokePrinterCommandA*(hwnd: HWND, uAction: uint32, lpBuf1: LPCSTR, + lpBuf2: LPCSTR, fModal: bool): bool{.stdcall, dynlib: "shell32.dll", importc: "SHInvokePrinterCommandA".} -proc SHInvokePrinterCommandW*(HWND: hwnd, uAction: UINT, lpBuf1: LPCWSTR, - lpBuf2: LPCWSTR, fModal: Bool): Bool{.stdcall, +proc SHInvokePrinterCommandW*(hwnd: HWND, uAction: uint32, lpBuf1: LPCWSTR, + lpBuf2: LPCWSTR, fModal: bool): bool{.stdcall, dynlib: "shell32.dll", importc: "SHInvokePrinterCommandW".} -proc SHInvokePrinterCommand*(HWND: hwnd, uAction: UINT, lpBuf1: LPCSTR, - lpBuf2: LPCSTR, fModal: Bool): Bool{.stdcall, +proc SHInvokePrinterCommand*(hwnd: HWND, uAction: uint32, lpBuf1: LPCSTR, + lpBuf2: LPCSTR, fModal: bool): bool{.stdcall, dynlib: "shell32.dll", importc: "SHInvokePrinterCommandA".} -proc SHInvokePrinterCommand*(HWND: hwnd, uAction: UINT, lpBuf1: LPCWSTR, - lpBuf2: LPCWSTR, fModal: Bool): Bool{.stdcall, +proc SHInvokePrinterCommand*(hwnd: HWND, uAction: uint32, lpBuf1: LPCWSTR, + lpBuf2: LPCWSTR, fModal: bool): bool{.stdcall, dynlib: "shell32.dll", importc: "SHInvokePrinterCommandW".} proc SHLoadNonloadedIconOverlayIdentifiers*(): HResult{.stdcall, dynlib: "shell32.dll", importc: "SHInvokePrinterCommandW".} diff --git a/lib/windows/shfolder.nim b/lib/windows/shfolder.nim index 253b1c77a..886d757eb 100644 --- a/lib/windows/shfolder.nim +++ b/lib/windows/shfolder.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2006 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim index 5fd9127b3..f5b69402a 100644 --- a/lib/windows/windows.nim +++ b/lib/windows/windows.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this @@ -49,15 +49,15 @@ type # BaseTsd.h -- Type definitions for the basic sized types DWORD64* = int64 PDWORD64* = ptr DWORD64 # int32 on Win32, int64 on Win64 - INT_PTR* = TAddress - UINT_PTR* = TAddress - LONG_PTR* = TAddress - ULONG_PTR* = TAddress - SIZE_T* = TAddress - SSIZE_T* = TAddress - DWORD_PTR* = TAddress + INT_PTR* = ByteAddress + UINT_PTR* = ByteAddress + LONG_PTR* = ByteAddress + ULONG_PTR* = ByteAddress + SIZE_T* = ByteAddress + SSIZE_T* = ByteAddress + DWORD_PTR* = ByteAddress # Thread affinity - KAFFINITY* = TAddress + KAFFINITY* = ByteAddress PKAFFINITY* = ptr KAFFINITY type # WinDef.h -- Basic Windows Type Definitions @@ -74,8 +74,8 @@ type # WinDef.h -- Basic Windows Type Definitions DWORD* = int32 WINBOOL* = int32 WORD* = int16 - # FLOAT* = float - PFLOAT* = ptr FLOAT + #FLOAT* = float + PFLOAT* = ptr float32 PWINBOOL* = ptr WINBOOL LPWINBOOL* = ptr WINBOOL PBYTE* = ptr int8 @@ -383,7 +383,7 @@ type stdcall.} LPCFHOOKPROC* = proc (para1: HWND, para2: WINUINT, para3: WPARAM, para4: LPARAM): WINUINT{. stdcall.} - PTHREAD_START_ROUTINE* = Pointer + PTHREAD_START_ROUTINE* = pointer LPTHREAD_START_ROUTINE* = PTHREAD_START_ROUTINE EDITSTREAMCALLBACK* = proc (para1: DWORD, para2: LPBYTE, para3: LONG, para4: LONG): DWORD{.stdcall.} @@ -8415,34 +8415,34 @@ type # dmDisplayFixedOutput: DWORD; LPDEVMODE* = ptr DEVMODE - devicemode* = DEVMODE - tdevicemode* = DEVMODE - tdevicemodeA* = DEVMODE + Devicemode* = DEVMODE + TDevicemode* = DEVMODE + TDevicemodeA* = DEVMODE PDeviceModeA* = LPDEVMODE PDeviceMode* = LPDEVMODE TDEVMODE* = DEVMODE PDEVMODE* = LPDEVMODE - devmodeW* {.final, pure.} = object + DEVMODEW* {.final, pure.} = object dmDeviceName*: array[0..CCHDEVICENAME - 1, WCHAR] dmSpecVersion*: int16 dmDriverVersion*: int16 dmSize*: int16 dmDriverExtra*: int16 dmFields*: DWORD - dmOrientation*: short - dmPaperSize*: short - dmPaperLength*: short - dmPaperWidth*: short - dmScale*: short - dmCopies*: short - dmDefaultSource*: short - dmPrintQuality*: short - dmColor*: short - dmDuplex*: short - dmYResolution*: short - dmTTOption*: short - dmCollate*: short - dmFormName*: array[0..CCHFORMNAME - 1, wchar] + dmOrientation*: SHORT + dmPaperSize*: SHORT + dmPaperLength*: SHORT + dmPaperWidth*: SHORT + dmScale*: SHORT + dmCopies*: SHORT + dmDefaultSource*: SHORT + dmPrintQuality*: SHORT + dmColor*: SHORT + dmDuplex*: SHORT + dmYResolution*: SHORT + dmTTOption*: SHORT + dmCollate*: SHORT + dmFormName*: array[0..CCHFORMNAME - 1, WCHAR] dmLogPixels*: int16 dmBitsPerPel*: DWORD dmPelsWidth*: DWORD @@ -8459,7 +8459,7 @@ type dmPanningHeight*: DWORD LPDEVMODEW* = ptr DEVMODEW - devicemodeW* = DEVMODEW + DevicemodeW* = DEVMODEW TDeviceModeW* = DEVMODEW PDeviceModeW* = LPDEVMODEW TDEVMODEW* = DEVMODEW @@ -8497,7 +8497,7 @@ type LARGE_INTEGER* = int64 ULARGE_INTEGER* = int64 PLARGE_INTEGER* = ptr LARGE_INTEGER - TLargeInteger* = Int64 + TLargeInteger* = int64 PULARGE_INTEGER* = ptr ULARGE_INTEGER TULargeInteger* = int64 DISK_GEOMETRY* {.final, pure.} = object @@ -10469,7 +10469,7 @@ type ncb_name*: array[0..(NCBNAMSZ) - 1, UCHAR] ncb_rto*: UCHAR ncb_sto*: UCHAR - ncb_post*: proc (para1: p_NCB){.CDECL.} + ncb_post*: proc (para1: p_NCB){.cdecl.} ncb_lana_num*: UCHAR ncb_cmd_cplt*: UCHAR ncb_reserve*: array[0..9, UCHAR] @@ -10681,7 +10681,7 @@ type nErrCode*: int16 Reserved1*: int16 Reserved2*: int16 - szPathName*: array[0..(OFS_MAXPATHNAME) - 1, CHAR] + szPathName*: array[0..(OFS_MAXPATHNAME) - 1, char] LPOFSTRUCT* = ptr OFSTRUCT TOFSTRUCT* = OFSTRUCT @@ -10733,8 +10733,8 @@ type lpfnHook*: LPOFNHOOKPROC lpTemplateName*: LPCTSTR pvReserved*: pointer - dwreserved*: dword - FlagsEx*: dword + dwreserved*: DWORD + FlagsEx*: DWORD LPOPENFILENAME* = ptr TOPENFILENAME POPENFILENAME* = ptr TOPENFILENAME @@ -11280,8 +11280,8 @@ type dwSize*: DWORD hrasconn*: HRASCONN szEntryName*: array[0..(RAS_MaxEntryName + 1) - 1, TCHAR] - szDeviceType*: array[0..(RAS_MaxDeviceType + 1) - 1, CHAR] - szDeviceName*: array[0..(RAS_MaxDeviceName + 1) - 1, CHAR] + szDeviceType*: array[0..(RAS_MaxDeviceType + 1) - 1, char] + szDeviceName*: array[0..(RAS_MaxDeviceName + 1) - 1, char] TRASCONN* = RASCONN PRASCONN* = ptr RASCONN @@ -11344,9 +11344,9 @@ type TRASPPPNBF* = RASPPPNBF PRASPPPNBF* = ptr RASPPPNBF RASTERIZER_STATUS* {.final, pure.} = object - nSize*: short - wFlags*: short - nLanguageID*: short + nSize*: SHORT + wFlags*: SHORT + nLanguageID*: SHORT LPRASTERIZER_STATUS* = ptr RASTERIZER_STATUS TRASTERIZERSTATUS* = RASTERIZER_STATUS @@ -11592,7 +11592,7 @@ type PSTRRET* = ptr STRRET STYLEBUF* {.final, pure.} = object dwStyle*: DWORD - szDescription*: array[0..31, CHAR] + szDescription*: array[0..31, char] LPSTYLEBUF* = ptr STYLEBUF TSTYLEBUF* = STYLEBUF @@ -11801,7 +11801,7 @@ type TTOGGLEKEYS* = TOGGLEKEYS PTOGGLEKEYS* = ptr TOGGLEKEYS TTOKEN_SOURCE* {.final, pure.} = object - SourceName*: array[0..7, CHAR] + SourceName*: array[0..7, char] SourceIdentifier*: LUID PTOKENSOURCE* = ptr TTOKEN_SOURCE @@ -12366,7 +12366,7 @@ type uFlags*: WINUINT uCallbackMessage*: WINUINT hIcon*: HICON - szTip*: array[0..63, Char] + szTip*: array[0..63, char] NOTIFYICONDATA* = NOTIFYICONDATAA NOTIFYICONDATAW* {.final, pure.} = object @@ -13575,7 +13575,7 @@ type TWMSysKeyUp* = TWMKey TWMMenuChar* {.final, pure.} = object Msg*: WINUINT - User*: Char + User*: char MenuFlag*: int16 Menu*: HMENU Result*: LRESULT @@ -14432,19 +14432,19 @@ proc CharNextA*(lpsz: LPCSTR): LPSTR{.stdcall, dynlib: "user32", importc: "CharNextA".} proc CharPrevA*(lpszStart: LPCSTR, lpszCurrent: LPCSTR): LPSTR{.stdcall, dynlib: "user32", importc: "CharPrevA".} -proc IsCharAlphaA*(ch: CHAR): WINBOOL{.stdcall, dynlib: "user32", +proc IsCharAlphaA*(ch: char): WINBOOL{.stdcall, dynlib: "user32", importc: "IsCharAlphaA".} -proc IsCharAlphaNumericA*(ch: CHAR): WINBOOL{.stdcall, dynlib: "user32", +proc IsCharAlphaNumericA*(ch: char): WINBOOL{.stdcall, dynlib: "user32", importc: "IsCharAlphaNumericA".} -proc IsCharUpperA*(ch: CHAR): WINBOOL{.stdcall, dynlib: "user32", +proc IsCharUpperA*(ch: char): WINBOOL{.stdcall, dynlib: "user32", importc: "IsCharUpperA".} -proc IsCharLowerA*(ch: CHAR): WINBOOL{.stdcall, dynlib: "user32", +proc IsCharLowerA*(ch: char): WINBOOL{.stdcall, dynlib: "user32", importc: "IsCharLowerA".} proc GetKeyNameTextA*(lParam: LONG, lpString: LPSTR, nSize: int32): int32{. stdcall, dynlib: "user32", importc: "GetKeyNameTextA".} -proc VkKeyScanA*(ch: CHAR): SHORT{.stdcall, dynlib: "user32", +proc VkKeyScanA*(ch: char): SHORT{.stdcall, dynlib: "user32", importc: "VkKeyScanA".} -proc VkKeyScanExA*(ch: CHAR, dwhkl: HKL): SHORT{.stdcall, dynlib: "user32", +proc VkKeyScanExA*(ch: char, dwhkl: HKL): SHORT{.stdcall, dynlib: "user32", importc: "VkKeyScanExA".} proc MapVirtualKeyA*(uCode: WINUINT, uMapType: WINUINT): WINUINT{.stdcall, dynlib: "user32", importc: "MapVirtualKeyA".} @@ -14772,7 +14772,7 @@ proc DialogBoxA*(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND, lpDialogFunc: DLGPROC): int32 proc DialogBoxIndirectA*(hInstance: HINST, hDialogTemplate: LPCDLGTEMPLATE, hWndParent: HWND, lpDialogFunc: DLGPROC): int32 -proc CreateDCA*(para1: LPCSTR, para2: LPCSTR, para3: LPCSTR, para4: pDEVMODE): HDC{. +proc CreateDCA*(para1: LPCSTR, para2: LPCSTR, para3: LPCSTR, para4: PDEVMODE): HDC{. stdcall, dynlib: "gdi32", importc: "CreateDCA".} proc VerInstallFileA*(uFlags: DWORD, szSrcFileName: LPSTR, szDestFileName: LPSTR, szSrcDir: LPSTR, szDestDir: LPSTR, @@ -14933,7 +14933,7 @@ proc WriteConsoleOutputCharacterA*(hConsoleOutput: HANDLE, lpCharacter: LPCSTR, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfCharsWritten: LPDWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterA".} -proc FillConsoleOutputCharacterA*(hConsoleOutput: HANDLE, cCharacter: CHAR, +proc FillConsoleOutputCharacterA*(hConsoleOutput: HANDLE, cCharacter: char, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfCharsWritten: LPDWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterA".} @@ -15896,7 +15896,7 @@ proc DialogBoxW*(hInstance: HINST, lpTemplate: LPCWSTR, hWndParent: HWND, lpDialogFunc: DLGPROC): int32 proc DialogBoxIndirectW*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE, hWndParent: HWND, lpDialogFunc: DLGPROC): int32 -proc CreateDCW*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR, para4: pDEVMODEW): HDC{. +proc CreateDCW*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR, para4: PDEVMODEW): HDC{. stdcall, dynlib: "gdi32", importc: "CreateDCW".} proc VerInstallFileW*(uFlags: DWORD, szSrcFileName: LPWSTR, szDestFileName: LPWSTR, szSrcDir: LPWSTR, @@ -17038,7 +17038,7 @@ when defined(winUnicode): lpDialogFunc: DLGPROC): int32 proc DialogBoxIndirect*(hInstance: HINST, lpTemplate: LPCDLGTEMPLATE, hWndParent: HWND, lpDialogFunc: DLGPROC): int32 - proc CreateDC*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR, para4: pDEVMODE): HDC{. + proc CreateDC*(para1: LPCWSTR, para2: LPCWSTR, para3: LPCWSTR, para4: PDEVMODE): HDC{. stdcall, dynlib: "gdi32", importc: "CreateDCW".} proc VerInstallFile*(uFlags: DWORD, szSrcFileName: LPWSTR, szDestFileName: LPWSTR, szSrcDir: LPWSTR, @@ -17825,19 +17825,19 @@ else: importc: "CharNextA".} proc CharPrev*(lpszStart: LPCSTR, lpszCurrent: LPCSTR): LPSTR{.stdcall, dynlib: "user32", importc: "CharPrevA".} - proc IsCharAlpha*(ch: CHAR): WINBOOL{.stdcall, dynlib: "user32", + proc IsCharAlpha*(ch: char): WINBOOL{.stdcall, dynlib: "user32", importc: "IsCharAlphaA".} - proc IsCharAlphaNumeric*(ch: CHAR): WINBOOL{.stdcall, dynlib: "user32", + proc IsCharAlphaNumeric*(ch: char): WINBOOL{.stdcall, dynlib: "user32", importc: "IsCharAlphaNumericA".} - proc IsCharUpper*(ch: CHAR): WINBOOL{.stdcall, dynlib: "user32", + proc IsCharUpper*(ch: char): WINBOOL{.stdcall, dynlib: "user32", importc: "IsCharUpperA".} - proc IsCharLower*(ch: CHAR): WINBOOL{.stdcall, dynlib: "user32", + proc IsCharLower*(ch: char): WINBOOL{.stdcall, dynlib: "user32", importc: "IsCharLowerA".} proc GetKeyNameText*(lParam: LONG, lpString: LPSTR, nSize: int32): int32{. stdcall, dynlib: "user32", importc: "GetKeyNameTextA".} - proc VkKeyScan*(ch: CHAR): SHORT{.stdcall, dynlib: "user32", + proc VkKeyScan*(ch: char): SHORT{.stdcall, dynlib: "user32", importc: "VkKeyScanA".} - proc VkKeyScanEx*(ch: CHAR, dwhkl: HKL): SHORT{.stdcall, dynlib: "user32", + proc VkKeyScanEx*(ch: char, dwhkl: HKL): SHORT{.stdcall, dynlib: "user32", importc: "VkKeyScanExA".} proc MapVirtualKey*(uCode: WINUINT, uMapType: WINUINT): WINUINT{.stdcall, dynlib: "user32", importc: "MapVirtualKeyA".} @@ -18170,7 +18170,7 @@ else: lpDialogFunc: DLGPROC): int32 proc DialogBoxIndirect*(hInstance: HINST, hDialogTemplate: LPCDLGTEMPLATE, hWndParent: HWND, lpDialogFunc: DLGPROC): int32 - proc CreateDC*(para1: LPCSTR, para2: LPCSTR, para3: LPCSTR, para4: pDEVMODE): HDC{. + proc CreateDC*(para1: LPCSTR, para2: LPCSTR, para3: LPCSTR, para4: PDEVMODE): HDC{. stdcall, dynlib: "gdi32", importc: "CreateDCA".} proc VerInstallFile*(uFlags: DWORD, szSrcFileName: LPSTR, szDestFileName: LPSTR, szSrcDir: LPSTR, szDestDir: LPSTR, @@ -18332,7 +18332,7 @@ else: nLength: DWORD, dwWriteCoord: COORD, lpNumberOfCharsWritten: LPDWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterA".} - proc FillConsoleOutputCharacter*(hConsoleOutput: HANDLE, cCharacter: CHAR, + proc FillConsoleOutputCharacter*(hConsoleOutput: HANDLE, cCharacter: char, nLength: DWORD, dwWriteCoord: COORD, lpNumberOfCharsWritten: LPDWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterA".} @@ -18513,9 +18513,9 @@ proc DisableThreadLibraryCalls*(hLibModule: HMODULE): WINBOOL{.stdcall, proc GetProcAddress*(hModule: HINST, lpProcName: LPCSTR): FARPROC{.stdcall, dynlib: "kernel32", importc: "GetProcAddress".} proc GetVersion*(): DWORD{.stdcall, dynlib: "kernel32", importc: "GetVersion".} -proc GlobalAlloc*(uFlags: INT, dwBytes: DWORD): HGLOBAL{.stdcall, +proc GlobalAlloc*(uFlags: int32, dwBytes: DWORD): HGLOBAL{.stdcall, dynlib: "kernel32", importc: "GlobalAlloc".} -proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: INT): HGLOBAL{. +proc GlobalReAlloc*(hMem: HGLOBAL, dwBytes: DWORD, uFlags: int32): HGLOBAL{. stdcall, dynlib: "kernel32", importc: "GlobalReAlloc".} proc GlobalSize*(hMem: HGLOBAL): DWORD{.stdcall, dynlib: "kernel32", importc: "GlobalSize".} @@ -19678,7 +19678,7 @@ proc GetSysColor*(nIndex: int32): DWORD{.stdcall, dynlib: "user32", importc: "GetSysColor".} proc GetSysColorBrush*(nIndex: int32): HBRUSH{.stdcall, dynlib: "user32", importc: "GetSysColorBrush".} -proc SetSysColors*(cElements: int32, lpaElements: var wINT, +proc SetSysColors*(cElements: int32, lpaElements: var WINT, lpaRgbValues: var COLORREF): WINBOOL{.stdcall, dynlib: "user32", importc: "SetSysColors".} proc DrawFocusRect*(hDC: HDC, lprc: var RECT): WINBOOL{.stdcall, @@ -19878,7 +19878,7 @@ proc CreatePen*(para1: int32, para2: int32, para3: COLORREF): HPEN{.stdcall, dynlib: "gdi32", importc: "CreatePen".} proc CreatePenIndirect*(para1: var LOGPEN): HPEN{.stdcall, dynlib: "gdi32", importc: "CreatePenIndirect".} -proc CreatePolyPolygonRgn*(para1: var POINT, para2: var wINT, para3: int32, +proc CreatePolyPolygonRgn*(para1: var POINT, para2: var WINT, para3: int32, para4: int32): HRGN{.stdcall, dynlib: "gdi32", importc: "CreatePolyPolygonRgn".} proc CreatePatternBrush*(para1: HBITMAP): HBRUSH{.stdcall, dynlib: "gdi32", @@ -20049,7 +20049,7 @@ proc PlayMetaFile*(para1: HDC, para2: HMETAFILE): WINBOOL{.stdcall, dynlib: "gdi32", importc: "PlayMetaFile".} proc PaintRgn*(para1: HDC, para2: HRGN): WINBOOL{.stdcall, dynlib: "gdi32", importc: "PaintRgn".} -proc PolyPolygon*(para1: HDC, para2: var POINT, para3: var wINT, para4: int32): WINBOOL{. +proc PolyPolygon*(para1: HDC, para2: var POINT, para3: var WINT, para4: int32): WINBOOL{. stdcall, dynlib: "gdi32", importc: "PolyPolygon".} proc PtInRegion*(para1: HRGN, para2: int32, para3: int32): WINBOOL{.stdcall, dynlib: "gdi32", importc: "PtInRegion".} @@ -20165,7 +20165,7 @@ proc GetEnhMetaFilePaletteEntries*(para1: HENHMETAFILE, para2: WINUINT, proc GetEnhMetaFileBits*(para1: HENHMETAFILE, para2: WINUINT, para3: LPBYTE): WINUINT{. stdcall, dynlib: "gdi32", importc: "GetEnhMetaFileBits".} proc GetWinMetaFileBits*(para1: HENHMETAFILE, para2: WINUINT, para3: LPBYTE, - para4: wINT, para5: HDC): WINUINT{.stdcall, + para4: WINT, para5: HDC): WINUINT{.stdcall, dynlib: "gdi32", importc: "GetWinMetaFileBits".} proc PlayEnhMetaFile*(para1: HDC, para2: HENHMETAFILE, para3: RECT): WINBOOL{. stdcall, dynlib: "gdi32", importc: "PlayEnhMetaFile".} @@ -20748,7 +20748,7 @@ proc ListView_GetColumn*(wnd: HWND, iCol: int32, col: var LV_COLUMN): LRESULT proc ListView_GetColumnWidth*(wnd: HWND, iCol: int32): LRESULT proc ListView_GetCountPerPage*(hwndLV: HWND): LRESULT proc ListView_GetEditControl*(hwndLV: HWND): LRESULT -proc ListView_GetImageList*(wnd: HWND, iImageList: wINT): LRESULT +proc ListView_GetImageList*(wnd: HWND, iImageList: WINT): LRESULT proc ListView_GetISearchString*(hwndLV: HWND, lpsz: LPTSTR): LRESULT proc ListView_GetItem*(wnd: HWND, item: var LV_ITEM): LRESULT proc ListView_GetItemCount*(wnd: HWND): LRESULT @@ -20867,13 +20867,13 @@ proc CommDlg_OpenSave_HideControl*(hdlg: HWND, id: int32): LRESULT proc CommDlg_OpenSave_SetDefExt*(hdlg: HWND, pszext: LPSTR): LRESULT proc GetNextWindow*(wnd: HWND, uCmd: WINUINT): HWND{.stdcall, dynlib: "user32", importc: "GetWindow".} -proc GlobalAllocPtr*(flags, cb: DWord): Pointer -proc GlobalFreePtr*(lp: Pointer): Pointer -proc GlobalUnlockPtr*(lp: pointer): Pointer -proc GlobalLockPtr*(lp: pointer): Pointer -proc GlobalReAllocPtr*(lp: Pointer, cbNew, flags: DWord): Pointer -proc GlobalPtrHandle*(lp: pointer): Pointer -proc SetLayeredWindowAttributes*(HWND: hwnd, crKey: COLORREF, bAlpha: int8, +proc GlobalAllocPtr*(flags, cb: DWord): pointer +proc GlobalFreePtr*(lp: pointer): pointer +proc GlobalUnlockPtr*(lp: pointer): pointer +proc GlobalLockPtr*(lp: pointer): pointer +proc GlobalReAllocPtr*(lp: pointer, cbNew, flags: DWord): pointer +proc GlobalPtrHandle*(lp: pointer): pointer +proc SetLayeredWindowAttributes*(hwnd: HWND, crKey: COLORREF, bAlpha: int8, dwFlags: DWORD): WINBOOL{.stdcall, dynlib: "user32", importc: "SetLayeredWindowAttributes".} type @@ -21059,21 +21059,21 @@ proc AllocateAndInitializeSid*(pIdentifierAuthority: TSIDIdentifierAuthority, nSubAuthorityCount: int8, nSubAuthority0, nSubAuthority1: DWORD, nSubAuthority2, nSubAuthority3, nSubAuthority4: DWORD, nSubAuthority5, - nSubAuthority6, nSubAuthority7: DWORD, pSid: var Pointer): WINBOOL{.stdcall, + nSubAuthority6, nSubAuthority7: DWORD, pSid: var pointer): WINBOOL{.stdcall, dynlib: "advapi32", importc: "AllocateAndInitializeSid".} proc AllocateLocallyUniqueId*(Luid: var TLargeInteger): WINBOOL{.stdcall, dynlib: "advapi32", importc: "AllocateLocallyUniqueId".} proc BackupRead*(hFile: THandle, lpBuffer: PByte, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: var DWORD, bAbort: WINBOOL, - bProcessSecurity: WINBOOL, lpContext: var Pointer): WINBOOL{. + bProcessSecurity: WINBOOL, lpContext: var pointer): WINBOOL{. stdcall, dynlib: "kernel32", importc: "BackupRead".} proc BackupSeek*(hFile: THandle, dwLowBytesToSeek, dwHighBytesToSeek: DWORD, lpdwLowByteSeeked, lpdwHighByteSeeked: var DWORD, - lpContext: Pointer): WINBOOL{.stdcall, dynlib: "kernel32", + lpContext: pointer): WINBOOL{.stdcall, dynlib: "kernel32", importc: "BackupSeek".} proc BackupWrite*(hFile: THandle, lpBuffer: PByte, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: var DWORD, - bAbort, bProcessSecurity: WINBOOL, lpContext: var Pointer): WINBOOL{. + bAbort, bProcessSecurity: WINBOOL, lpContext: var pointer): WINBOOL{. stdcall, dynlib: "kernel32", importc: "BackupWrite".} proc BeginPaint*(wnd: HWND, lpPaint: var TPaintStruct): HDC{.stdcall, dynlib: "user32", importc: "BeginPaint".} @@ -21098,18 +21098,18 @@ proc CallMsgFilterA*(lpMsg: var TMsg, nCode: int): WINBOOL{.stdcall, dynlib: "user32", importc: "CallMsgFilterA".} proc CallMsgFilterW*(lpMsg: var TMsg, nCode: int): WINBOOL{.stdcall, dynlib: "user32", importc: "CallMsgFilterW".} -proc CallNamedPipe*(lpNamedPipeName: cstring, lpInBuffer: Pointer, - nInBufferSize: DWORD, lpOutBuffer: Pointer, +proc CallNamedPipe*(lpNamedPipeName: cstring, lpInBuffer: pointer, + nInBufferSize: DWORD, lpOutBuffer: pointer, nOutBufferSize: DWORD, lpBytesRead: var DWORD, nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "CallNamedPipeA".} -proc CallNamedPipeA*(lpNamedPipeName: LPCSTR, lpInBuffer: Pointer, - nInBufferSize: DWORD, lpOutBuffer: Pointer, +proc CallNamedPipeA*(lpNamedPipeName: LPCSTR, lpInBuffer: pointer, + nInBufferSize: DWORD, lpOutBuffer: pointer, nOutBufferSize: DWORD, lpBytesRead: var DWORD, nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "CallNamedPipeA".} -proc CallNamedPipeW*(lpNamedPipeName: LPWSTR, lpInBuffer: Pointer, - nInBufferSize: DWORD, lpOutBuffer: Pointer, +proc CallNamedPipeW*(lpNamedPipeName: LPWSTR, lpInBuffer: pointer, + nInBufferSize: DWORD, lpOutBuffer: pointer, nOutBufferSize: DWORD, lpBytesRead: var DWORD, nTimeOut: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "CallNamedPipeW".} @@ -21122,15 +21122,15 @@ proc ChangeDisplaySettingsA*(lpDevMode: var TDeviceModeA, dwFlags: DWORD): int32 stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsA".} proc ChangeDisplaySettingsEx*(lpszDeviceName: cstring, lpDevMode: var TDeviceMode, wnd: HWND, - dwFlags: DWORD, lParam: Pointer): int32{.stdcall, + dwFlags: DWORD, lParam: pointer): int32{.stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsExA".} proc ChangeDisplaySettingsExA*(lpszDeviceName: LPCSTR, lpDevMode: var TDeviceModeA, wnd: HWND, - dwFlags: DWORD, lParam: Pointer): int32{.stdcall, + dwFlags: DWORD, lParam: pointer): int32{.stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsExA".} proc ChangeDisplaySettingsExW*(lpszDeviceName: LPWSTR, lpDevMode: var TDeviceModeW, wnd: HWND, - dwFlags: DWORD, lParam: Pointer): int32{.stdcall, + dwFlags: DWORD, lParam: pointer): int32{.stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsExW".} proc ChangeDisplaySettingsW*(lpDevMode: var TDeviceModeW, dwFlags: DWORD): int32{. stdcall, dynlib: "user32", importc: "ChangeDisplaySettingsW".} @@ -21184,8 +21184,8 @@ proc CreateDialogIndirectParam*(hInstance: HINST, lpTemplate: TDlgTemplate, #function CreateDialogIndirectParamA(hInstance: HINST; const lpTemplate: TDlgTemplate; hWndParent: HWND; lpDialogFunc: TFNDlgProc; dwInitParam: LPARAM): HWND; stdcall; external 'user32' name 'CreateDialogIndirectParamA'; #function CreateDialogIndirectParamW(hInstance: HINST; const lpTemplate: TDlgTemplate; hWndParent: HWND; lpDialogFunc: TFNDlgProc; dwInitParam: LPARAM): HWND; stdcall; external 'user32' name 'CreateDialogIndirectParamW'; #function CreateDIBitmap(DC: HDC; var InfoHeader: TBitmapInfoHeader; dwUsage: DWORD; InitBits: PChar; var InitInfo: TBitmapInfo; wUsage: WINUINT): HBITMAP; stdcall; external 'gdi32' name 'CreateDIBitmap'; - #function CreateDIBPatternBrushPt(const p1: Pointer; p2: WINUINT): HBRUSH; stdcall; external 'gdi32' name 'CreateDIBPatternBrushPt'; - #function CreateDIBSection(DC: HDC; const p2: TBitmapInfo; p3: WINUINT; var p4: Pointer; p5: THandle; p6: DWORD): HBITMAP; stdcall; external 'gdi32' name 'CreateDIBSection'; + #function CreateDIBPatternBrushPt(const p1: pointer; p2: WINUINT): HBRUSH; stdcall; external 'gdi32' name 'CreateDIBPatternBrushPt'; + #function CreateDIBSection(DC: HDC; const p2: TBitmapInfo; p3: WINUINT; var p4: pointer; p5: THandle; p6: DWORD): HBITMAP; stdcall; external 'gdi32' name 'CreateDIBSection'; #function CreateEllipticRgnIndirect(const p1: TRect): HRGN; stdcall; external 'gdi32' name 'CreateEllipticRgnIndirect'; #function CreateFontIndirect(const p1: TLogFont): HFONT;stdcall; external 'gdi32' name 'CreateFontIndirectA'; #function CreateFontIndirectA(const p1: TLogFontA): HFONT; stdcall; external 'gdi32' name 'CreateFontIndirectA'; @@ -21211,39 +21211,39 @@ proc CreatePolyPolygonRgn*(pPtStructs: pointer, pIntArray: pointer, p3, p4: int) proc CreateProcess*(lpApplicationName: cstring, lpCommandLine: cstring, lpProcessAttributes, lpThreadAttributes: PSecurityAttributes, bInheritHandles: WINBOOL, dwCreationFlags: DWORD, - lpEnvironment: Pointer, lpCurrentDirectory: cstring, + lpEnvironment: pointer, lpCurrentDirectory: cstring, lpStartupInfo: TStartupInfo, lpProcessInformation: var TProcessInformation): WINBOOL{. stdcall, dynlib: "kernel32", importc: "CreateProcessA".} proc CreateProcessA*(lpApplicationName: LPCSTR, lpCommandLine: LPCSTR, lpProcessAttributes, lpThreadAttributes: PSecurityAttributes, bInheritHandles: WINBOOL, dwCreationFlags: DWORD, - lpEnvironment: Pointer, lpCurrentDirectory: LPCSTR, + lpEnvironment: pointer, lpCurrentDirectory: LPCSTR, lpStartupInfo: TStartupInfo, lpProcessInformation: var TProcessInformation): WINBOOL{. stdcall, dynlib: "kernel32", importc: "CreateProcessA".} #function CreateProcessAsUser(hToken: THandle; lpApplicationName: PChar; lpCommandLine: PChar; lpProcessAttributes: PSecurityAttributes; lpThreadAttributes: PSecurityAttributes; bInheritHandles: WINBOOL; dwCreationFlags: DWORD; - # lpEnvironment: Pointer; lpCurrentDirectory: PChar; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): WINBOOL;stdcall; external 'advapi32' name 'CreateProcessAsUserA'; + # lpEnvironment: pointer; lpCurrentDirectory: PChar; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): WINBOOL;stdcall; external 'advapi32' name 'CreateProcessAsUserA'; #function CreateProcessAsUserA(hToken: THandle; lpApplicationName: LPCSTR; lpCommandLine: LPCSTR; lpProcessAttributes: PSecurityAttributes; lpThreadAttributes: PSecurityAttributes; bInheritHandles: WINBOOL; dwCreationFlags: DWORD; - # lpEnvironment: Pointer; lpCurrentDirectory: LPCSTR; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): WINBOOL; stdcall; external 'advapi32' name 'CreateProcessAsUserA'; + # lpEnvironment: pointer; lpCurrentDirectory: LPCSTR; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): WINBOOL; stdcall; external 'advapi32' name 'CreateProcessAsUserA'; #function CreateProcessAsUserW(hToken: THandle; lpApplicationName: LPWSTR; lpCommandLine: LPWSTR; lpProcessAttributes: PSecurityAttributes; lpThreadAttributes: PSecurityAttributes; bInheritHandles: WINBOOL; dwCreationFlags: DWORD; - # lpEnvironment: Pointer; lpCurrentDirectory: LPWSTR; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): WINBOOL; stdcall; external 'advapi32' name 'CreateProcessAsUserW'; + # lpEnvironment: pointer; lpCurrentDirectory: LPWSTR; const lpStartupInfo: TStartupInfo; var lpProcessInformation: TProcessInformation): WINBOOL; stdcall; external 'advapi32' name 'CreateProcessAsUserW'; proc CreateProcessW*(lpApplicationName: LPWSTR, lpCommandLine: LPWSTR, lpProcessAttributes, lpThreadAttributes: PSecurityAttributes, bInheritHandles: WINBOOL, dwCreationFlags: DWORD, - lpEnvironment: Pointer, lpCurrentDirectory: LPWSTR, + lpEnvironment: pointer, lpCurrentDirectory: LPWSTR, lpStartupInfo: TStartupInfo, lpProcessInformation: var TProcessInformation): WINBOOL{. stdcall, dynlib: "kernel32", importc: "CreateProcessW".} #function CreateRectRgnIndirect(const p1: TRect): HRGN; stdcall; external 'gdi32' name 'CreateRectRgnIndirect'; -proc CreateRemoteThread*(hProcess: THandle, lpThreadAttributes: Pointer, +proc CreateRemoteThread*(hProcess: THandle, lpThreadAttributes: pointer, dwStackSize: DWORD, lpStartAddress: TFNThreadStartRoutine, - lpParameter: Pointer, dwCreationFlags: DWORD, + lpParameter: pointer, dwCreationFlags: DWORD, lpThreadId: var DWORD): THandle{.stdcall, dynlib: "kernel32", importc: "CreateRemoteThread".} -proc CreateThread*(lpThreadAttributes: Pointer, dwStackSize: DWORD, - lpStartAddress: TFNThreadStartRoutine, lpParameter: Pointer, +proc CreateThread*(lpThreadAttributes: pointer, dwStackSize: DWORD, + lpStartAddress: TFNThreadStartRoutine, lpParameter: pointer, dwCreationFlags: DWORD, lpThreadId: var DWORD): THandle{. stdcall, dynlib: "kernel32", importc: "CreateThread".} proc DdeSetQualityOfService*(hWndClient: HWnd, @@ -21256,8 +21256,8 @@ proc DescribePixelFormat*(DC: HDC, p2: int, p3: WINUINT, dynlib: "gdi32", importc: "DescribePixelFormat".} #function DestroyPrivateObjectSecurity(var ObjectDescriptor: PSecurityDescriptor): WINBOOL; stdcall; external 'advapi32' name 'DestroyPrivateObjectSecurity'; proc DeviceIoControl*(hDevice: THandle, dwIoControlCode: DWORD, - lpInBuffer: Pointer, nInBufferSize: DWORD, - lpOutBuffer: Pointer, nOutBufferSize: DWORD, + lpInBuffer: pointer, nInBufferSize: DWORD, + lpOutBuffer: pointer, nOutBufferSize: DWORD, lpBytesReturned: var DWORD, lpOverlapped: POverlapped): WINBOOL{. stdcall, dynlib: "kernel32", importc: "DeviceIoControl".} proc DialogBoxIndirectParam*(hInstance: HINST, lpDialogTemplate: TDlgTemplate, @@ -21311,9 +21311,9 @@ proc DrawTextW*(hDC: HDC, lpString: LPWSTR, nCount: int, lpRect: var TRect, # stdcall; external 'advapi32' name 'DuplicateTokenEx'; proc EndPaint*(wnd: HWND, lpPaint: TPaintStruct): WINBOOL{.stdcall, dynlib: "user32", importc: "EndPaint".} - #function EnumDisplayDevices(Unused: Pointer; iDevNum: DWORD; var lpDisplayDevice: TDisplayDevice; dwFlags: DWORD): WINBOOL;stdcall; external 'user32' name 'EnumDisplayDevicesA'; - #function EnumDisplayDevicesA(Unused: Pointer; iDevNum: DWORD; var lpDisplayDevice: TDisplayDeviceA; dwFlags: DWORD): WINBOOL;stdcall; external 'user32' name 'EnumDisplayDevicesA'; - #function EnumDisplayDevicesW(Unused: Pointer; iDevNum: DWORD; var lpDisplayDevice: TDisplayDeviceW; dwFlags: DWORD): WINBOOL;stdcall; external 'user32' name 'EnumDisplayDevicesW'; + #function EnumDisplayDevices(Unused: pointer; iDevNum: DWORD; var lpDisplayDevice: TDisplayDevice; dwFlags: DWORD): WINBOOL;stdcall; external 'user32' name 'EnumDisplayDevicesA'; + #function EnumDisplayDevicesA(Unused: pointer; iDevNum: DWORD; var lpDisplayDevice: TDisplayDeviceA; dwFlags: DWORD): WINBOOL;stdcall; external 'user32' name 'EnumDisplayDevicesA'; + #function EnumDisplayDevicesW(Unused: pointer; iDevNum: DWORD; var lpDisplayDevice: TDisplayDeviceW; dwFlags: DWORD): WINBOOL;stdcall; external 'user32' name 'EnumDisplayDevicesW'; proc EnumDisplaySettings*(lpszDeviceName: cstring, iModeNum: DWORD, lpDevMode: var TDeviceMode): WINBOOL{.stdcall, dynlib: "user32", importc: "EnumDisplaySettingsA".} @@ -21323,13 +21323,13 @@ proc EnumDisplaySettingsA*(lpszDeviceName: LPCSTR, iModeNum: DWORD, proc EnumDisplaySettingsW*(lpszDeviceName: LPWSTR, iModeNum: DWORD, lpDevMode: var TDeviceModeW): WINBOOL{.stdcall, dynlib: "user32", importc: "EnumDisplaySettingsW".} - #function EnumEnhMetaFile(DC: HDC; p2: HENHMETAFILE; p3: TFNEnhMFEnumProc; p4: Pointer; const p5: TRect): WINBOOL; stdcall; external 'gdi32' name 'EnumEnhMetaFile'; + #function EnumEnhMetaFile(DC: HDC; p2: HENHMETAFILE; p3: TFNEnhMFEnumProc; p4: pointer; const p5: TRect): WINBOOL; stdcall; external 'gdi32' name 'EnumEnhMetaFile'; #function EnumFontFamiliesEx(DC: HDC; var p2: TLogFont; p3: TFNFontEnumProc; p4: LPARAM; p5: DWORD): WINBOOL;stdcall; external 'gdi32' name 'EnumFontFamiliesExA'; #function EnumFontFamiliesExA(DC: HDC; var p2: TLogFontA; p3: TFNFontEnumProcA; p4: LPARAM; p5: DWORD): WINBOOL; stdcall; external 'gdi32' name 'EnumFontFamiliesExA'; #function EnumFontFamiliesExW(DC: HDC; var p2: TLogFontW; p3: TFNFontEnumProcW; p4: LPARAM; p5: DWORD): WINBOOL; stdcall; external 'gdi32' name 'EnumFontFamiliesExW'; #function EqualRect(const lprc1, lprc2: TRect): WINBOOL; stdcall; external 'user32' name 'EqualRect'; proc ExtCreatePen*(PenStyle, Width: DWORD, Brush: TLogBrush, StyleCount: DWORD, - Style: Pointer): HPEN{.stdcall, dynlib: "gdi32", + Style: pointer): HPEN{.stdcall, dynlib: "gdi32", importc: "ExtCreatePen".} proc ExtCreateRegion*(p1: PXForm, p2: DWORD, p3: TRgnData): HRGN{.stdcall, dynlib: "gdi32", importc: "ExtCreateRegion".} @@ -21346,7 +21346,7 @@ proc FillConsoleOutputAttribute*(hConsoleOutput: THandle, wAttribute: int16, nLength: DWORD, dwWriteCoord: TCoord, lpNumberOfAttrsWritten: var DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "FillConsoleOutputAttribute".} -proc FillConsoleOutputCharacter*(hConsoleOutput: THandle, cCharacter: Char, +proc FillConsoleOutputCharacter*(hConsoleOutput: THandle, cCharacter: char, nLength: DWORD, dwWriteCoord: TCoord, lpNumberOfCharsWritten: var DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "FillConsoleOutputCharacterA".} @@ -21365,18 +21365,18 @@ proc FindFirstFileA*(lpFileName: LPCSTR, lpFindFileData: var TWIN32FindDataA): T stdcall, dynlib: "kernel32", importc: "FindFirstFileA".} proc FindFirstFileW*(lpFileName: LPWSTR, lpFindFileData: var TWIN32FindDataW): THandle{. stdcall, dynlib: "kernel32", importc: "FindFirstFileW".} - #function FindFirstFreeAce(var pAcl: TACL; var pAce: Pointer): WINBOOL; stdcall; external 'advapi32' name 'FindFirstFreeAce'; + #function FindFirstFreeAce(var pAcl: TACL; var pAce: pointer): WINBOOL; stdcall; external 'advapi32' name 'FindFirstFreeAce'; proc FindNextFile*(hFindFile: THandle, lpFindFileData: var TWIN32FindData): WINBOOL{. stdcall, dynlib: "kernel32", importc: "FindNextFileA".} proc FindNextFileA*(hFindFile: THandle, lpFindFileData: var TWIN32FindDataA): WINBOOL{. stdcall, dynlib: "kernel32", importc: "FindNextFileA".} proc FindNextFileW*(hFindFile: THandle, lpFindFileData: var TWIN32FindDataW): WINBOOL{. stdcall, dynlib: "kernel32", importc: "FindNextFileW".} - #function FlushInstructionCache(hProcess: THandle; const lpBaseAddress: Pointer; dwSize: DWORD): WINBOOL; stdcall; external 'kernel32' name 'FlushInstructionCache'; - #function FlushViewOfFile(const lpBaseAddress: Pointer; dwNumberOfBytesToFlush: DWORD): WINBOOL; stdcall; external 'kernel32' name 'FlushViewOfFile'; + #function FlushInstructionCache(hProcess: THandle; const lpBaseAddress: pointer; dwSize: DWORD): WINBOOL; stdcall; external 'kernel32' name 'FlushInstructionCache'; + #function FlushViewOfFile(const lpBaseAddress: pointer; dwNumberOfBytesToFlush: DWORD): WINBOOL; stdcall; external 'kernel32' name 'FlushViewOfFile'; #function FrameRect(hDC: HDC; const lprc: TRect; hbr: HBRUSH): Integer; stdcall; external 'user32' name 'FrameRect'; - #function GetAce(const pAcl: TACL; dwAceIndex: DWORD; var pAce: Pointer): WINBOOL; stdcall; external 'advapi32' name 'GetAce'; - #function GetAclInformation(const pAcl: TACL; pAclInformation: Pointer; nAclInformationLength: DWORD; dwAclInformationClass: TAclInformationClass): WINBOOL; stdcall; external 'advapi32' name 'GetAclInformation'; + #function GetAce(const pAcl: TACL; dwAceIndex: DWORD; var pAce: pointer): WINBOOL; stdcall; external 'advapi32' name 'GetAce'; + #function GetAclInformation(const pAcl: TACL; pAclInformation: pointer; nAclInformationLength: DWORD; dwAclInformationClass: TAclInformationClass): WINBOOL; stdcall; external 'advapi32' name 'GetAclInformation'; #function GetAltTabInfo(wnd: HWND; iItem: Integer; var pati: TAltTabInfo; pszItemText: PChar; cchItemText: WINUINT): WINBOOL;stdcall; external 'user32' name 'GetAltTabInfoA'; #function GetAltTabInfoA(wnd: HWND; iItem: Integer; var pati: TAltTabInfo; pszItemText: LPCSTR; cchItemText: WINUINT): WINBOOL;stdcall; external 'user32' name 'GetAltTabInfoA'; #function GetAltTabInfoW(wnd: HWND; iItem: Integer; var pati: TAltTabInfo; pszItemText: LPWSTR; cchItemText: WINUINT): WINBOOL;stdcall; external 'user32' name 'GetAltTabInfoW'; @@ -21507,7 +21507,7 @@ proc GetDefaultCommConfigW*(lpszName: LPWSTR, lpCC: var TCommConfig, proc GetDIBColorTable*(DC: HDC, p2, p3: WINUINT, RGBQuadStructs: pointer): WINUINT{. stdcall, dynlib: "gdi32", importc: "GetDIBColorTable".} proc GetDIBits*(DC: HDC, Bitmap: HBitmap, StartScan, NumScans: WINUINT, - Bits: Pointer, BitInfo: var TBitmapInfo, Usage: WINUINT): int{. + Bits: pointer, BitInfo: var TBitmapInfo, Usage: WINUINT): int{. stdcall, dynlib: "gdi32", importc: "GetDIBits".} proc GetDiskFreeSpace*(lpRootPathName: cstring, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters: var DWORD): WINBOOL{. @@ -21531,13 +21531,13 @@ proc GetDiskFreeSpaceW*(lpRootPathName: LPWSTR, lpSectorsPerCluster, lpBytesPerSector, lpNumberOfFreeClusters, lpTotalNumberOfClusters: var DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceW".} proc GetDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller, - lpTotalNumberOfBytes: pLargeInteger, lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{. + lpTotalNumberOfBytes: PLargeInteger, lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{. stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".} proc GetDiskFreeSpaceExA*(lpDirectoryName: LPCSTR, lpFreeBytesAvailableToCaller, - lpTotalNumberOfBytes: pLargeInteger, lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{. + lpTotalNumberOfBytes: PLargeInteger, lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{. stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".} proc GetDiskFreeSpaceExW*(lpDirectoryName: LPWSTR, lpFreeBytesAvailableToCaller, - lpTotalNumberOfBytes: pLargeInteger, lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{. + lpTotalNumberOfBytes: PLargeInteger, lpTotalNumberOfFreeBytes: PLargeInteger): WINBOOL{. stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExW".} #function GetEnhMetaFilePixelFormat(p1: HENHMETAFILE; p2: Cardinal; var p3: TPixelFormatDescriptor): WINUINT;stdcall; external 'gdi32' name 'GetEnhMetaFilePixelFormat'; proc GetExitCodeProcess*(hProcess: THandle, lpExitCode: var DWORD): WINBOOL{. @@ -21560,13 +21560,13 @@ proc GetFileVersionInfoSizeW*(lptstrFilename: LPWSTR, lpdwHandle: var DWORD): DW # function GetFullPathNameA(lpFileName: LPCSTR; nBufferLength: DWORD; lpBuffer: LPCSTR; var lpFilePart: LPCSTR): DWORD; stdcall; external 'kernel32' name 'GetFullPathNameA'; # function GetFullPathNameW(lpFileName: LPWSTR; nBufferLength: DWORD; lpBuffer: LPWSTR; var lpFilePart: LPWSTR): DWORD; stdcall; external 'kernel32' name 'GetFullPathNameW'; proc GetGlyphOutline*(DC: HDC, p2, p3: WINUINT, p4: TGlyphMetrics, p5: DWORD, - p6: Pointer, p7: TMat2): DWORD{.stdcall, dynlib: "gdi32", + p6: pointer, p7: TMat2): DWORD{.stdcall, dynlib: "gdi32", importc: "GetGlyphOutlineA".} proc GetGlyphOutlineA*(DC: HDC, p2, p3: WINUINT, p4: TGlyphMetrics, p5: DWORD, - p6: Pointer, p7: TMat2): DWORD{.stdcall, dynlib: "gdi32", + p6: pointer, p7: TMat2): DWORD{.stdcall, dynlib: "gdi32", importc: "GetGlyphOutlineA".} proc GetGlyphOutlineW*(DC: HDC, p2, p3: WINUINT, p4: TGlyphMetrics, p5: DWORD, - p6: Pointer, p7: TMat2): DWORD{.stdcall, dynlib: "gdi32", + p6: pointer, p7: TMat2): DWORD{.stdcall, dynlib: "gdi32", importc: "GetGlyphOutlineW".} #function GetGUIThreadInfo(idThread: DWORD; var pgui: TGUIThreadinfo): WINBOOL;stdcall; external 'user32' name 'GetGUIThreadInfo'; proc GetHandleInformation*(hObject: THandle, lpdwFlags: var DWORD): WINBOOL{. @@ -21600,9 +21600,9 @@ proc GetLogColorSpaceA*(p1: HCOLORSPACE, ColorSpace: var TLogColorSpaceA, Size: DWORD): WINBOOL{.stdcall, dynlib: "gdi32", importc: "GetLogColorSpaceA".} #function GetLogColorSpaceW(p1: HCOLORSPACE; var ColorSpace: TLogColorSpaceW; Size: DWORD): WINBOOL; stdcall; external 'gdi32' name 'GetLogColorSpaceW'; -proc GetMailslotInfo*(hMailslot: THandle, lpMaxMessageSize: Pointer, +proc GetMailslotInfo*(hMailslot: THandle, lpMaxMessageSize: pointer, lpNextSize: var DWORD, - lpMessageCount, lpReadTimeout: Pointer): WINBOOL{.stdcall, + lpMessageCount, lpReadTimeout: pointer): WINBOOL{.stdcall, dynlib: "kernel32", importc: "GetMailslotInfo".} #function GetMenuBarInfo(hend: HWND; idObject, idItem: Longint; var pmbi: TMenuBarInfo): WINBOOL;stdcall; external 'user32' name 'GetMenuBarInfo'; #function GetMenuInfo(menu: HMENU; var lpmi: TMenuInfo): WINBOOL;stdcall; external 'user32' name 'GetMenuInfo'; @@ -21625,7 +21625,7 @@ proc GetMiterLimit*(DC: HDC, Limit: var float32): WINBOOL{.stdcall, dynlib: "gdi32", importc: "GetMiterLimit".} #function GetMouseMovePoints(cbSize: WINUINT; var lppt, lpptBuf: TMouseMovePoint; nBufPoints: Integer; resolution: DWORD): Integer;stdcall; external 'user32' name 'GetMouseMovePoints'; proc GetNamedPipeInfo*(hNamedPipe: THandle, lpFlags: var DWORD, - lpOutBufferSize, lpInBufferSize, lpMaxInstances: Pointer): WINBOOL{. + lpOutBufferSize, lpInBufferSize, lpMaxInstances: pointer): WINBOOL{. stdcall, dynlib: "kernel32", importc: "GetNamedPipeInfo".} proc GetNumberOfConsoleInputEvents*(hConsoleInput: THandle, lpNumberOfEvents: var DWORD): WINBOOL{. @@ -21738,11 +21738,11 @@ proc GetTabbedTextExtentW*(hDC: HDC, lpString: LPWSTR, lpnTabStopPositions: pointer): DWORD{.stdcall, dynlib: "user32", importc: "GetTabbedTextExtentW".} proc GetTapeParameters*(hDevice: THandle, dwOperation: DWORD, - lpdwSize: var DWORD, lpTapeInformation: Pointer): DWORD{. + lpdwSize: var DWORD, lpTapeInformation: pointer): DWORD{. stdcall, dynlib: "kernel32", importc: "GetTapeParameters".} proc GetTapePosition*(hDevice: THandle, dwPositionType: DWORD, lpdwPartition, lpdwOffsetLow: var DWORD, - lpdwOffsetHigh: Pointer): DWORD{.stdcall, + lpdwOffsetHigh: pointer): DWORD{.stdcall, dynlib: "kernel32", importc: "GetTapePosition".} proc GetTextExtentExPoint*(DC: HDC, p2: cstring, p3, p4: int, p5, p6: PInteger, p7: var TSize): WINBOOL{.stdcall, dynlib: "gdi32", @@ -21784,7 +21784,7 @@ proc GetThreadTimes*(hThread: THandle, lpCreationTime, lpExitTime, lpKernelTime, proc GetTimeZoneInformation*(lpTimeZoneInformation: var TTimeZoneInformation): DWORD{. stdcall, dynlib: "kernel32", importc: "GetTimeZoneInformation".} #function GetTitleBarInfo(wnd: HWND; var pti: TTitleBarInfo): WINBOOL;stdcall; external 'user32' name 'GetTitleBarInfo'; - #function GetTokenInformation(TokenHandle: THandle; TokenInformationClass: TTokenInformationClass; TokenInformation: Pointer; TokenInformationLength: DWORD; var ReturnLength: DWORD): WINBOOL; stdcall; external 'advapi32' name 'GetTokenInformation'; + #function GetTokenInformation(TokenHandle: THandle; TokenInformationClass: TTokenInformationClass; TokenInformation: pointer; TokenInformationLength: DWORD; var ReturnLength: DWORD): WINBOOL; stdcall; external 'advapi32' name 'GetTokenInformation'; proc GetUpdateRect*(wnd: HWND, lpRect: var TRect, bErase: WINBOOL): WINBOOL{. stdcall, dynlib: "user32", importc: "GetUpdateRect".} proc GetUserName*(lpBuffer: cstring, nSize: var DWORD): WINBOOL{.stdcall, @@ -21793,13 +21793,13 @@ proc GetUserNameA*(lpBuffer: LPCSTR, nSize: var DWORD): WINBOOL{.stdcall, dynlib: "advapi32", importc: "GetUserNameA".} proc GetUserNameW*(lpBuffer: LPWSTR, nSize: var DWORD): WINBOOL{.stdcall, dynlib: "advapi32", importc: "GetUserNameW".} -proc GetUserObjectInformation*(hObj: THandle, nIndex: int, pvInfo: Pointer, +proc GetUserObjectInformation*(hObj: THandle, nIndex: int, pvInfo: pointer, nLength: DWORD, lpnLengthNeeded: var DWORD): WINBOOL{. stdcall, dynlib: "user32", importc: "GetUserObjectInformationA".} -proc GetUserObjectInformationA*(hObj: THandle, nIndex: int, pvInfo: Pointer, +proc GetUserObjectInformationA*(hObj: THandle, nIndex: int, pvInfo: pointer, nLength: DWORD, lpnLengthNeeded: var DWORD): WINBOOL{. stdcall, dynlib: "user32", importc: "GetUserObjectInformationA".} -proc GetUserObjectInformationW*(hObj: THandle, nIndex: int, pvInfo: Pointer, +proc GetUserObjectInformationW*(hObj: THandle, nIndex: int, pvInfo: pointer, nLength: DWORD, lpnLengthNeeded: var DWORD): WINBOOL{. stdcall, dynlib: "user32", importc: "GetUserObjectInformationW".} proc GetUserObjectSecurity*(hObj: THandle, pSIRequested: var DWORD, @@ -21845,7 +21845,7 @@ proc GetWindowRect*(wnd: HWND, lpRect: var TRect): WINBOOL{.stdcall, dynlib: "user32", importc: "GetWindowRect".} proc GetWorldTransform*(DC: HDC, p2: var TXForm): WINBOOL{.stdcall, dynlib: "gdi32", importc: "GetWorldTransform".} - #function GradientFill(DC: HDC; var p2: TTriVertex; p3: ULONG; p4: Pointer; p5, p6: ULONG): WINBOOL;stdcall; external 'gdi32' name 'GradientFill'; + #function GradientFill(DC: HDC; var p2: TTriVertex; p3: ULONG; p4: pointer; p5, p6: ULONG): WINBOOL;stdcall; external 'gdi32' name 'GradientFill'; proc GlobalMemoryStatus*(Buffer: var MEMORYSTATUS){.stdcall, dynlib: "kernel32", importc: "GlobalMemoryStatus".} proc HeapWalk*(hHeap: THandle, lpEntry: var TProcessHeapEntry): WINBOOL{. @@ -21856,7 +21856,7 @@ proc InflateRect*(lprc: var TRect, dx, dy: int): WINBOOL{.stdcall, dynlib: "user32", importc: "InflateRect".} proc InitializeAcl*(pAcl: var TACL, nAclLength, dwAclRevision: DWORD): WINBOOL{. stdcall, dynlib: "advapi32", importc: "InitializeAcl".} -proc InitializeSid*(Sid: Pointer, pIdentifierAuthority: TSIDIdentifierAuthority, +proc InitializeSid*(Sid: pointer, pIdentifierAuthority: TSIDIdentifierAuthority, nSubAuthorityCount: int8): WINBOOL{.stdcall, dynlib: "advapi32", importc: "InitializeSid".} proc InsertMenuItemA*(p1: HMENU, p2: WINUINT, p3: WINBOOL, p4: TMenuItemInfoA): WINBOOL{. @@ -21958,7 +21958,7 @@ proc MakeAbsoluteSD*(pSelfRelativeSecurityDescriptor: PSecurityDescriptor, pDacl: var TACL, lpdwDaclSize: var DWORD, pSacl: var TACL, lpdwSaclSize: var DWORD, pOwner: PSID, - lpdwOwnerSize: var DWORD, pPrimaryGroup: Pointer, + lpdwOwnerSize: var DWORD, pPrimaryGroup: pointer, lpdwPrimaryGroupSize: var DWORD): WINBOOL{.stdcall, dynlib: "advapi32", importc: "MakeAbsoluteSD".} proc MakeSelfRelativeSD*(pAbsoluteSecurityDescriptor: PSecurityDescriptor, @@ -21983,7 +21983,7 @@ proc MsgWaitForMultipleObjectsEx*(nCount: DWORD, pHandles: pointer, dwMilliseconds, dwWakeMask, dwFlags: DWORD): DWORD{. stdcall, dynlib: "user32", importc: "MsgWaitForMultipleObjectsEx".} # function MultiByteToWideChar(CodePage: WINUINT; dwFlags: DWORD; const lpMultiByteStr: LPCSTR; cchMultiByte: Integer; lLPWSTRStr: LPWSTR; cchWideChar: Integer): Integer; stdcall; external 'kernel32' name 'MultiByteToWideChar'; -proc ObjectOpenAuditAlarm*(SubsystemName: cstring, HandleId: Pointer, +proc ObjectOpenAuditAlarm*(SubsystemName: cstring, HandleId: pointer, ObjectTypeName: cstring, ObjectName: cstring, pSecurityDescriptor: PSecurityDescriptor, ClientToken: THandle, @@ -21992,7 +21992,7 @@ proc ObjectOpenAuditAlarm*(SubsystemName: cstring, HandleId: Pointer, ObjectCreation, AccessGranted: WINBOOL, GenerateOnClose: var WINBOOL): WINBOOL{.stdcall, dynlib: "advapi32", importc: "ObjectOpenAuditAlarmA".} -proc ObjectOpenAuditAlarmA*(SubsystemName: LPCSTR, HandleId: Pointer, +proc ObjectOpenAuditAlarmA*(SubsystemName: LPCSTR, HandleId: pointer, ObjectTypeName: LPCSTR, ObjectName: LPCSTR, pSecurityDescriptor: PSecurityDescriptor, ClientToken: THandle, @@ -22001,7 +22001,7 @@ proc ObjectOpenAuditAlarmA*(SubsystemName: LPCSTR, HandleId: Pointer, ObjectCreation, AccessGranted: WINBOOL, GenerateOnClose: var WINBOOL): WINBOOL{.stdcall, dynlib: "advapi32", importc: "ObjectOpenAuditAlarmA".} -proc ObjectOpenAuditAlarmW*(SubsystemName: LPWSTR, HandleId: Pointer, +proc ObjectOpenAuditAlarmW*(SubsystemName: LPWSTR, HandleId: pointer, ObjectTypeName: LPWSTR, ObjectName: LPWSTR, pSecurityDescriptor: PSecurityDescriptor, ClientToken: THandle, @@ -22010,17 +22010,17 @@ proc ObjectOpenAuditAlarmW*(SubsystemName: LPWSTR, HandleId: Pointer, ObjectCreation, AccessGranted: WINBOOL, GenerateOnClose: var WINBOOL): WINBOOL{.stdcall, dynlib: "advapi32", importc: "ObjectOpenAuditAlarmW".} -proc ObjectPrivilegeAuditAlarm*(SubsystemName: cstring, HandleId: Pointer, +proc ObjectPrivilegeAuditAlarm*(SubsystemName: cstring, HandleId: pointer, ClientToken: THandle, DesiredAccess: DWORD, Privileges: var TPrivilegeSet, AccessGranted: WINBOOL): WINBOOL{.stdcall, dynlib: "advapi32", importc: "ObjectPrivilegeAuditAlarmA".} -proc ObjectPrivilegeAuditAlarmA*(SubsystemName: LPCSTR, HandleId: Pointer, +proc ObjectPrivilegeAuditAlarmA*(SubsystemName: LPCSTR, HandleId: pointer, ClientToken: THandle, DesiredAccess: DWORD, Privileges: var TPrivilegeSet, AccessGranted: WINBOOL): WINBOOL{.stdcall, dynlib: "advapi32", importc: "ObjectPrivilegeAuditAlarmA".} -proc ObjectPrivilegeAuditAlarmW*(SubsystemName: LPWSTR, HandleId: Pointer, +proc ObjectPrivilegeAuditAlarmW*(SubsystemName: LPWSTR, HandleId: pointer, ClientToken: THandle, DesiredAccess: DWORD, Privileges: var TPrivilegeSet, AccessGranted: WINBOOL): WINBOOL{.stdcall, @@ -22111,21 +22111,21 @@ proc QueryPerformanceCounter*(lpPerformanceCount: var TLargeInteger): WINBOOL{. stdcall, dynlib: "kernel32", importc: "QueryPerformanceCounter".} proc QueryPerformanceFrequency*(lpFrequency: var TLargeInteger): WINBOOL{. stdcall, dynlib: "kernel32", importc: "QueryPerformanceFrequency".} - #function QueryRecoveryAgents(p1: PChar; var p2: Pointer; var p3: TRecoveryAgentInformation): DWORD;stdcall; external 'kernel32' name 'QueryRecoveryAgentsA'; - #function QueryRecoveryAgentsA(p1: LPCSTR; var p2: Pointer; var p3: TRecoveryAgentInformationA): DWORD;stdcall; external 'kernel32' name 'QueryRecoveryAgentsA'; - #function QueryRecoveryAgentsW(p1: LPWSTR; var p2: Pointer; var p3: TRecoveryAgentInformationW): DWORD;stdcall; external 'kernel32' name 'QueryRecoveryAgentsW'; + #function QueryRecoveryAgents(p1: PChar; var p2: pointer; var p3: TRecoveryAgentInformation): DWORD;stdcall; external 'kernel32' name 'QueryRecoveryAgentsA'; + #function QueryRecoveryAgentsA(p1: LPCSTR; var p2: pointer; var p3: TRecoveryAgentInformationA): DWORD;stdcall; external 'kernel32' name 'QueryRecoveryAgentsA'; + #function QueryRecoveryAgentsW(p1: LPWSTR; var p2: pointer; var p3: TRecoveryAgentInformationW): DWORD;stdcall; external 'kernel32' name 'QueryRecoveryAgentsW'; proc RaiseException*(dwExceptionCode: DWORD, dwExceptionFlags: DWORD, nNumberOfArguments: DWORD, lpArguments: var DWORD){. stdcall, dynlib: "kernel32", importc: "RaiseException".} proc UnhandledExceptionFilter*(ExceptionInfo: var emptyrecord): LONG{.stdcall, dynlib: "kernel32", importc: "UnhandledExceptionFilter".} -proc ReadConsole*(hConsoleInput: THandle, lpBuffer: Pointer, +proc ReadConsole*(hConsoleInput: THandle, lpBuffer: pointer, nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: var DWORD, - lpReserved: Pointer): WINBOOL{.stdcall, dynlib: "kernel32", + lpReserved: pointer): WINBOOL{.stdcall, dynlib: "kernel32", importc: "ReadConsoleA".} -proc ReadConsoleA*(hConsoleInput: THandle, lpBuffer: Pointer, +proc ReadConsoleA*(hConsoleInput: THandle, lpBuffer: pointer, nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: var DWORD, - lpReserved: Pointer): WINBOOL{.stdcall, dynlib: "kernel32", + lpReserved: pointer): WINBOOL{.stdcall, dynlib: "kernel32", importc: "ReadConsoleA".} proc ReadConsoleInput*(hConsoleInput: THandle, lpBuffer: var TInputRecord, nLength: DWORD, lpNumberOfEventsRead: var DWORD): WINBOOL{. @@ -22136,15 +22136,15 @@ proc ReadConsoleInputA*(hConsoleInput: THandle, lpBuffer: var TInputRecord, proc ReadConsoleInputW*(hConsoleInput: THandle, lpBuffer: var TInputRecord, nLength: DWORD, lpNumberOfEventsRead: var DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "ReadConsoleInputW".} -proc ReadConsoleOutput*(hConsoleOutput: THandle, lpBuffer: Pointer, +proc ReadConsoleOutput*(hConsoleOutput: THandle, lpBuffer: pointer, dwBufferSize, dwBufferCoord: TCoord, lpReadRegion: var TSmallRect): WINBOOL{.stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputA".} -proc ReadConsoleOutputA*(hConsoleOutput: THandle, lpBuffer: Pointer, +proc ReadConsoleOutputA*(hConsoleOutput: THandle, lpBuffer: pointer, dwBufferSize, dwBufferCoord: TCoord, lpReadRegion: var TSmallRect): WINBOOL{.stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputA".} -proc ReadConsoleOutputAttribute*(hConsoleOutput: THandle, lpAttribute: Pointer, +proc ReadConsoleOutputAttribute*(hConsoleOutput: THandle, lpAttribute: pointer, nLength: DWORD, dwReadCoord: TCoord, lpNumberOfAttrsRead: var DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputAttribute".} @@ -22160,31 +22160,31 @@ proc ReadConsoleOutputCharacterW*(hConsoleOutput: THandle, lpCharacter: LPCSTR, nLength: DWORD, dwReadCoord: TCoord, lpNumberOfCharsRead: var DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputCharacterW".} -proc ReadConsoleOutputW*(hConsoleOutput: THandle, lpBuffer: Pointer, +proc ReadConsoleOutputW*(hConsoleOutput: THandle, lpBuffer: pointer, dwBufferSize, dwBufferCoord: TCoord, lpReadRegion: var TSmallRect): WINBOOL{.stdcall, dynlib: "kernel32", importc: "ReadConsoleOutputW".} -proc ReadConsoleW*(hConsoleInput: THandle, lpBuffer: Pointer, +proc ReadConsoleW*(hConsoleInput: THandle, lpBuffer: pointer, nNumberOfCharsToRead: DWORD, lpNumberOfCharsRead: var DWORD, - lpReserved: Pointer): WINBOOL{.stdcall, dynlib: "kernel32", + lpReserved: pointer): WINBOOL{.stdcall, dynlib: "kernel32", importc: "ReadConsoleW".} proc ReadEventLog*(hEventLog: THandle, dwReadFlags, dwRecordOffset: DWORD, - lpBuffer: Pointer, nNumberOfBytesToRead: DWORD, + lpBuffer: pointer, nNumberOfBytesToRead: DWORD, pnBytesRead, pnMinNumberOfBytesNeeded: var DWORD): WINBOOL{. stdcall, dynlib: "advapi32", importc: "ReadEventLogA".} proc ReadEventLogA*(hEventLog: THandle, dwReadFlags, dwRecordOffset: DWORD, - lpBuffer: Pointer, nNumberOfBytesToRead: DWORD, + lpBuffer: pointer, nNumberOfBytesToRead: DWORD, pnBytesRead, pnMinNumberOfBytesNeeded: var DWORD): WINBOOL{. stdcall, dynlib: "advapi32", importc: "ReadEventLogA".} proc ReadEventLogW*(hEventLog: THandle, dwReadFlags, dwRecordOffset: DWORD, - lpBuffer: Pointer, nNumberOfBytesToRead: DWORD, + lpBuffer: pointer, nNumberOfBytesToRead: DWORD, pnBytesRead, pnMinNumberOfBytesNeeded: var DWORD): WINBOOL{. stdcall, dynlib: "advapi32", importc: "ReadEventLogW".} proc ReadFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: var DWORD, lpOverlapped: POverlapped): WINBOOL{. stdcall, dynlib: "kernel32", importc: "ReadFile".} -proc ReadProcessMemory*(hProcess: THandle, lpBaseAddress: Pointer, - lpBuffer: Pointer, nSize: DWORD, +proc ReadProcessMemory*(hProcess: THandle, lpBaseAddress: pointer, + lpBuffer: pointer, nSize: DWORD, lpNumberOfBytesRead: var DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "ReadProcessMemory".} #function RectInRegion(RGN: HRGN; const p2: TRect): WINBOOL; stdcall; external 'gdi32' name 'RectInRegion'; @@ -22217,27 +22217,27 @@ proc RegCreateKeyExW*(key: HKEY, lpSubKey: LPWSTR, Reserved: DWORD, proc RegCreateKeyW*(key: HKEY, lpSubKey: LPWSTR, phkResult: var HKEY): int32{. stdcall, dynlib: "advapi32", importc: "RegCreateKeyW".} proc RegEnumKeyEx*(key: HKEY, dwIndex: DWORD, lpName: cstring, - lpcbName: var DWORD, lpReserved: Pointer, lpClass: cstring, + lpcbName: var DWORD, lpReserved: pointer, lpClass: cstring, lpcbClass: PDWORD, lpftLastWriteTime: PFileTime): int32{. stdcall, dynlib: "advapi32", importc: "RegEnumKeyExA".} proc RegEnumKeyExA*(key: HKEY, dwIndex: DWORD, lpName: LPCSTR, - lpcbName: var DWORD, lpReserved: Pointer, lpClass: LPCSTR, + lpcbName: var DWORD, lpReserved: pointer, lpClass: LPCSTR, lpcbClass: PDWORD, lpftLastWriteTime: PFileTime): int32{. stdcall, dynlib: "advapi32", importc: "RegEnumKeyExA".} proc RegEnumKeyExW*(key: HKEY, dwIndex: DWORD, lpName: LPWSTR, - lpcbName: var DWORD, lpReserved: Pointer, lpClass: LPWSTR, + lpcbName: var DWORD, lpReserved: pointer, lpClass: LPWSTR, lpcbClass: PDWORD, lpftLastWriteTime: PFileTime): int32{. stdcall, dynlib: "advapi32", importc: "RegEnumKeyExW".} proc RegEnumValue*(key: HKEY, dwIndex: DWORD, lpValueName: cstring, - lpcbValueName: var DWORD, lpReserved: Pointer, + lpcbValueName: var DWORD, lpReserved: pointer, lpType: PDWORD, lpData: PByte, lpcbData: PDWORD): int32{. stdcall, dynlib: "advapi32", importc: "RegEnumValueA".} proc RegEnumValueA*(key: HKEY, dwIndex: DWORD, lpValueName: cstring, - lpcbValueName: var DWORD, lpReserved: Pointer, + lpcbValueName: var DWORD, lpReserved: pointer, lpType: PDWORD, lpData: PByte, lpcbData: PDWORD): int32{. stdcall, dynlib: "advapi32", importc: "RegEnumValueA".} proc RegEnumValueW*(key: HKEY, dwIndex: DWORD, lpValueName: cstring, - lpcbValueName: var DWORD, lpReserved: Pointer, + lpcbValueName: var DWORD, lpReserved: pointer, lpType: PDWORD, lpData: PByte, lpcbData: PDWORD): int32{. stdcall, dynlib: "advapi32", importc: "RegEnumValueW".} proc RegGetKeySecurity*(key: HKEY, SecurityInformation: SECURITY_INFORMATION, @@ -22324,10 +22324,10 @@ proc ScrollConsoleScreenBufferW*(hConsoleOutput: THandle, lpFill: var TCharInfo): WINBOOL{.stdcall, dynlib: "kernel32", importc: "ScrollConsoleScreenBufferW".} proc ScrollWindow*(wnd: HWND, XAmount: int32, YAmount: int32, rect: LPRECT, - lpClipRect: lpRECT): WINBOOL{.stdcall, dynlib: "user32", + lpClipRect: LPRECT): WINBOOL{.stdcall, dynlib: "user32", importc: "ScrollWindow".} -proc ScrollWindowEx*(wnd: HWND, dx: int32, dy: int32, prcScroll: lpRECT, - prcClip: lpRECT, hrgnUpdate: HRGN, prcUpdate: LPRECT, +proc ScrollWindowEx*(wnd: HWND, dx: int32, dy: int32, prcScroll: LPRECT, + prcClip: LPRECT, hrgnUpdate: HRGN, prcUpdate: LPRECT, flags: WINUINT): int32{.stdcall, dynlib: "user32", importc: "ScrollWindowEx".} #function ScrollDC(DC: HDC; DX, DY: Integer; var Scroll, Clip: TRect; Rgn: HRGN; Update: PRect): WINBOOL; stdcall; external 'user32' name 'ScrollDC'; @@ -22344,7 +22344,7 @@ proc SendMessageTimeoutA*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM, proc SendMessageTimeoutW*(wnd: HWND, Msg: WINUINT, wp: WPARAM, lp: LPARAM, fuFlags, uTimeout: WINUINT, lpdwResult: var DWORD): LRESULT{. stdcall, dynlib: "user32", importc: "SendMessageTimeoutW".} - #function SetAclInformation(var pAcl: TACL; pAclInformation: Pointer; nAclInformationLength: DWORD; dwAclInformationClass: TAclInformationClass): WINBOOL; stdcall; external 'advapi32' name 'SetAclInformation'; + #function SetAclInformation(var pAcl: TACL; pAclInformation: pointer; nAclInformationLength: DWORD; dwAclInformationClass: TAclInformationClass): WINBOOL; stdcall; external 'advapi32' name 'SetAclInformation'; #function SetColorAdjustment(DC: HDC; const p2: TColorAdjustment): WINBOOL; stdcall; external 'gdi32' name 'SetColorAdjustment'; proc SetCommConfig*(hCommDev: THandle, lpCC: TCommConfig, dwSize: DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "SetCommConfig".} @@ -22359,9 +22359,9 @@ proc SetConsoleCursorInfo*(hConsoleOutput: THandle, proc SetDIBColorTable*(DC: HDC, p2, p3: WINUINT, RGBQuadSTructs: pointer): WINUINT{. stdcall, dynlib: "gdi32", importc: "SetDIBColorTable".} proc SetDIBits*(DC: HDC, Bitmap: HBITMAP, StartScan, NumScans: WINUINT, - Bits: Pointer, BitsInfo: var TBitmapInfo, Usage: WINUINT): int{. + Bits: pointer, BitsInfo: var TBitmapInfo, Usage: WINUINT): int{. stdcall, dynlib: "gdi32", importc: "SetDIBits".} - #function SetDIBitsToDevice(DC: HDC; DestX, DestY: Integer; Width, Height: DWORD; SrcX, SrcY: Integer; nStartScan, NumScans: WINUINT; Bits: Pointer; var BitsInfo: TBitmapInfo; Usage: WINUINT): Integer; stdcall; external 'gdi32' name 'SetDIBitsToDevice'; + #function SetDIBitsToDevice(DC: HDC; DestX, DestY: Integer; Width, Height: DWORD; SrcX, SrcY: Integer; nStartScan, NumScans: WINUINT; Bits: pointer; var BitsInfo: TBitmapInfo; Usage: WINUINT): Integer; stdcall; external 'gdi32' name 'SetDIBitsToDevice'; proc SetEnhMetaFileBits*(para1: WINUINT, para2: pointer): HENHMETAFILE{.stdcall, dynlib: "gdi32", importc: "SetEnhMetaFileBits".} proc SetFileTime*(hFile: HANDLE, lpCreationTime: var FILETIME, @@ -22378,7 +22378,7 @@ proc SetMenuItemInfoA*(p1: HMENU, p2: WINUINT, p3: WINBOOL, p4: TMenuItemInfoA): proc SetMetaFileBitsEx*(p1: WINUINT, p2: cstring): HMETAFILE{.stdcall, dynlib: "gdi32", importc: "SetMetaFileBitsEx".} proc SetNamedPipeHandleState*(hNamedPipe: THandle, lpMode: var DWORD, - lpMaxCollectionCount, lpCollectDataTimeout: Pointer): WINBOOL{.stdcall, + lpMaxCollectionCount, lpCollectDataTimeout: pointer): WINBOOL{.stdcall, dynlib: "kernel32", importc: "SetNamedPipeHandleState".} proc SetPaletteEntries*(Palette: HPALETTE, StartIndex, NumEntries: WINUINT, PaletteEntries: pointer): WINUINT{.stdcall, @@ -22405,7 +22405,7 @@ proc SetUserObjectSecurity*(hObj: THandle, pSIRequested: var DWORD, dynlib: "user32", importc: "SetUserObjectSecurity".} proc SetWaitableTimer*(hTimer: THandle, lpDueTime: var TLargeInteger, lPeriod: int32, pfnCompletionRoutine: TFNTimerAPCRoutine, - lpArgToCompletionRoutine: Pointer, fResume: WINBOOL): WINBOOL{. + lpArgToCompletionRoutine: pointer, fResume: WINBOOL): WINBOOL{. stdcall, dynlib: "kernel32", importc: "SetWaitableTimer".} proc SetWinMetaFileBits*(p1: WINUINT, p2: cstring, p3: HDC, p4: TMetaFilePict): HENHMETAFILE{. stdcall, dynlib: "gdi32", importc: "SetWinMetaFileBits".} @@ -22415,7 +22415,7 @@ proc StartDoc*(DC: HDC, p2: TDocInfo): int{.stdcall, dynlib: "gdi32", proc StartDocA*(DC: HDC, p2: TDocInfoA): int{.stdcall, dynlib: "gdi32", importc: "StartDocA".} #function StartDocW(DC: HDC; const p2: TDocInfoW): Integer; stdcall; external 'gdi32' name 'StartDocW'; - #function StretchDIBits(DC: HDC; DestX, DestY, DestWidth, DestHegiht, SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bits: Pointer; var BitsInfo: TBitmapInfo; Usage: WINUINT; Rop: DWORD): Integer; stdcall; external 'gdi32' name 'StretchDIBits'; + #function StretchDIBits(DC: HDC; DestX, DestY, DestWidth, DestHegiht, SrcX, SrcY, SrcWidth, SrcHeight: Integer; Bits: pointer; var BitsInfo: TBitmapInfo; Usage: WINUINT; Rop: DWORD): Integer; stdcall; external 'gdi32' name 'StretchDIBits'; proc SubtractRect*(lprcDst: var TRect, lprcSrc1, lprcSrc2: TRect): WINBOOL{. stdcall, dynlib: "user32", importc: "SubtractRect".} proc SystemTimeToFileTime*(lpSystemTime: TSystemTime, lpFileTime: var TFileTime): WINBOOL{. @@ -22446,8 +22446,8 @@ proc TrackMouseEvent*(lpEventTrack: PTrackMouseEvent): WINBOOL{.stdcall, proc TrackPopupMenu*(menu: HMENU, uFlags: WINUINT, x: int32, y: int32, nReserved: int32, wnd: HWND, prcRect: PRect): WINBOOL{. stdcall, dynlib: "user32", importc: "TrackPopupMenu".} -proc TransactNamedPipe*(hNamedPipe: THandle, lpInBuffer: Pointer, - nInBufferSize: DWORD, lpOutBuffer: Pointer, +proc TransactNamedPipe*(hNamedPipe: THandle, lpInBuffer: pointer, + nInBufferSize: DWORD, lpOutBuffer: pointer, nOutBufferSize: DWORD, lpBytesRead: var DWORD, lpOverlapped: POverlapped): WINBOOL{.stdcall, dynlib: "kernel32", importc: "TransactNamedPipe".} @@ -22464,8 +22464,8 @@ proc TranslateMDISysAccel*(hWndClient: HWND, lpMsg: TMsg): WINBOOL{.stdcall, dynlib: "user32", importc: "TranslateMDISysAccel".} proc TranslateMessage*(lpMsg: TMsg): WINBOOL{.stdcall, dynlib: "user32", importc: "TranslateMessage".} - #function TransparentDIBits(DC: HDC; p2, p3, p4, p5: Integer; const p6: Pointer; const p7: PBitmapInfo; p8: WINUINT; p9, p10, p11, p12: Integer; p13: WINUINT): WINBOOL;stdcall; external 'gdi32' name 'TransparentDIBits'; -proc UnhandledExceptionFilter*(ExceptionInfo: TExceptionPointers): int32{. + #function TransparentDIBits(DC: HDC; p2, p3, p4, p5: Integer; const p6: pointer; const p7: PBitmapInfo; p8: WINUINT; p9, p10, p11, p12: Integer; p13: WINUINT): WINBOOL;stdcall; external 'gdi32' name 'TransparentDIBits'; +proc UnhandledExceptionFilter*(ExceptionInfo: TExceptionpointers): int32{. stdcall, dynlib: "kernel32", importc: "UnhandledExceptionFilter".} proc UnionRect*(lprcDst: var TRect, lprcSrc1, lprcSrc2: TRect): WINBOOL{. stdcall, dynlib: "user32", importc: "UnionRect".} @@ -22499,19 +22499,19 @@ proc VerInstallFileW*(uFlags: DWORD, szSrcFileName, szDestFileName, szSrcDir, szDestDir, szCurDir, szTmpFile: LPWSTR, lpuTmpFileLen: var WINUINT): DWORD{.stdcall, dynlib: "version", importc: "VerInstallFileW".} -proc VerQueryValue*(pBlock: Pointer, lpSubBlock: cstring, - lplpBuffer: var Pointer, puLen: var WINUINT): WINBOOL{.stdcall, +proc VerQueryValue*(pBlock: pointer, lpSubBlock: cstring, + lplpBuffer: var pointer, puLen: var WINUINT): WINBOOL{.stdcall, dynlib: "version", importc: "VerQueryValueA".} -proc VerQueryValueA*(pBlock: Pointer, lpSubBlock: LPCSTR, - lplpBuffer: var Pointer, puLen: var WINUINT): WINBOOL{. +proc VerQueryValueA*(pBlock: pointer, lpSubBlock: LPCSTR, + lplpBuffer: var pointer, puLen: var WINUINT): WINBOOL{. stdcall, dynlib: "version", importc: "VerQueryValueA".} -proc VerQueryValueW*(pBlock: Pointer, lpSubBlock: LPWSTR, - lplpBuffer: var Pointer, puLen: var WINUINT): WINBOOL{. +proc VerQueryValueW*(pBlock: pointer, lpSubBlock: LPWSTR, + lplpBuffer: var pointer, puLen: var WINUINT): WINBOOL{. stdcall, dynlib: "version", importc: "VerQueryValueW".} -proc VirtualQuery*(lpAddress: Pointer, lpBuffer: var TMemoryBasicInformation, +proc VirtualQuery*(lpAddress: pointer, lpBuffer: var TMemoryBasicInformation, dwLength: DWORD): DWORD{.stdcall, dynlib: "kernel32", importc: "VirtualQuery".} -proc VirtualQueryEx*(hProcess: THandle, lpAddress: Pointer, +proc VirtualQueryEx*(hProcess: THandle, lpAddress: pointer, lpBuffer: var TMemoryBasicInformation, dwLength: DWORD): DWORD{. stdcall, dynlib: "kernel32", importc: "VirtualQueryEx".} proc WaitCommEvent*(hFile: THandle, lpEvtMask: var DWORD, @@ -22528,7 +22528,7 @@ proc wglSetLayerPaletteEntries*(p1: HDC, p2, p3, p4: int, pcr: pointer): int{. stdcall, dynlib: "opengl32", importc: "wglSetLayerPaletteEntries".} #function wglSwapMultipleBuffers(p1: WINUINT; const p2: PWGLSwap): DWORD;stdcall; external 'opengl32' name 'wglSwapMultipleBuffers'; #function WinSubmitCertificate(var lpCertificate: TWinCertificate): WINBOOL;stdcall; external 'imaghlp' name 'WinSubmitCertificate'; - #function WinVerifyTrust(wnd: HWND; const ActionID: TGUID; ActionData: Pointer): Longint;stdcall; external 'imaghlp' name 'WinVerifyTrust'; + #function WinVerifyTrust(wnd: HWND; const ActionID: TGUID; ActionData: pointer): Longint;stdcall; external 'imaghlp' name 'WinVerifyTrust'; proc WNetAddConnection2*(lpNetResource: var TNetResource, lpPassword, lpUserName: cstring, dwFlags: DWORD): DWORD{. stdcall, dynlib: "mpr", importc: "WNetAddConnection2A".} @@ -22553,13 +22553,13 @@ proc WNetDisconnectDialog1*(lpConnDlgStruct: var TDiscDlgStruct): DWORD{. proc WNetDisconnectDialog1A*(lpConnDlgStruct: var TDiscDlgStructA): DWORD{. stdcall, dynlib: "mpr", importc: "WNetDisconnectDialog1A".} #function WNetDisconnectDialog1W(var lpConnDlgStruct: TDiscDlgStructW): DWORD; stdcall; external 'mpr' name 'WNetDisconnectDialog1W'; -proc WNetEnumResource*(hEnum: THandle, lpcCount: var DWORD, lpBuffer: Pointer, +proc WNetEnumResource*(hEnum: THandle, lpcCount: var DWORD, lpBuffer: pointer, lpBufferSize: var DWORD): DWORD{.stdcall, dynlib: "mpr", importc: "WNetEnumResourceA".} -proc WNetEnumResourceA*(hEnum: THandle, lpcCount: var DWORD, lpBuffer: Pointer, +proc WNetEnumResourceA*(hEnum: THandle, lpcCount: var DWORD, lpBuffer: pointer, lpBufferSize: var DWORD): DWORD{.stdcall, dynlib: "mpr", importc: "WNetEnumResourceA".} -proc WNetEnumResourceW*(hEnum: THandle, lpcCount: var DWORD, lpBuffer: Pointer, +proc WNetEnumResourceW*(hEnum: THandle, lpcCount: var DWORD, lpBuffer: pointer, lpBufferSize: var DWORD): DWORD{.stdcall, dynlib: "mpr", importc: "WNetEnumResourceW".} proc WNetGetConnection*(lpLocalName: cstring, lpRemoteName: cstring, @@ -22601,21 +22601,21 @@ proc WNetGetProviderNameA*(dwNetType: DWORD, lpProviderName: LPCSTR, proc WNetGetProviderNameW*(dwNetType: DWORD, lpProviderName: LPWSTR, lpBufferSize: var DWORD): DWORD{.stdcall, dynlib: "mpr", importc: "WNetGetProviderNameW".} -proc WNetGetResourceParent*(lpNetResource: PNetResource, lpBuffer: Pointer, +proc WNetGetResourceParent*(lpNetResource: PNetResource, lpBuffer: pointer, cbBuffer: var DWORD): DWORD{.stdcall, dynlib: "mpr", importc: "WNetGetResourceParentA".} -proc WNetGetResourceParentA*(lpNetResource: PNetResourceA, lpBuffer: Pointer, +proc WNetGetResourceParentA*(lpNetResource: PNetResourceA, lpBuffer: pointer, cbBuffer: var DWORD): DWORD{.stdcall, dynlib: "mpr", importc: "WNetGetResourceParentA".} - #function WNetGetResourceParentW(lpNetResource: PNetResourceW; lpBuffer: Pointer; var cbBuffer: DWORD): DWORD;stdcall; external 'mpr' name 'WNetGetResourceParentW'; + #function WNetGetResourceParentW(lpNetResource: PNetResourceW; lpBuffer: pointer; var cbBuffer: DWORD): DWORD;stdcall; external 'mpr' name 'WNetGetResourceParentW'; proc WNetGetUniversalName*(lpLocalPath: cstring, dwInfoLevel: DWORD, - lpBuffer: Pointer, lpBufferSize: var DWORD): DWORD{. + lpBuffer: pointer, lpBufferSize: var DWORD): DWORD{. stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameA".} proc WNetGetUniversalNameA*(lpLocalPath: LPCSTR, dwInfoLevel: DWORD, - lpBuffer: Pointer, lpBufferSize: var DWORD): DWORD{. + lpBuffer: pointer, lpBufferSize: var DWORD): DWORD{. stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameA".} proc WNetGetUniversalNameW*(lpLocalPath: LPWSTR, dwInfoLevel: DWORD, - lpBuffer: Pointer, lpBufferSize: var DWORD): DWORD{. + lpBuffer: pointer, lpBufferSize: var DWORD): DWORD{. stdcall, dynlib: "mpr", importc: "WNetGetUniversalNameW".} proc WNetGetUser*(lpName: cstring, lpUserName: cstring, lpnLength: var DWORD): DWORD{. stdcall, dynlib: "mpr", importc: "WNetGetUserA".} @@ -22641,13 +22641,13 @@ proc WNetUseConnectionA*(hwndOwner: HWND, lpNetResource: var TNetResourceA, lpResult: var DWORD): DWORD{.stdcall, dynlib: "mpr", importc: "WNetUseConnectionA".} #function WNetUseConnectionW(hwndOwner: HWND; var lpNetResource: TNetResourceW; lpUserID: LPWSTR; lpPassword: LPWSTR; dwFlags: DWORD; lpAccessName: LPWSTR; var lpBufferSize: DWORD; var lpResult: DWORD): DWORD; stdcall; external 'mpr' name 'WNetUseConnectionW'; -proc WriteConsole*(hConsoleOutput: THandle, lpBuffer: Pointer, +proc WriteConsole*(hConsoleOutput: THandle, lpBuffer: pointer, nNumberOfCharsToWrite: DWORD, - lpNumberOfCharsWritten: var DWORD, lpReserved: Pointer): WINBOOL{. + lpNumberOfCharsWritten: var DWORD, lpReserved: pointer): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteConsoleA".} -proc WriteConsoleA*(hConsoleOutput: THandle, lpBuffer: Pointer, +proc WriteConsoleA*(hConsoleOutput: THandle, lpBuffer: pointer, nNumberOfCharsToWrite: DWORD, - lpNumberOfCharsWritten: var DWORD, lpReserved: Pointer): WINBOOL{. + lpNumberOfCharsWritten: var DWORD, lpReserved: pointer): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteConsoleA".} proc WriteConsoleInput*(hConsoleInput: THandle, lpBuffer: TInputRecord, nLength: DWORD, lpNumberOfEventsWritten: var DWORD): WINBOOL{. @@ -22658,15 +22658,15 @@ proc WriteConsoleInputA*(hConsoleInput: THandle, lpBuffer: TInputRecord, proc WriteConsoleInputW*(hConsoleInput: THandle, lpBuffer: TInputRecord, nLength: DWORD, lpNumberOfEventsWritten: var DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteConsoleInputW".} -proc WriteConsoleOutput*(hConsoleOutput: THandle, lpBuffer: Pointer, +proc WriteConsoleOutput*(hConsoleOutput: THandle, lpBuffer: pointer, dwBufferSize, dwBufferCoord: TCoord, lpWriteRegion: var TSmallRect): WINBOOL{.stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputA".} -proc WriteConsoleOutputA*(hConsoleOutput: THandle, lpBuffer: Pointer, +proc WriteConsoleOutputA*(hConsoleOutput: THandle, lpBuffer: pointer, dwBufferSize, dwBufferCoord: TCoord, lpWriteRegion: var TSmallRect): WINBOOL{.stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputA".} -proc WriteConsoleOutputAttribute*(hConsoleOutput: THandle, lpAttribute: Pointer, +proc WriteConsoleOutputAttribute*(hConsoleOutput: THandle, lpAttribute: pointer, nLength: DWORD, dwWriteCoord: TCoord, lpNumberOfAttrsWritten: var DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputAttribute".} @@ -22682,18 +22682,18 @@ proc WriteConsoleOutputCharacterW*(hConsoleOutput: THandle, lpCharacter: LPWSTR, nLength: DWORD, dwWriteCoord: TCoord, lpNumberOfCharsWritten: var DWORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputCharacterW".} -proc WriteConsoleOutputW*(hConsoleOutput: THandle, lpBuffer: Pointer, +proc WriteConsoleOutputW*(hConsoleOutput: THandle, lpBuffer: pointer, dwBufferSize, dwBufferCoord: TCoord, lpWriteRegion: var TSmallRect): WINBOOL{.stdcall, dynlib: "kernel32", importc: "WriteConsoleOutputW".} -proc WriteConsoleW*(hConsoleOutput: THandle, lpBuffer: Pointer, +proc WriteConsoleW*(hConsoleOutput: THandle, lpBuffer: pointer, nNumberOfCharsToWrite: DWORD, - lpNumberOfCharsWritten: var DWORD, lpReserved: Pointer): WINBOOL{. + lpNumberOfCharsWritten: var DWORD, lpReserved: pointer): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteConsoleW".} proc WriteFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: var DWORD, lpOverlapped: POverlapped): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteFile".} -proc WriteFileEx*(hFile: THandle, lpBuffer: Pointer, +proc WriteFileEx*(hFile: THandle, lpBuffer: pointer, nNumberOfBytesToWrite: DWORD, lpOverlapped: TOverlapped, lpCompletionRoutine: FARPROC): WINBOOL{.stdcall, dynlib: "kernel32", importc: "WriteFileEx".} @@ -22707,8 +22707,8 @@ proc WritePrivateProfileStructW*(lpszSection, lpszKey: LPCWSTR, proc WritePrivateProfileStruct*(lpszSection, lpszKey: LPCTSTR, lpStruct: LPVOID, uSizeStruct: WINUINT, szFile: LPCTSTR): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WritePrivateProfileStructA".} -proc WriteProcessMemory*(hProcess: THandle, lpBaseAddress: Pointer, - lpBuffer: Pointer, nSize: DWORD, +proc WriteProcessMemory*(hProcess: THandle, lpBaseAddress: pointer, + lpBuffer: pointer, nSize: DWORD, lpNumberOfBytesWritten: var DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "WriteProcessMemory".} proc SHFileOperation*(para1: var SHFILEOPSTRUCT): int32{.stdcall, @@ -22821,7 +22821,7 @@ proc INDEXTOSTATEIMAGEMASK*(i: int32): int32 = result = i shl 12'i32 proc MAKEINTATOM*(i: int32): LPTSTR = - result = cast[LPTSTR](cast[ULONG_PTR](ToU16(i))) + result = cast[LPTSTR](cast[ULONG_PTR](toU16(i))) proc MAKELANGID*(p, s: int32): int32 = # return type might be wrong @@ -22849,10 +22849,10 @@ proc MAKEROP4*(fore, back: int32): DWORD = proc MAKEWPARAM*(L, h: int32): WPARAM = result = WPARAM(MAKELONG(L, h)) -proc GET_X_LPARAM*(lp: Windows.LParam): int32 = +proc GET_X_LPARAM*(lp: windows.LParam): int32 = result = LOWORD(lp.int32) -proc GET_Y_LPARAM*(lp: Windows.LParam): int32 = +proc GET_Y_LPARAM*(lp: windows.LParam): int32 = result = HIWORD(lp.int32) proc UNICODE_NULL*(): WCHAR = @@ -23229,10 +23229,10 @@ proc set_fAckReq(a: var DDEUP, fAckReq: int16) = a.flag0 = a.flag0 or ((fAckReq shl bp_DDEUP_fAckReq) and bm_DDEUP_fAckReq) proc CreateWindowA(lpClassName: LPCSTR, lpWindowName: LPCSTR, dwStyle: DWORD, - X: int32, Y: int32, nWidth: int32, nHeight: int32, + X, Y, nWidth, nHeight: int32, hWndParent: HWND, menu: HMENU, hInstance: HINST, lpParam: LPVOID): HWND = - result = CreateWindowExA(0, lpClassName, lpWindowName, dwStyle, x, y, nWidth, + result = CreateWindowExA(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, menu, hInstance, lpParam) proc CreateDialogA(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND, @@ -23259,7 +23259,7 @@ proc CreateWindowW(lpClassName: LPCWSTR, lpWindowName: LPCWSTR, dwStyle: DWORD, X: int32, Y: int32, nWidth: int32, nHeight: int32, hWndParent: HWND, menu: HMENU, hInstance: HINST, lpParam: LPVOID): HWND = - result = CreateWindowExW(0, lpClassName, lpWindowName, dwStyle, x, y, nWidth, + result = CreateWindowExW(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, menu, hInstance, lpParam) proc CreateDialogW(hInstance: HINST, lpName: LPCWSTR, hWndParent: HWND, @@ -23285,7 +23285,7 @@ when defined(winUnicode): X: int32, Y: int32, nWidth: int32, nHeight: int32, hWndParent: HWND, menu: HMENU, hInstance: HINST, lpParam: LPVOID): HWND = - result = CreateWindowEx(0, lpClassName, lpWindowName, dwStyle, x, y, nWidth, + result = CreateWindowEx(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam) proc CreateDialog(hInstance: HINST, lpName: LPCWSTR, hWndParent: HWND, @@ -23311,7 +23311,7 @@ else: X: int32, Y: int32, nWidth: int32, nHeight: int32, hWndParent: HWND, menu: HMENU, hInstance: HINST, lpParam: LPVOID): HWND = - result = CreateWindowEx(0, lpClassName, lpWindowName, dwStyle, x, y, nWidth, + result = CreateWindowEx(0, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, menu, hInstance, lpParam) proc CreateDialog(hInstance: HINST, lpTemplateName: LPCSTR, hWndParent: HWND, @@ -23334,24 +23334,24 @@ else: result = DialogBoxIndirectParam(hInstance, hDialogTemplate, hWndParent, lpDialogFunc, 0) -proc GlobalAllocPtr(flags, cb: DWord): Pointer = +proc GlobalAllocPtr(flags, cb: DWord): pointer = result = GlobalLock(GlobalAlloc(flags, cb)) -proc GlobalFreePtr(lp: Pointer): Pointer = - result = cast[Pointer](GlobalFree(cast[HWND](GlobalUnlockPtr(lp)))) +proc GlobalFreePtr(lp: pointer): pointer = + result = cast[pointer](GlobalFree(cast[HWND](GlobalUnlockPtr(lp)))) -proc GlobalUnlockPtr(lp: pointer): Pointer = +proc GlobalUnlockPtr(lp: pointer): pointer = discard GlobalUnlock(GlobalHandle(lp)) result = lp -proc GlobalLockPtr(lp: pointer): Pointer = +proc GlobalLockPtr(lp: pointer): pointer = result = GlobalLock(GlobalHandle(lp)) -proc GlobalReAllocPtr(lp: Pointer, cbNew, flags: DWord): Pointer = +proc GlobalReAllocPtr(lp: pointer, cbNew, flags: DWord): pointer = result = GlobalLock(GlobalReAlloc(cast[HWND](GlobalUnlockPtr(lp)), cbNew, flags)) -proc GlobalPtrHandle(lp: pointer): Pointer = - result = cast[Pointer](GlobalHandle(lp)) +proc GlobalPtrHandle(lp: pointer): pointer = + result = cast[pointer](GlobalHandle(lp)) proc ImageList_AddIcon(himl: HIMAGELIST, hicon: HICON): int32 = result = ImageList_ReplaceIcon(himl, -1, hicon) @@ -23502,7 +23502,7 @@ proc ListView_GetCountPerPage(hwndLV: HWND): LRESULT = proc ListView_GetEditControl(hwndLV: HWND): LRESULT = result = SendMessage(hwndLV, LVM_GETEDITCONTROL, 0, 0) -proc ListView_GetImageList(wnd: HWND, iImageList: wINT): LRESULT = +proc ListView_GetImageList(wnd: HWND, iImageList: WINT): LRESULT = result = SendMessage(wnd, LVM_GETIMAGELIST, WPARAM(iImageList), 0) proc ListView_GetISearchString(hwndLV: HWND, lpsz: LPTSTR): LRESULT = @@ -23702,7 +23702,7 @@ proc TreeView_SetItem(wnd: HWND, item: var TV_ITEM): LRESULT = result = SendMessage(wnd, TVM_SETITEM, 0, cast[LPARAM](addr(item))) proc TreeView_EditLabel(wnd: HWND, hitem: HTREEITEM): LRESULT = - Result = SendMessage(wnd, TVM_EDITLABEL, 0, cast[LPARAM](hitem)) + result = SendMessage(wnd, TVM_EDITLABEL, 0, cast[LPARAM](hitem)) proc TreeView_GetEditControl(wnd: HWND): LRESULT = result = SendMessage(wnd, TVM_GETEDITCONTROL, 0, 0) @@ -23854,10 +23854,10 @@ proc CommDlg_OpenSave_SetDefExt(hdlg: HWND, pszext: LPSTR): LRESULT = proc InternalGetLargestConsoleWindowSize(hConsoleOutput: HANDLE): DWord{. stdcall, dynlib: "kernel32", importc: "GetLargestConsoleWindowSize".} proc GetLargestConsoleWindowSize(hConsoleOutput: HANDLE): COORD = - var res: dword + var res: DWORD res = InternalGetLargestConsoleWindowSize(hConsoleOutput) - result.y = toU16(res and 0x0000ffff) # XXX: correct? - result.x = toU16(res shr 16) + result.Y = toU16(res and 0x0000ffff) # XXX: correct? + result.X = toU16(res shr 16) proc Succeeded(Status: HRESULT): WINBOOL = result = (Status and 0x80000000).WinBool diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 09696b67f..cc633d90b 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -8,7 +8,7 @@ # ## This module implements a small wrapper for some needed Win API procedures, -## so that the Nimrod compiler does not depend on the huge Windows module. +## so that the Nim compiler does not depend on the huge Windows module. const useWinUnicode* = not defined(useWinAnsi) @@ -104,11 +104,11 @@ proc closeHandle*(hObject: THandle): WINBOOL {.stdcall, dynlib: "kernel32", importc: "CloseHandle".} proc readFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32, - lpNumberOfBytesRead: var int32, lpOverlapped: pointer): WINBOOL{. + lpNumberOfBytesRead: ptr int32, lpOverlapped: pointer): WINBOOL{. stdcall, dynlib: "kernel32", importc: "ReadFile".} proc writeFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32, - lpNumberOfBytesWritten: var int32, + lpNumberOfBytesWritten: ptr int32, lpOverlapped: pointer): WINBOOL{. stdcall, dynlib: "kernel32", importc: "WriteFile".} @@ -199,14 +199,14 @@ else: importc: "GetCurrentDirectoryA", dynlib: "kernel32", stdcall.} proc setCurrentDirectoryA*(lpPathName: cstring): int32 {. importc: "SetCurrentDirectoryA", dynlib: "kernel32", stdcall.} - proc createDirectoryA*(pathName: cstring, security: Pointer=nil): int32 {. + proc createDirectoryA*(pathName: cstring, security: pointer=nil): int32 {. importc: "CreateDirectoryA", dynlib: "kernel32", stdcall.} proc removeDirectoryA*(lpPathName: cstring): int32 {. importc: "RemoveDirectoryA", dynlib: "kernel32", stdcall.} proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {. stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".} - proc getModuleFileNameA*(handle: THandle, buf: CString, size: int32): int32 {. + proc getModuleFileNameA*(handle: THandle, buf: cstring, size: int32): int32 {. importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.} when useWinUnicode: @@ -304,7 +304,7 @@ else: dwFileAttributes: int32): WINBOOL {. stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".} - proc copyFileA*(lpExistingFileName, lpNewFileName: CString, + proc copyFileA*(lpExistingFileName, lpNewFileName: cstring, bFailIfExists: cint): cint {. importc: "CopyFileA", stdcall, dynlib: "kernel32".} @@ -363,48 +363,50 @@ const proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.} type - TSocketHandle* = distinct int + SocketHandle* = distinct int + +{.deprecated: [TSocketHandle: SocketHandle].} type - TWSAData* {.pure, final, importc: "WSADATA", header: "Winsock2.h".} = object + WSAData* {.importc: "WSADATA", header: "Winsock2.h".} = object wVersion, wHighVersion: int16 szDescription: array[0..WSADESCRIPTION_LEN, char] szSystemStatus: array[0..WSASYS_STATUS_LEN, char] iMaxSockets, iMaxUdpDg: int16 lpVendorInfo: cstring - TSockAddr* {.pure, final, importc: "SOCKADDR", header: "Winsock2.h".} = object + SockAddr* {.importc: "SOCKADDR", header: "Winsock2.h".} = object sa_family*: int16 # unsigned sa_data: array[0..13, char] - TInAddr* {.pure, final, importc: "IN_ADDR", header: "Winsock2.h".} = object + InAddr* {.importc: "IN_ADDR", header: "Winsock2.h".} = object s_addr*: int32 # IP address - Tsockaddr_in* {.pure, final, importc: "SOCKADDR_IN", + Sockaddr_in* {.importc: "SOCKADDR_IN", header: "Winsock2.h".} = object sin_family*: int16 sin_port*: int16 # unsigned - sin_addr*: TInAddr + sin_addr*: InAddr sin_zero*: array[0..7, char] - Tin6_addr* {.pure, final, importc: "IN6_ADDR", header: "Winsock2.h".} = object + In6_addr* {.importc: "IN6_ADDR", header: "Winsock2.h".} = object bytes*: array[0..15, char] - Tsockaddr_in6* {.pure, final, importc: "SOCKADDR_IN6", + Sockaddr_in6* {.importc: "SOCKADDR_IN6", header: "Winsock2.h".} = object sin6_family*: int16 sin6_port*: int16 # unsigned sin6_flowinfo*: int32 # unsigned - sin6_addr*: Tin6_addr + sin6_addr*: In6_addr sin6_scope_id*: int32 # unsigned - Tsockaddr_in6_old* {.pure, final.} = object + Sockaddr_in6_old* = object sin6_family*: int16 sin6_port*: int16 # unsigned sin6_flowinfo*: int32 # unsigned - sin6_addr*: Tin6_addr + sin6_addr*: In6_addr - TServent* {.pure, final.} = object + Servent* = object s_name*: cstring s_aliases*: cstringArray when defined(cpu64): @@ -414,35 +416,42 @@ type s_port*: int16 s_proto*: cstring - Thostent* {.pure, final.} = object + Hostent* = object h_name*: cstring h_aliases*: cstringArray h_addrtype*: int16 h_length*: int16 h_addr_list*: cstringArray - TFdSet* {.pure, final.} = object + TFdSet* = object fd_count*: cint # unsigned - fd_array*: array[0..FD_SETSIZE-1, TSocketHandle] + fd_array*: array[0..FD_SETSIZE-1, SocketHandle] - TTimeval* {.pure, final.} = object + Timeval* = object tv_sec*, tv_usec*: int32 - TAddrInfo* {.pure, final.} = object + AddrInfo* = object ai_flags*: cint ## Input flags. ai_family*: cint ## Address family of socket. ai_socktype*: cint ## Socket type. ai_protocol*: cint ## Protocol of socket. ai_addrlen*: int ## Length of socket address. ai_canonname*: cstring ## Canonical name of service location. - ai_addr*: ptr TSockAddr ## Socket address of socket. - ai_next*: ptr TAddrInfo ## Pointer to next in list. + ai_addr*: ptr SockAddr ## Socket address of socket. + ai_next*: ptr AddrInfo ## Pointer to next in list. + + SockLen* = cuint + +{.deprecated: [TSockaddr_in: Sockaddr_in, TAddrinfo: AddrInfo, + TSockAddr: SockAddr, TSockLen: SockLen, TTimeval: Timeval, + TWSADATA: WSADATA, Thostent: Hostent, TServent: Servent, + TInAddr: InAddr, Tin6_addr: In6_addr, Tsockaddr_in6: Sockaddr_in6, + Tsockaddr_in6_old: Sockaddr_in6_old].} - TSockLen* = cuint var SOMAXCONN* {.importc, header: "Winsock2.h".}: cint - INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle + INVALID_SOCKET* {.importc, header: "Winsock2.h".}: SocketHandle SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen() @@ -458,94 +467,94 @@ var SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse SO_ERROR* {.importc, header: "Winsock2.h".}: cint -proc `==`*(x, y: TSocketHandle): bool {.borrow.} +proc `==`*(x, y: SocketHandle): bool {.borrow.} -proc getservbyname*(name, proto: cstring): ptr TServent {. +proc getservbyname*(name, proto: cstring): ptr Servent {. stdcall, importc: "getservbyname", dynlib: ws2dll.} -proc getservbyport*(port: cint, proto: cstring): ptr TServent {. +proc getservbyport*(port: cint, proto: cstring): ptr Servent {. stdcall, importc: "getservbyport", dynlib: ws2dll.} -proc gethostbyaddr*(ip: ptr TInAddr, len: cuint, theType: cint): ptr Thostent {. +proc gethostbyaddr*(ip: ptr InAddr, len: cuint, theType: cint): ptr Hostent {. stdcall, importc: "gethostbyaddr", dynlib: ws2dll.} -proc gethostbyname*(name: cstring): ptr Thostent {. +proc gethostbyname*(name: cstring): ptr Hostent {. stdcall, importc: "gethostbyname", dynlib: ws2dll.} -proc socket*(af, typ, protocol: cint): TSocketHandle {. +proc socket*(af, typ, protocol: cint): SocketHandle {. stdcall, importc: "socket", dynlib: ws2dll.} -proc closesocket*(s: TSocketHandle): cint {. +proc closesocket*(s: SocketHandle): cint {. stdcall, importc: "closesocket", dynlib: ws2dll.} -proc accept*(s: TSocketHandle, a: ptr TSockAddr, addrlen: ptr TSockLen): TSocketHandle {. +proc accept*(s: SocketHandle, a: ptr SockAddr, addrlen: ptr SockLen): SocketHandle {. stdcall, importc: "accept", dynlib: ws2dll.} -proc bindSocket*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {. +proc bindSocket*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {. stdcall, importc: "bind", dynlib: ws2dll.} -proc connect*(s: TSocketHandle, name: ptr TSockAddr, namelen: TSockLen): cint {. +proc connect*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {. stdcall, importc: "connect", dynlib: ws2dll.} -proc getsockname*(s: TSocketHandle, name: ptr TSockAddr, - namelen: ptr TSockLen): cint {. +proc getsockname*(s: SocketHandle, name: ptr SockAddr, + namelen: ptr SockLen): cint {. stdcall, importc: "getsockname", dynlib: ws2dll.} -proc getsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer, - optlen: ptr TSockLen): cint {. +proc getsockopt*(s: SocketHandle, level, optname: cint, optval: pointer, + optlen: ptr SockLen): cint {. stdcall, importc: "getsockopt", dynlib: ws2dll.} -proc setsockopt*(s: TSocketHandle, level, optname: cint, optval: pointer, - optlen: TSockLen): cint {. +proc setsockopt*(s: SocketHandle, level, optname: cint, optval: pointer, + optlen: SockLen): cint {. stdcall, importc: "setsockopt", dynlib: ws2dll.} -proc listen*(s: TSocketHandle, backlog: cint): cint {. +proc listen*(s: SocketHandle, backlog: cint): cint {. stdcall, importc: "listen", dynlib: ws2dll.} -proc recv*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {. +proc recv*(s: SocketHandle, buf: pointer, len, flags: cint): cint {. stdcall, importc: "recv", dynlib: ws2dll.} -proc recvfrom*(s: TSocketHandle, buf: cstring, len, flags: cint, - fromm: ptr TSockAddr, fromlen: ptr TSockLen): cint {. +proc recvfrom*(s: SocketHandle, buf: cstring, len, flags: cint, + fromm: ptr SockAddr, fromlen: ptr SockLen): cint {. stdcall, importc: "recvfrom", dynlib: ws2dll.} proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet, - timeout: ptr TTimeval): cint {. + timeout: ptr Timeval): cint {. stdcall, importc: "select", dynlib: ws2dll.} -proc send*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {. +proc send*(s: SocketHandle, buf: pointer, len, flags: cint): cint {. stdcall, importc: "send", dynlib: ws2dll.} -proc sendto*(s: TSocketHandle, buf: pointer, len, flags: cint, - to: ptr TSockAddr, tolen: TSockLen): cint {. +proc sendto*(s: SocketHandle, buf: pointer, len, flags: cint, + to: ptr SockAddr, tolen: SockLen): cint {. stdcall, importc: "sendto", dynlib: ws2dll.} -proc shutdown*(s: TSocketHandle, how: cint): cint {. +proc shutdown*(s: SocketHandle, how: cint): cint {. stdcall, importc: "shutdown", dynlib: ws2dll.} -proc getnameinfo*(a1: ptr TSockAddr, a2: TSockLen, - a3: cstring, a4: TSockLen, a5: cstring, - a6: TSockLen, a7: cint): cint {. +proc getnameinfo*(a1: ptr SockAddr, a2: SockLen, + a3: cstring, a4: SockLen, a5: cstring, + a6: SockLen, a7: cint): cint {. stdcall, importc: "getnameinfo", dynlib: ws2dll.} proc inet_addr*(cp: cstring): int32 {. stdcall, importc: "inet_addr", dynlib: ws2dll.} -proc WSAFDIsSet(s: TSocketHandle, FDSet: var TFdSet): bool {. +proc WSAFDIsSet(s: SocketHandle, set: var TFdSet): bool {. stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll, noSideEffect.} -proc FD_ISSET*(Socket: TSocketHandle, FDSet: var TFdSet): cint = - result = if WSAFDIsSet(Socket, FDSet): 1'i32 else: 0'i32 +proc FD_ISSET*(socket: SocketHandle, set: var TFdSet): cint = + result = if WSAFDIsSet(socket, set): 1'i32 else: 0'i32 -proc FD_SET*(Socket: TSocketHandle, FDSet: var TFdSet) = - if FDSet.fd_count < FD_SETSIZE: - FDSet.fd_array[int(FDSet.fd_count)] = Socket - inc(FDSet.fd_count) +proc fdSet*(socket: SocketHandle, s: var TFdSet) = + if s.fd_count < FD_SETSIZE: + s.fd_array[int(s.fd_count)] = socket + inc(s.fd_count) -proc FD_ZERO*(FDSet: var TFdSet) = - FDSet.fd_count = 0 +proc FD_ZERO*(s: var TFdSet) = + s.fd_count = 0 -proc wsaStartup*(wVersionRequired: int16, WSData: ptr TWSAData): cint {. +proc wsaStartup*(wVersionRequired: int16, WSData: ptr WSAData): cint {. stdcall, importc: "WSAStartup", dynlib: ws2dll.} -proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo, - res: var ptr TAddrInfo): cint {. +proc getaddrinfo*(nodename, servname: cstring, hints: ptr AddrInfo, + res: var ptr AddrInfo): cint {. stdcall, importc: "getaddrinfo", dynlib: ws2dll.} -proc freeaddrinfo*(ai: ptr TAddrInfo) {. +proc freeaddrinfo*(ai: ptr AddrInfo) {. stdcall, importc: "freeaddrinfo", dynlib: ws2dll.} -proc inet_ntoa*(i: TInAddr): cstring {. +proc inet_ntoa*(i: InAddr): cstring {. stdcall, importc, dynlib: ws2dll.} const @@ -564,12 +573,14 @@ proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray, const GENERIC_READ* = 0x80000000'i32 + GENERIC_WRITE* = 0x40000000'i32 GENERIC_ALL* = 0x10000000'i32 FILE_SHARE_READ* = 1'i32 FILE_SHARE_DELETE* = 4'i32 FILE_SHARE_WRITE* = 2'i32 CREATE_ALWAYS* = 2'i32 + CREATE_NEW* = 1'i32 OPEN_EXISTING* = 3'i32 FILE_BEGIN* = 0'i32 INVALID_SET_FILE_POINTER* = -1'i32 @@ -586,6 +597,7 @@ const # Error Constants const ERROR_ACCESS_DENIED* = 5 + ERROR_HANDLE_EOF* = 38 when useWinUnicode: proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD, @@ -640,11 +652,11 @@ proc unmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall, type TOVERLAPPED* {.pure, inheritable.} = object - Internal*: PULONG - InternalHigh*: PULONG - Offset*: DWORD - OffsetHigh*: DWORD - hEvent*: THANDLE + internal*: PULONG + internalHigh*: PULONG + offset*: DWORD + offsetHigh*: DWORD + hEvent*: THandle POVERLAPPED* = ptr TOVERLAPPED @@ -659,6 +671,7 @@ type const ERROR_IO_PENDING* = 997 # a.k.a WSA_IO_PENDING + FILE_FLAG_OVERLAPPED* = 1073741824 WSAECONNABORTED* = 10053 WSAECONNRESET* = 10054 WSAEDISCON* = 10101 @@ -666,17 +679,21 @@ const WSAETIMEDOUT* = 10060 ERROR_NETNAME_DELETED* = 64 -proc CreateIoCompletionPort*(FileHandle: THANDLE, ExistingCompletionPort: THANDLE, +proc createIoCompletionPort*(FileHandle: THandle, ExistingCompletionPort: THandle, CompletionKey: DWORD, - NumberOfConcurrentThreads: DWORD): THANDLE{.stdcall, + NumberOfConcurrentThreads: DWORD): THandle{.stdcall, dynlib: "kernel32", importc: "CreateIoCompletionPort".} -proc GetQueuedCompletionStatus*(CompletionPort: THandle, +proc getQueuedCompletionStatus*(CompletionPort: THandle, lpNumberOfBytesTransferred: PDWORD, lpCompletionKey: PULONG, - lpOverlapped: ptr POverlapped, + lpOverlapped: ptr POVERLAPPED, dwMilliseconds: DWORD): WINBOOL{.stdcall, dynlib: "kernel32", importc: "GetQueuedCompletionStatus".} +proc getOverlappedResult*(hFile: THandle, lpOverlapped: TOVERLAPPED, + lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{. + stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".} + const IOC_OUT* = 0x40000000 IOC_IN* = 0x80000000 @@ -697,9 +714,9 @@ var WSAID_GETACCEPTEXSOCKADDRS*: TGUID = TGUID(D1: 0xb5367df2'i32, D2: 0xcbac'i16, D3: 0x11cf, D4: [ 0x95'i8, 0xca'i8, 0x00'i8, 0x80'i8, 0x5f'i8, 0x48'i8, 0xa1'i8, 0x92'i8]) -proc WSAIoctl*(s: TSocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer, +proc WSAIoctl*(s: SocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer, cbInBuffer: DWORD, lpvOutBuffer: pointer, cbOutBuffer: DWORD, - lpcbBytesReturned: PDword, lpOverlapped: POVERLAPPED, + lpcbBytesReturned: PDWORD, lpOverlapped: POVERLAPPED, lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint {.stdcall, importc: "WSAIoctl", dynlib: "Ws2_32.dll".} @@ -708,17 +725,17 @@ type len*: ULONG buf*: cstring -proc WSARecv*(s: TSocketHandle, buf: ptr TWSABuf, bufCount: DWORD, - bytesReceived, flags: PDWORD, lpOverlapped: POverlapped, +proc WSARecv*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD, + bytesReceived, flags: PDWORD, lpOverlapped: POVERLAPPED, completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {. stdcall, importc: "WSARecv", dynlib: "Ws2_32.dll".} -proc WSASend*(s: TSocketHandle, buf: ptr TWSABuf, bufCount: DWORD, - bytesSent: PDWord, flags: DWORD, lpOverlapped: POverlapped, +proc WSASend*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD, + bytesSent: PDWORD, flags: DWORD, lpOverlapped: POVERLAPPED, completionProc: POVERLAPPED_COMPLETION_ROUTINE): cint {. stdcall, importc: "WSASend", dynlib: "Ws2_32.dll".} -proc get_osfhandle*(fd:TFileHandle): THandle {. +proc get_osfhandle*(fd:FileHandle): THandle {. importc: "_get_osfhandle", header:"<io.h>".} proc getSystemTimes*(lpIdleTime, lpKernelTime, diff --git a/lib/wrappers/expat.nim b/lib/wrappers/expat.nim index 3400dfdf7..a3d888201 100644 --- a/lib/wrappers/expat.nim +++ b/lib/wrappers/expat.nim @@ -77,8 +77,8 @@ type type TContent*{.pure, final.} = object - typ*: TContent_Type - quant*: TContent_Quant + typ*: TContentType + quant*: TContentQuant name*: cstring numchildren*: cint children*: ptr TContent @@ -93,7 +93,7 @@ type TElementDeclHandler* = proc (userData: pointer, name: cstring, model: ptr TContent){.cdecl.} -proc SetElementDeclHandler*(parser: PParser, eldecl: TElementDeclHandler){. +proc setElementDeclHandler*(parser: PParser, eldecl: TElementDeclHandler){. cdecl, importc: "XML_SetElementDeclHandler", dynlib: expatDll.} # The Attlist declaration handler is called for *each* attribute. So # a single Attlist declaration with multiple attributes declared will @@ -106,10 +106,10 @@ proc SetElementDeclHandler*(parser: PParser, eldecl: TElementDeclHandler){. type TAttlistDeclHandler* = proc (userData: pointer, elname: cstring, - attname: cstring, att_type: cstring, + attname: cstring, attType: cstring, dflt: cstring, isrequired: cint){.cdecl.} -proc SetAttlistDeclHandler*(parser: PParser, attdecl: TAttlistDeclHandler){. +proc setAttlistDeclHandler*(parser: PParser, attdecl: TAttlistDeclHandler){. cdecl, importc: "XML_SetAttlistDeclHandler", dynlib: expatDll.} # The XML declaration handler is called for *both* XML declarations # and text declarations. The way to distinguish is that the version @@ -124,20 +124,20 @@ type TXmlDeclHandler* = proc (userData: pointer, version: cstring, encoding: cstring, standalone: cint){.cdecl.} -proc SetXmlDeclHandler*(parser: PParser, xmldecl: TXmlDeclHandler){.cdecl, +proc setXmlDeclHandler*(parser: PParser, xmldecl: TXmlDeclHandler){.cdecl, importc: "XML_SetXmlDeclHandler", dynlib: expatDll.} type TMemory_Handling_Suite*{.pure, final.} = object - malloc_fcn*: proc (size: int): pointer{.cdecl.} - realloc_fcn*: proc (p: pointer, size: int): pointer{.cdecl.} - free_fcn*: proc (p: pointer){.cdecl.} + mallocFcn*: proc (size: int): pointer{.cdecl.} + reallocFcn*: proc (p: pointer, size: int): pointer{.cdecl.} + freeFcn*: proc (p: pointer){.cdecl.} # Constructs a new parser; encoding is the encoding specified by the # external protocol or NULL if there is none specified. # -proc ParserCreate*(encoding: cstring): PParser{.cdecl, +proc parserCreate*(encoding: cstring): PParser{.cdecl, importc: "XML_ParserCreate", dynlib: expatDll.} # Constructs a new parser and namespace processor. Element type # names and attribute names that belong to a namespace will be @@ -151,7 +151,7 @@ proc ParserCreate*(encoding: cstring): PParser{.cdecl, # triplets (see XML_SetReturnNSTriplet). # -proc ParserCreateNS*(encoding: cstring, namespaceSeparator: char): PParser{. +proc parserCreateNS*(encoding: cstring, namespaceSeparator: char): PParser{. cdecl, importc: "XML_ParserCreateNS", dynlib: expatDll.} # Constructs a new parser using the memory management suite referred to # by memsuite. If memsuite is NULL, then use the standard library memory @@ -163,7 +163,7 @@ proc ParserCreateNS*(encoding: cstring, namespaceSeparator: char): PParser{. # the given suite. # -proc ParserCreate_MM*(encoding: cstring, memsuite: ptr TMemory_Handling_Suite, +proc parserCreateMM*(encoding: cstring, memsuite: ptr TMemoryHandlingSuite, namespaceSeparator: cstring): PParser{.cdecl, importc: "XML_ParserCreate_MM", dynlib: expatDll.} # Prepare a parser object to be re-used. This is particularly @@ -176,7 +176,7 @@ proc ParserCreate_MM*(encoding: cstring, memsuite: ptr TMemory_Handling_Suite, # Added in Expat 1.95.3. # -proc ParserReset*(parser: PParser, encoding: cstring): Bool{.cdecl, +proc parserReset*(parser: PParser, encoding: cstring): bool{.cdecl, importc: "XML_ParserReset", dynlib: expatDll.} # atts is array of name/value pairs, terminated by 0; # names and values are 0 terminated. @@ -230,7 +230,7 @@ type type TStartDoctypeDeclHandler* = proc (userData: pointer, doctypeName: cstring, sysid: cstring, pubid: cstring, - has_internal_subset: cint){.cdecl.} + hasInternalSubset: cint){.cdecl.} # This is called for the start of the DOCTYPE declaration when the # closing > is encountered, but after processing any external @@ -261,12 +261,12 @@ type type TEntityDeclHandler* = proc (userData: pointer, entityName: cstring, - is_parameter_entity: cint, value: cstring, - value_length: cint, base: cstring, + isParameterEntity: cint, value: cstring, + valueLength: cint, base: cstring, systemId: cstring, publicId: cstring, notationName: cstring){.cdecl.} -proc SetEntityDeclHandler*(parser: PParser, handler: TEntityDeclHandler){.cdecl, +proc setEntityDeclHandler*(parser: PParser, handler: TEntityDeclHandler){.cdecl, importc: "XML_SetEntityDeclHandler", dynlib: expatDll.} # OBSOLETE -- OBSOLETE -- OBSOLETE # This handler has been superceded by the EntityDeclHandler above. @@ -372,7 +372,7 @@ type type TSkippedEntityHandler* = proc (userData: pointer, entityName: cstring, - is_parameter_entity: cint){.cdecl.} + isParameterEntity: cint){.cdecl.} # This structure is filled in by the XML_UnknownEncodingHandler to # provide information to the parser about encodings that are unknown @@ -455,27 +455,27 @@ type TUnknownEncodingHandler* = proc (encodingHandlerData: pointer, name: cstring, info: ptr TEncoding): cint{.cdecl.} -proc SetElementHandler*(parser: PParser, start: TStartElementHandler, +proc setElementHandler*(parser: PParser, start: TStartElementHandler, endHandler: TEndElementHandler){.cdecl, importc: "XML_SetElementHandler", dynlib: expatDll.} -proc SetStartElementHandler*(parser: PParser, handler: TStartElementHandler){. +proc setStartElementHandler*(parser: PParser, handler: TStartElementHandler){. cdecl, importc: "XML_SetStartElementHandler", dynlib: expatDll.} -proc SetEndElementHandler*(parser: PParser, handler: TEndElementHandler){.cdecl, +proc setEndElementHandler*(parser: PParser, handler: TEndElementHandler){.cdecl, importc: "XML_SetEndElementHandler", dynlib: expatDll.} -proc SetCharacterDataHandler*(parser: PParser, handler: TCharacterDataHandler){. +proc setCharacterDataHandler*(parser: PParser, handler: TCharacterDataHandler){. cdecl, importc: "XML_SetCharacterDataHandler", dynlib: expatDll.} -proc SetProcessingInstructionHandler*(parser: PParser, +proc setProcessingInstructionHandler*(parser: PParser, handler: TProcessingInstructionHandler){. cdecl, importc: "XML_SetProcessingInstructionHandler", dynlib: expatDll.} -proc SetCommentHandler*(parser: PParser, handler: TCommentHandler){.cdecl, +proc setCommentHandler*(parser: PParser, handler: TCommentHandler){.cdecl, importc: "XML_SetCommentHandler", dynlib: expatDll.} -proc SetCdataSectionHandler*(parser: PParser, start: TStartCdataSectionHandler, +proc setCdataSectionHandler*(parser: PParser, start: TStartCdataSectionHandler, endHandler: TEndCdataSectionHandler){.cdecl, importc: "XML_SetCdataSectionHandler", dynlib: expatDll.} -proc SetStartCdataSectionHandler*(parser: PParser, +proc setStartCdataSectionHandler*(parser: PParser, start: TStartCdataSectionHandler){.cdecl, importc: "XML_SetStartCdataSectionHandler", dynlib: expatDll.} -proc SetEndCdataSectionHandler*(parser: PParser, +proc setEndCdataSectionHandler*(parser: PParser, endHandler: TEndCdataSectionHandler){.cdecl, importc: "XML_SetEndCdataSectionHandler", dynlib: expatDll.} # This sets the default handler and also inhibits expansion of @@ -483,42 +483,42 @@ proc SetEndCdataSectionHandler*(parser: PParser, # default handler, or to the skipped entity handler, if one is set. # -proc SetDefaultHandler*(parser: PParser, handler: TDefaultHandler){.cdecl, +proc setDefaultHandler*(parser: PParser, handler: TDefaultHandler){.cdecl, importc: "XML_SetDefaultHandler", dynlib: expatDll.} # This sets the default handler but does not inhibit expansion of # internal entities. The entity reference will not be passed to the # default handler. # -proc SetDefaultHandlerExpand*(parser: PParser, handler: TDefaultHandler){.cdecl, +proc setDefaultHandlerExpand*(parser: PParser, handler: TDefaultHandler){.cdecl, importc: "XML_SetDefaultHandlerExpand", dynlib: expatDll.} -proc SetDoctypeDeclHandler*(parser: PParser, start: TStartDoctypeDeclHandler, +proc setDoctypeDeclHandler*(parser: PParser, start: TStartDoctypeDeclHandler, endHandler: TEndDoctypeDeclHandler){.cdecl, importc: "XML_SetDoctypeDeclHandler", dynlib: expatDll.} -proc SetStartDoctypeDeclHandler*(parser: PParser, +proc setStartDoctypeDeclHandler*(parser: PParser, start: TStartDoctypeDeclHandler){.cdecl, importc: "XML_SetStartDoctypeDeclHandler", dynlib: expatDll.} -proc SetEndDoctypeDeclHandler*(parser: PParser, +proc setEndDoctypeDeclHandler*(parser: PParser, endHandler: TEndDoctypeDeclHandler){.cdecl, importc: "XML_SetEndDoctypeDeclHandler", dynlib: expatDll.} -proc SetUnparsedEntityDeclHandler*(parser: PParser, +proc setUnparsedEntityDeclHandler*(parser: PParser, handler: TUnparsedEntityDeclHandler){.cdecl, importc: "XML_SetUnparsedEntityDeclHandler", dynlib: expatDll.} -proc SetNotationDeclHandler*(parser: PParser, handler: TNotationDeclHandler){. +proc setNotationDeclHandler*(parser: PParser, handler: TNotationDeclHandler){. cdecl, importc: "XML_SetNotationDeclHandler", dynlib: expatDll.} -proc SetNamespaceDeclHandler*(parser: PParser, +proc setNamespaceDeclHandler*(parser: PParser, start: TStartNamespaceDeclHandler, endHandler: TEndNamespaceDeclHandler){.cdecl, importc: "XML_SetNamespaceDeclHandler", dynlib: expatDll.} -proc SetStartNamespaceDeclHandler*(parser: PParser, +proc setStartNamespaceDeclHandler*(parser: PParser, start: TStartNamespaceDeclHandler){.cdecl, importc: "XML_SetStartNamespaceDeclHandler", dynlib: expatDll.} -proc SetEndNamespaceDeclHandler*(parser: PParser, +proc setEndNamespaceDeclHandler*(parser: PParser, endHandler: TEndNamespaceDeclHandler){.cdecl, importc: "XML_SetEndNamespaceDeclHandler", dynlib: expatDll.} -proc SetNotStandaloneHandler*(parser: PParser, handler: TNotStandaloneHandler){. +proc setNotStandaloneHandler*(parser: PParser, handler: TNotStandaloneHandler){. cdecl, importc: "XML_SetNotStandaloneHandler", dynlib: expatDll.} -proc SetExternalEntityRefHandler*(parser: PParser, +proc setExternalEntityRefHandler*(parser: PParser, handler: TExternalEntityRefHandler){.cdecl, importc: "XML_SetExternalEntityRefHandler", dynlib: expatDll.} # If a non-NULL value for arg is specified here, then it will be @@ -526,11 +526,11 @@ proc SetExternalEntityRefHandler*(parser: PParser, # instead of the parser object. # -proc SetExternalEntityRefHandlerArg*(parser: PParser, arg: pointer){.cdecl, +proc setExternalEntityRefHandlerArg*(parser: PParser, arg: pointer){.cdecl, importc: "XML_SetExternalEntityRefHandlerArg", dynlib: expatDll.} -proc SetSkippedEntityHandler*(parser: PParser, handler: TSkippedEntityHandler){. +proc setSkippedEntityHandler*(parser: PParser, handler: TSkippedEntityHandler){. cdecl, importc: "XML_SetSkippedEntityHandler", dynlib: expatDll.} -proc SetUnknownEncodingHandler*(parser: PParser, +proc setUnknownEncodingHandler*(parser: PParser, handler: TUnknownEncodingHandler, encodingHandlerData: pointer){.cdecl, importc: "XML_SetUnknownEncodingHandler", dynlib: expatDll.} @@ -539,7 +539,7 @@ proc SetUnknownEncodingHandler*(parser: PParser, # corresponding markup to be passed to the default handler. # -proc DefaultCurrent*(parser: PParser){.cdecl, importc: "XML_DefaultCurrent", +proc defaultCurrent*(parser: PParser){.cdecl, importc: "XML_DefaultCurrent", dynlib: expatDll.} # If do_nst is non-zero, and namespace processing is in effect, and # a name has a prefix (i.e. an explicit namespace qualifier) then @@ -555,15 +555,15 @@ proc DefaultCurrent*(parser: PParser){.cdecl, importc: "XML_DefaultCurrent", # XML_ParseBuffer has no effect. # -proc SetReturnNSTriplet*(parser: PParser, do_nst: cint){.cdecl, +proc setReturnNSTriplet*(parser: PParser, doNst: cint){.cdecl, importc: "XML_SetReturnNSTriplet", dynlib: expatDll.} # This value is passed as the userData argument to callbacks. -proc SetUserData*(parser: PParser, userData: pointer){.cdecl, +proc setUserData*(parser: PParser, userData: pointer){.cdecl, importc: "XML_SetUserData", dynlib: expatDll.} # Returns the last value set by XML_SetUserData or NULL. -template GetUserData*(parser: expr): expr = +template getUserData*(parser: expr): expr = (cast[ptr pointer]((parser))[] ) # This is equivalent to supplying an encoding argument to @@ -573,14 +573,14 @@ template GetUserData*(parser: expr): expr = # has no effect and returns XML_STATUS_ERROR. # -proc SetEncoding*(parser: PParser, encoding: cstring): TStatus{.cdecl, +proc setEncoding*(parser: PParser, encoding: cstring): TStatus{.cdecl, importc: "XML_SetEncoding", dynlib: expatDll.} # If this function is called, then the parser will be passed as the # first argument to callbacks instead of userData. The userData will # still be accessible using XML_GetUserData. # -proc UseParserAsHandlerArg*(parser: PParser){.cdecl, +proc useParserAsHandlerArg*(parser: PParser){.cdecl, importc: "XML_UseParserAsHandlerArg", dynlib: expatDll.} # If useDTD == XML_TRUE is passed to this function, then the parser # will assume that there is an external subset, even if none is @@ -601,7 +601,7 @@ proc UseParserAsHandlerArg*(parser: PParser){.cdecl, # XML_ERROR_FEATURE_REQUIRES_XML_DTD. # -proc UseForeignDTD*(parser: PParser, useDTD: Bool): TError{.cdecl, +proc useForeignDTD*(parser: PParser, useDTD: bool): TError{.cdecl, importc: "XML_UseForeignDTD", dynlib: expatDll.} # Sets the base to be used for resolving relative URIs in system # identifiers in declarations. Resolving relative identifiers is @@ -612,9 +612,9 @@ proc UseForeignDTD*(parser: PParser, useDTD: Bool): TError{.cdecl, # XML_STATUS_OK otherwise. # -proc SetBase*(parser: PParser, base: cstring): TStatus{.cdecl, +proc setBase*(parser: PParser, base: cstring): TStatus{.cdecl, importc: "XML_SetBase", dynlib: expatDll.} -proc GetBase*(parser: PParser): cstring{.cdecl, importc: "XML_GetBase", +proc getBase*(parser: PParser): cstring{.cdecl, importc: "XML_GetBase", dynlib: expatDll.} # Returns the number of the attribute/value pairs passed in last call # to the XML_StartElementHandler that were specified in the start-tag @@ -623,7 +623,7 @@ proc GetBase*(parser: PParser): cstring{.cdecl, importc: "XML_GetBase", # XML_StartElementHandler. # -proc GetSpecifiedAttributeCount*(parser: PParser): cint{.cdecl, +proc getSpecifiedAttributeCount*(parser: PParser): cint{.cdecl, importc: "XML_GetSpecifiedAttributeCount", dynlib: expatDll.} # Returns the index of the ID attribute passed in the last call to # XML_StartElementHandler, or -1 if there is no ID attribute. Each @@ -631,7 +631,7 @@ proc GetSpecifiedAttributeCount*(parser: PParser): cint{.cdecl, # index into the atts array passed to the XML_StartElementHandler. # -proc GetIdAttributeIndex*(parser: PParser): cint{.cdecl, +proc getIdAttributeIndex*(parser: PParser): cint{.cdecl, importc: "XML_GetIdAttributeIndex", dynlib: expatDll.} # Parses some input. Returns XML_STATUS_ERROR if a fatal error is # detected. The last call to XML_Parse must have isFinal true; len @@ -643,11 +643,11 @@ proc GetIdAttributeIndex*(parser: PParser): cint{.cdecl, # values. # -proc Parse*(parser: PParser, s: cstring, len: cint, isFinal: cint): TStatus{. +proc parse*(parser: PParser, s: cstring, len: cint, isFinal: cint): TStatus{. cdecl, importc: "XML_Parse", dynlib: expatDll.} -proc GetBuffer*(parser: PParser, len: cint): pointer{.cdecl, +proc getBuffer*(parser: PParser, len: cint): pointer{.cdecl, importc: "XML_GetBuffer", dynlib: expatDll.} -proc ParseBuffer*(parser: PParser, len: cint, isFinal: cint): TStatus{.cdecl, +proc parseBuffer*(parser: PParser, len: cint, isFinal: cint): TStatus{.cdecl, importc: "XML_ParseBuffer", dynlib: expatDll.} # Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return. # Must be called from within a call-back handler, except when aborting @@ -681,7 +681,7 @@ proc ParseBuffer*(parser: PParser, len: cint, isFinal: cint): TStatus{.cdecl, # When suspended, parsing can be resumed by calling XML_ResumeParser(). # -proc StopParser*(parser: PParser, resumable: Bool): TStatus{.cdecl, +proc stopParser*(parser: PParser, resumable: bool): TStatus{.cdecl, importc: "XML_StopParser", dynlib: expatDll.} # Resumes parsing after it has been suspended with XML_StopParser(). # Must not be called from within a handler call-back. Returns same @@ -696,14 +696,14 @@ proc StopParser*(parser: PParser, resumable: Bool): TStatus{.cdecl, # application to call XML_ResumeParser() on it at the appropriate moment. # -proc ResumeParser*(parser: PParser): TStatus{.cdecl, +proc resumeParser*(parser: PParser): TStatus{.cdecl, importc: "XML_ResumeParser", dynlib: expatDll.} type TParsing* = enum INITIALIZED, PARSING, FINISHED, SUSPENDED TParsingStatus*{.pure, final.} = object parsing*: TParsing - finalBuffer*: Bool + finalBuffer*: bool # Returns status of parser with respect to being initialized, parsing, @@ -712,7 +712,7 @@ type # XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED # -proc GetParsingStatus*(parser: PParser, status: ptr TParsingStatus){.cdecl, +proc getParsingStatus*(parser: PParser, status: ptr TParsingStatus){.cdecl, importc: "XML_GetParsingStatus", dynlib: expatDll.} # Creates an XML_Parser object that can parse an external general # entity; context is a '\0'-terminated string specifying the parse @@ -731,7 +731,7 @@ proc GetParsingStatus*(parser: PParser, status: ptr TParsingStatus){.cdecl, # Otherwise returns a new XML_Parser object. # -proc ExternalEntityParserCreate*(parser: PParser, context: cstring, +proc externalEntityParserCreate*(parser: PParser, context: cstring, encoding: cstring): PParser{.cdecl, importc: "XML_ExternalEntityParserCreate", dynlib: expatDll.} type @@ -763,13 +763,13 @@ type # XML_ParseBuffer, then it has no effect and will always return 0. # -proc SetParamEntityParsing*(parser: PParser, parsing: TParamEntityParsing): cint{. +proc setParamEntityParsing*(parser: PParser, parsing: TParamEntityParsing): cint{. cdecl, importc: "XML_SetParamEntityParsing", dynlib: expatDll.} # If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then # XML_GetErrorCode returns information about the error. # -proc GetErrorCode*(parser: PParser): TError{.cdecl, importc: "XML_GetErrorCode", +proc getErrorCode*(parser: PParser): TError{.cdecl, importc: "XML_GetErrorCode", dynlib: expatDll.} # These functions return information about the current parse # location. They may be called from any callback called to report @@ -788,17 +788,17 @@ proc GetErrorCode*(parser: PParser): TError{.cdecl, importc: "XML_GetErrorCode", # parse event, as described above. # -proc GetCurrentLineNumber*(parser: PParser): int{.cdecl, +proc getCurrentLineNumber*(parser: PParser): int{.cdecl, importc: "XML_GetCurrentLineNumber", dynlib: expatDll.} -proc GetCurrentColumnNumber*(parser: PParser): int{.cdecl, +proc getCurrentColumnNumber*(parser: PParser): int{.cdecl, importc: "XML_GetCurrentColumnNumber", dynlib: expatDll.} -proc GetCurrentByteIndex*(parser: PParser): int{.cdecl, +proc getCurrentByteIndex*(parser: PParser): int{.cdecl, importc: "XML_GetCurrentByteIndex", dynlib: expatDll.} # Return the number of bytes in the current event. # Returns 0 if the event is in an internal entity. # -proc GetCurrentByteCount*(parser: PParser): cint{.cdecl, +proc getCurrentByteCount*(parser: PParser): cint{.cdecl, importc: "XML_GetCurrentByteCount", dynlib: expatDll.} # If XML_CONTEXT_BYTES is defined, returns the input buffer, sets # the integer pointed to by offset to the offset within this buffer @@ -811,31 +811,31 @@ proc GetCurrentByteCount*(parser: PParser): cint{.cdecl, # the handler that makes the call. # -proc GetInputContext*(parser: PParser, offset: ptr cint, size: ptr cint): cstring{. +proc getInputContext*(parser: PParser, offset: ptr cint, size: ptr cint): cstring{. cdecl, importc: "XML_GetInputContext", dynlib: expatDll.} # Frees the content model passed to the element declaration handler -proc FreeContentModel*(parser: PParser, model: ptr TContent){.cdecl, +proc freeContentModel*(parser: PParser, model: ptr TContent){.cdecl, importc: "XML_FreeContentModel", dynlib: expatDll.} # Exposing the memory handling functions used in Expat -proc MemMalloc*(parser: PParser, size: int): pointer{.cdecl, +proc memMalloc*(parser: PParser, size: int): pointer{.cdecl, importc: "XML_MemMalloc", dynlib: expatDll.} -proc MemRealloc*(parser: PParser, p: pointer, size: int): pointer{.cdecl, +proc memRealloc*(parser: PParser, p: pointer, size: int): pointer{.cdecl, importc: "XML_MemRealloc", dynlib: expatDll.} -proc MemFree*(parser: PParser, p: pointer){.cdecl, importc: "XML_MemFree", +proc memFree*(parser: PParser, p: pointer){.cdecl, importc: "XML_MemFree", dynlib: expatDll.} # Frees memory used by the parser. -proc ParserFree*(parser: PParser){.cdecl, importc: "XML_ParserFree", +proc parserFree*(parser: PParser){.cdecl, importc: "XML_ParserFree", dynlib: expatDll.} # Returns a string describing the error. -proc ErrorString*(code: TError): cstring{.cdecl, importc: "XML_ErrorString", +proc errorString*(code: TError): cstring{.cdecl, importc: "XML_ErrorString", dynlib: expatDll.} # Return a string containing the version number of this expat -proc ExpatVersion*(): cstring{.cdecl, importc: "XML_ExpatVersion", +proc expatVersion*(): cstring{.cdecl, importc: "XML_ExpatVersion", dynlib: expatDll.} type TExpat_Version*{.pure, final.} = object @@ -848,7 +848,7 @@ type # number information for this version of expat. # -proc ExpatVersionInfo*(): TExpat_Version{.cdecl, +proc expatVersionInfo*(): TExpatVersion{.cdecl, importc: "XML_ExpatVersionInfo", dynlib: expatDll.} # Added in Expat 1.95.5. @@ -863,7 +863,7 @@ type value*: int -proc GetFeatureList*(): ptr TFeature{.cdecl, importc: "XML_GetFeatureList", +proc getFeatureList*(): ptr TFeature{.cdecl, importc: "XML_GetFeatureList", dynlib: expatDll.} # Expat follows the GNU/Linux convention of odd number minor version for # beta/development releases and even number minor version for stable diff --git a/lib/wrappers/iup.nim b/lib/wrappers/iup.nim index 2ee1ca3ee..6695dc5e2 100644 --- a/lib/wrappers/iup.nim +++ b/lib/wrappers/iup.nim @@ -46,321 +46,321 @@ const constIUP_VERSION_DATE* = "2009/07/18" type - Ihandle {.pure.} = object + Ihandle = object PIhandle* = ptr Ihandle Icallback* = proc (arg: PIhandle): cint {.cdecl.} -# pre-definided dialogs -proc FileDlg*: PIhandle {.importc: "IupFileDlg", dynlib: dllname, cdecl.} -proc MessageDlg*: PIhandle {.importc: "IupMessageDlg", dynlib: dllname, cdecl.} -proc ColorDlg*: PIhandle {.importc: "IupColorDlg", dynlib: dllname, cdecl.} -proc FontDlg*: PIhandle {.importc: "IupFontDlg", dynlib: dllname, cdecl.} +# pre-defineded dialogs +proc fileDlg*: PIhandle {.importc: "IupFileDlg", dynlib: dllname, cdecl.} +proc messageDlg*: PIhandle {.importc: "IupMessageDlg", dynlib: dllname, cdecl.} +proc colorDlg*: PIhandle {.importc: "IupColorDlg", dynlib: dllname, cdecl.} +proc fontDlg*: PIhandle {.importc: "IupFontDlg", dynlib: dllname, cdecl.} -proc GetFile*(arq: cstring): cint {. +proc getFile*(arq: cstring): cint {. importc: "IupGetFile", dynlib: dllname, cdecl.} -proc Message*(title, msg: cstring) {. +proc message*(title, msg: cstring) {. importc: "IupMessage", dynlib: dllname, cdecl.} -proc Messagef*(title, format: cstring) {. +proc messagef*(title, format: cstring) {. importc: "IupMessagef", dynlib: dllname, cdecl, varargs.} -proc Alarm*(title, msg, b1, b2, b3: cstring): cint {. +proc alarm*(title, msg, b1, b2, b3: cstring): cint {. importc: "IupAlarm", dynlib: dllname, cdecl.} -proc Scanf*(format: cstring): cint {. +proc scanf*(format: cstring): cint {. importc: "IupScanf", dynlib: dllname, cdecl, varargs.} -proc ListDialog*(theType: cint, title: cstring, size: cint, - list: cstringArray, op, max_col, max_lin: cint, +proc listDialog*(theType: cint, title: cstring, size: cint, + list: cstringArray, op, maxCol, maxLin: cint, marks: ptr cint): cint {. importc: "IupListDialog", dynlib: dllname, cdecl.} -proc GetText*(title, text: cstring): cint {. +proc getText*(title, text: cstring): cint {. importc: "IupGetText", dynlib: dllname, cdecl.} -proc GetColor*(x, y: cint, r, g, b: var byte): cint {. +proc getColor*(x, y: cint, r, g, b: var byte): cint {. importc: "IupGetColor", dynlib: dllname, cdecl.} type - Iparamcb* = proc (dialog: PIhandle, param_index: cint, - user_data: pointer): cint {.cdecl.} + Iparamcb* = proc (dialog: PIhandle, paramIndex: cint, + userData: pointer): cint {.cdecl.} -proc GetParam*(title: cstring, action: Iparamcb, user_data: pointer, +proc getParam*(title: cstring, action: Iparamcb, userData: pointer, format: cstring): cint {. importc: "IupGetParam", cdecl, varargs, dynlib: dllname.} -proc GetParamv*(title: cstring, action: Iparamcb, user_data: pointer, - format: cstring, param_count, param_extra: cint, - param_data: pointer): cint {. +proc getParamv*(title: cstring, action: Iparamcb, userData: pointer, + format: cstring, paramCount, paramExtra: cint, + paramData: pointer): cint {. importc: "IupGetParamv", cdecl, dynlib: dllname.} # Functions -proc Open*(argc: ptr cint, argv: ptr cstringArray): cint {. +proc open*(argc: ptr cint, argv: ptr cstringArray): cint {. importc: "IupOpen", cdecl, dynlib: dllname.} -proc Close*() {.importc: "IupClose", cdecl, dynlib: dllname.} -proc ImageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.} +proc close*() {.importc: "IupClose", cdecl, dynlib: dllname.} +proc imageLibOpen*() {.importc: "IupImageLibOpen", cdecl, dynlib: dllname.} -proc MainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname, +proc mainLoop*(): cint {.importc: "IupMainLoop", cdecl, dynlib: dllname, discardable.} -proc LoopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname, +proc loopStep*(): cint {.importc: "IupLoopStep", cdecl, dynlib: dllname, discardable.} -proc MainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl, +proc mainLoopLevel*(): cint {.importc: "IupMainLoopLevel", cdecl, dynlib: dllname, discardable.} -proc Flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.} -proc ExitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.} - -proc Update*(ih: PIhandle) {.importc: "IupUpdate", cdecl, dynlib: dllname.} -proc UpdateChildren*(ih: PIhandle) {.importc: "IupUpdateChildren", cdecl, dynlib: dllname.} -proc Redraw*(ih: PIhandle, children: cint) {.importc: "IupRedraw", cdecl, dynlib: dllname.} -proc Refresh*(ih: PIhandle) {.importc: "IupRefresh", cdecl, dynlib: dllname.} - -proc MapFont*(iupfont: cstring): cstring {.importc: "IupMapFont", cdecl, dynlib: dllname.} -proc UnMapFont*(driverfont: cstring): cstring {.importc: "IupUnMapFont", cdecl, dynlib: dllname.} -proc Help*(url: cstring): cint {.importc: "IupHelp", cdecl, dynlib: dllname.} -proc Load*(filename: cstring): cstring {.importc: "IupLoad", cdecl, dynlib: dllname.} - -proc IupVersion*(): cstring {.importc: "IupVersion", cdecl, dynlib: dllname.} -proc IupVersionDate*(): cstring {.importc: "IupVersionDate", cdecl, dynlib: dllname.} -proc IupVersionNumber*(): cint {.importc: "IupVersionNumber", cdecl, dynlib: dllname.} -proc SetLanguage*(lng: cstring) {.importc: "IupSetLanguage", cdecl, dynlib: dllname.} -proc GetLanguage*(): cstring {.importc: "IupGetLanguage", cdecl, dynlib: dllname.} - -proc Destroy*(ih: PIhandle) {.importc: "IupDestroy", cdecl, dynlib: dllname.} -proc Detach*(child: PIhandle) {.importc: "IupDetach", cdecl, dynlib: dllname.} -proc Append*(ih, child: PIhandle): PIhandle {. +proc flush*() {.importc: "IupFlush", cdecl, dynlib: dllname.} +proc exitLoop*() {.importc: "IupExitLoop", cdecl, dynlib: dllname.} + +proc update*(ih: PIhandle) {.importc: "IupUpdate", cdecl, dynlib: dllname.} +proc updateChildren*(ih: PIhandle) {.importc: "IupUpdateChildren", cdecl, dynlib: dllname.} +proc redraw*(ih: PIhandle, children: cint) {.importc: "IupRedraw", cdecl, dynlib: dllname.} +proc refresh*(ih: PIhandle) {.importc: "IupRefresh", cdecl, dynlib: dllname.} + +proc mapFont*(iupfont: cstring): cstring {.importc: "IupMapFont", cdecl, dynlib: dllname.} +proc unMapFont*(driverfont: cstring): cstring {.importc: "IupUnMapFont", cdecl, dynlib: dllname.} +proc help*(url: cstring): cint {.importc: "IupHelp", cdecl, dynlib: dllname.} +proc load*(filename: cstring): cstring {.importc: "IupLoad", cdecl, dynlib: dllname.} + +proc iupVersion*(): cstring {.importc: "IupVersion", cdecl, dynlib: dllname.} +proc iupVersionDate*(): cstring {.importc: "IupVersionDate", cdecl, dynlib: dllname.} +proc iupVersionNumber*(): cint {.importc: "IupVersionNumber", cdecl, dynlib: dllname.} +proc setLanguage*(lng: cstring) {.importc: "IupSetLanguage", cdecl, dynlib: dllname.} +proc getLanguage*(): cstring {.importc: "IupGetLanguage", cdecl, dynlib: dllname.} + +proc destroy*(ih: PIhandle) {.importc: "IupDestroy", cdecl, dynlib: dllname.} +proc detach*(child: PIhandle) {.importc: "IupDetach", cdecl, dynlib: dllname.} +proc append*(ih, child: PIhandle): PIhandle {. importc: "IupAppend", cdecl, dynlib: dllname, discardable.} -proc Insert*(ih, ref_child, child: PIhandle): PIhandle {. +proc insert*(ih, refChild, child: PIhandle): PIhandle {. importc: "IupInsert", cdecl, dynlib: dllname, discardable.} -proc GetChild*(ih: PIhandle, pos: cint): PIhandle {. +proc getChild*(ih: PIhandle, pos: cint): PIhandle {. importc: "IupGetChild", cdecl, dynlib: dllname.} -proc GetChildPos*(ih, child: PIhandle): cint {. +proc getChildPos*(ih, child: PIhandle): cint {. importc: "IupGetChildPos", cdecl, dynlib: dllname.} -proc GetChildCount*(ih: PIhandle): cint {. +proc getChildCount*(ih: PIhandle): cint {. importc: "IupGetChildCount", cdecl, dynlib: dllname.} -proc GetNextChild*(ih, child: PIhandle): PIhandle {. +proc getNextChild*(ih, child: PIhandle): PIhandle {. importc: "IupGetNextChild", cdecl, dynlib: dllname.} -proc GetBrother*(ih: PIhandle): PIhandle {. +proc getBrother*(ih: PIhandle): PIhandle {. importc: "IupGetBrother", cdecl, dynlib: dllname.} -proc GetParent*(ih: PIhandle): PIhandle {. +proc getParent*(ih: PIhandle): PIhandle {. importc: "IupGetParent", cdecl, dynlib: dllname.} -proc GetDialog*(ih: PIhandle): PIhandle {. +proc getDialog*(ih: PIhandle): PIhandle {. importc: "IupGetDialog", cdecl, dynlib: dllname.} -proc GetDialogChild*(ih: PIhandle, name: cstring): PIhandle {. +proc getDialogChild*(ih: PIhandle, name: cstring): PIhandle {. importc: "IupGetDialogChild", cdecl, dynlib: dllname.} -proc Reparent*(ih, new_parent: PIhandle): cint {. +proc reparent*(ih, newParent: PIhandle): cint {. importc: "IupReparent", cdecl, dynlib: dllname.} -proc Popup*(ih: PIhandle, x, y: cint): cint {. +proc popup*(ih: PIhandle, x, y: cint): cint {. importc: "IupPopup", cdecl, dynlib: dllname, discardable.} -proc Show*(ih: PIhandle): cint {. +proc show*(ih: PIhandle): cint {. importc: "IupShow", cdecl, dynlib: dllname, discardable.} -proc ShowXY*(ih: PIhandle, x, y: cint): cint {. +proc showXY*(ih: PIhandle, x, y: cint): cint {. importc: "IupShowXY", cdecl, dynlib: dllname, discardable.} -proc Hide*(ih: PIhandle): cint {. +proc hide*(ih: PIhandle): cint {. importc: "IupHide", cdecl, dynlib: dllname, discardable.} -proc Map*(ih: PIhandle): cint {. +proc map*(ih: PIhandle): cint {. importc: "IupMap", cdecl, dynlib: dllname, discardable.} -proc Unmap*(ih: PIhandle) {. +proc unmap*(ih: PIhandle) {. importc: "IupUnmap", cdecl, dynlib: dllname, discardable.} -proc SetAttribute*(ih: PIhandle, name, value: cstring) {. +proc setAttribute*(ih: PIhandle, name, value: cstring) {. importc: "IupSetAttribute", cdecl, dynlib: dllname.} -proc StoreAttribute*(ih: PIhandle, name, value: cstring) {. +proc storeAttribute*(ih: PIhandle, name, value: cstring) {. importc: "IupStoreAttribute", cdecl, dynlib: dllname.} -proc SetAttributes*(ih: PIhandle, str: cstring): PIhandle {. +proc setAttributes*(ih: PIhandle, str: cstring): PIhandle {. importc: "IupSetAttributes", cdecl, dynlib: dllname.} -proc GetAttribute*(ih: PIhandle, name: cstring): cstring {. +proc getAttribute*(ih: PIhandle, name: cstring): cstring {. importc: "IupGetAttribute", cdecl, dynlib: dllname.} -proc GetAttributes*(ih: PIhandle): cstring {. +proc getAttributes*(ih: PIhandle): cstring {. importc: "IupGetAttributes", cdecl, dynlib: dllname.} -proc GetInt*(ih: PIhandle, name: cstring): cint {. +proc getInt*(ih: PIhandle, name: cstring): cint {. importc: "IupGetInt", cdecl, dynlib: dllname.} -proc GetInt2*(ih: PIhandle, name: cstring): cint {. +proc getInt2*(ih: PIhandle, name: cstring): cint {. importc: "IupGetInt2", cdecl, dynlib: dllname.} -proc GetIntInt*(ih: PIhandle, name: cstring, i1, i2: var cint): cint {. +proc getIntInt*(ih: PIhandle, name: cstring, i1, i2: var cint): cint {. importc: "IupGetIntInt", cdecl, dynlib: dllname.} -proc GetFloat*(ih: PIhandle, name: cstring): cfloat {. +proc getFloat*(ih: PIhandle, name: cstring): cfloat {. importc: "IupGetFloat", cdecl, dynlib: dllname.} -proc SetfAttribute*(ih: PIhandle, name, format: cstring) {. +proc setfAttribute*(ih: PIhandle, name, format: cstring) {. importc: "IupSetfAttribute", cdecl, dynlib: dllname, varargs.} -proc GetAllAttributes*(ih: PIhandle, names: cstringArray, n: cint): cint {. +proc getAllAttributes*(ih: PIhandle, names: cstringArray, n: cint): cint {. importc: "IupGetAllAttributes", cdecl, dynlib: dllname.} -proc SetAtt*(handle_name: cstring, ih: PIhandle, name: cstring): PIhandle {. +proc setAtt*(handleName: cstring, ih: PIhandle, name: cstring): PIhandle {. importc: "IupSetAtt", cdecl, dynlib: dllname, varargs, discardable.} -proc SetGlobal*(name, value: cstring) {. +proc setGlobal*(name, value: cstring) {. importc: "IupSetGlobal", cdecl, dynlib: dllname.} -proc StoreGlobal*(name, value: cstring) {. +proc storeGlobal*(name, value: cstring) {. importc: "IupStoreGlobal", cdecl, dynlib: dllname.} -proc GetGlobal*(name: cstring): cstring {. +proc getGlobal*(name: cstring): cstring {. importc: "IupGetGlobal", cdecl, dynlib: dllname.} -proc SetFocus*(ih: PIhandle): PIhandle {. +proc setFocus*(ih: PIhandle): PIhandle {. importc: "IupSetFocus", cdecl, dynlib: dllname.} -proc GetFocus*(): PIhandle {. +proc getFocus*(): PIhandle {. importc: "IupGetFocus", cdecl, dynlib: dllname.} -proc PreviousField*(ih: PIhandle): PIhandle {. +proc previousField*(ih: PIhandle): PIhandle {. importc: "IupPreviousField", cdecl, dynlib: dllname.} -proc NextField*(ih: PIhandle): PIhandle {. +proc nextField*(ih: PIhandle): PIhandle {. importc: "IupNextField", cdecl, dynlib: dllname.} -proc GetCallback*(ih: PIhandle, name: cstring): Icallback {. +proc getCallback*(ih: PIhandle, name: cstring): Icallback {. importc: "IupGetCallback", cdecl, dynlib: dllname.} -proc SetCallback*(ih: PIhandle, name: cstring, func: Icallback): Icallback {. +proc setCallback*(ih: PIhandle, name: cstring, func: Icallback): Icallback {. importc: "IupSetCallback", cdecl, dynlib: dllname, discardable.} -proc SetCallbacks*(ih: PIhandle, name: cstring, func: Icallback): PIhandle {. +proc setCallbacks*(ih: PIhandle, name: cstring, func: Icallback): PIhandle {. importc: "IupSetCallbacks", cdecl, dynlib: dllname, varargs, discardable.} -proc GetFunction*(name: cstring): Icallback {. +proc getFunction*(name: cstring): Icallback {. importc: "IupGetFunction", cdecl, dynlib: dllname.} -proc SetFunction*(name: cstring, func: Icallback): Icallback {. +proc setFunction*(name: cstring, func: Icallback): Icallback {. importc: "IupSetFunction", cdecl, dynlib: dllname, discardable.} -proc GetActionName*(): cstring {. +proc getActionName*(): cstring {. importc: "IupGetActionName", cdecl, dynlib: dllname.} -proc GetHandle*(name: cstring): PIhandle {. +proc getHandle*(name: cstring): PIhandle {. importc: "IupGetHandle", cdecl, dynlib: dllname.} -proc SetHandle*(name: cstring, ih: PIhandle): PIhandle {. +proc setHandle*(name: cstring, ih: PIhandle): PIhandle {. importc: "IupSetHandle", cdecl, dynlib: dllname.} -proc GetAllNames*(names: cstringArray, n: cint): cint {. +proc getAllNames*(names: cstringArray, n: cint): cint {. importc: "IupGetAllNames", cdecl, dynlib: dllname.} -proc GetAllDialogs*(names: cstringArray, n: cint): cint {. +proc getAllDialogs*(names: cstringArray, n: cint): cint {. importc: "IupGetAllDialogs", cdecl, dynlib: dllname.} -proc GetName*(ih: PIhandle): cstring {. +proc getName*(ih: PIhandle): cstring {. importc: "IupGetName", cdecl, dynlib: dllname.} -proc SetAttributeHandle*(ih: PIhandle, name: cstring, ih_named: PIhandle) {. +proc setAttributeHandle*(ih: PIhandle, name: cstring, ihNamed: PIhandle) {. importc: "IupSetAttributeHandle", cdecl, dynlib: dllname.} -proc GetAttributeHandle*(ih: PIhandle, name: cstring): PIhandle {. +proc getAttributeHandle*(ih: PIhandle, name: cstring): PIhandle {. importc: "IupGetAttributeHandle", cdecl, dynlib: dllname.} -proc GetClassName*(ih: PIhandle): cstring {. +proc getClassName*(ih: PIhandle): cstring {. importc: "IupGetClassName", cdecl, dynlib: dllname.} -proc GetClassType*(ih: PIhandle): cstring {. +proc getClassType*(ih: PIhandle): cstring {. importc: "IupGetClassType", cdecl, dynlib: dllname.} -proc GetClassAttributes*(classname: cstring, names: cstringArray, +proc getClassAttributes*(classname: cstring, names: cstringArray, n: cint): cint {. importc: "IupGetClassAttributes", cdecl, dynlib: dllname.} -proc SaveClassAttributes*(ih: PIhandle) {. +proc saveClassAttributes*(ih: PIhandle) {. importc: "IupSaveClassAttributes", cdecl, dynlib: dllname.} -proc SetClassDefaultAttribute*(classname, name, value: cstring) {. +proc setClassDefaultAttribute*(classname, name, value: cstring) {. importc: "IupSetClassDefaultAttribute", cdecl, dynlib: dllname.} -proc Create*(classname: cstring): PIhandle {. +proc create*(classname: cstring): PIhandle {. importc: "IupCreate", cdecl, dynlib: dllname.} -proc Createv*(classname: cstring, params: pointer): PIhandle {. +proc createv*(classname: cstring, params: pointer): PIhandle {. importc: "IupCreatev", cdecl, dynlib: dllname.} -proc Createp*(classname: cstring, first: pointer): PIhandle {. +proc createp*(classname: cstring, first: pointer): PIhandle {. importc: "IupCreatep", cdecl, dynlib: dllname, varargs.} -proc Fill*(): PIhandle {.importc: "IupFill", cdecl, dynlib: dllname.} -proc Radio*(child: PIhandle): PIhandle {. +proc fill*(): PIhandle {.importc: "IupFill", cdecl, dynlib: dllname.} +proc radio*(child: PIhandle): PIhandle {. importc: "IupRadio", cdecl, dynlib: dllname.} -proc Vbox*(child: PIhandle): PIhandle {. +proc vbox*(child: PIhandle): PIhandle {. importc: "IupVbox", cdecl, dynlib: dllname, varargs.} -proc Vboxv*(children: ptr PIhandle): PIhandle {. +proc vboxv*(children: ptr PIhandle): PIhandle {. importc: "IupVboxv", cdecl, dynlib: dllname.} -proc Zbox*(child: PIhandle): PIhandle {. +proc zbox*(child: PIhandle): PIhandle {. importc: "IupZbox", cdecl, dynlib: dllname, varargs.} -proc Zboxv*(children: ptr PIhandle): PIhandle {. +proc zboxv*(children: ptr PIhandle): PIhandle {. importc: "IupZboxv", cdecl, dynlib: dllname.} -proc Hbox*(child: PIhandle): PIhandle {. +proc hbox*(child: PIhandle): PIhandle {. importc: "IupHbox", cdecl, dynlib: dllname, varargs.} -proc Hboxv*(children: ptr PIhandle): PIhandle {. +proc hboxv*(children: ptr PIhandle): PIhandle {. importc: "IupHboxv", cdecl, dynlib: dllname.} -proc Normalizer*(ih_first: PIhandle): PIhandle {. +proc normalizer*(ihFirst: PIhandle): PIhandle {. importc: "IupNormalizer", cdecl, dynlib: dllname, varargs.} -proc Normalizerv*(ih_list: ptr PIhandle): PIhandle {. +proc normalizerv*(ihList: ptr PIhandle): PIhandle {. importc: "IupNormalizerv", cdecl, dynlib: dllname.} -proc Cbox*(child: PIhandle): PIhandle {. +proc cbox*(child: PIhandle): PIhandle {. importc: "IupCbox", cdecl, dynlib: dllname, varargs.} -proc Cboxv*(children: ptr PIhandle): PIhandle {. +proc cboxv*(children: ptr PIhandle): PIhandle {. importc: "IupCboxv", cdecl, dynlib: dllname.} -proc Sbox*(child: PIhandle): PIhandle {. +proc sbox*(child: PIhandle): PIhandle {. importc: "IupSbox", cdecl, dynlib: dllname.} -proc Frame*(child: PIhandle): PIhandle {. +proc frame*(child: PIhandle): PIhandle {. importc: "IupFrame", cdecl, dynlib: dllname.} -proc Image*(width, height: cint, pixmap: pointer): PIhandle {. +proc image*(width, height: cint, pixmap: pointer): PIhandle {. importc: "IupImage", cdecl, dynlib: dllname.} -proc ImageRGB*(width, height: cint, pixmap: pointer): PIhandle {. +proc imageRGB*(width, height: cint, pixmap: pointer): PIhandle {. importc: "IupImageRGB", cdecl, dynlib: dllname.} -proc ImageRGBA*(width, height: cint, pixmap: pointer): PIhandle {. +proc imageRGBA*(width, height: cint, pixmap: pointer): PIhandle {. importc: "IupImageRGBA", cdecl, dynlib: dllname.} -proc Item*(title, action: cstring): PIhandle {. +proc item*(title, action: cstring): PIhandle {. importc: "IupItem", cdecl, dynlib: dllname.} -proc Submenu*(title: cstring, child: PIhandle): PIhandle {. +proc submenu*(title: cstring, child: PIhandle): PIhandle {. importc: "IupSubmenu", cdecl, dynlib: dllname.} -proc Separator*(): PIhandle {. +proc separator*(): PIhandle {. importc: "IupSeparator", cdecl, dynlib: dllname.} -proc Menu*(child: PIhandle): PIhandle {. +proc menu*(child: PIhandle): PIhandle {. importc: "IupMenu", cdecl, dynlib: dllname, varargs.} -proc Menuv*(children: ptr PIhandle): PIhandle {. +proc menuv*(children: ptr PIhandle): PIhandle {. importc: "IupMenuv", cdecl, dynlib: dllname.} -proc Button*(title, action: cstring): PIhandle {. +proc button*(title, action: cstring): PIhandle {. importc: "IupButton", cdecl, dynlib: dllname.} -proc Canvas*(action: cstring): PIhandle {. +proc canvas*(action: cstring): PIhandle {. importc: "IupCanvas", cdecl, dynlib: dllname.} -proc Dialog*(child: PIhandle): PIhandle {. +proc dialog*(child: PIhandle): PIhandle {. importc: "IupDialog", cdecl, dynlib: dllname.} -proc User*(): PIhandle {. +proc user*(): PIhandle {. importc: "IupUser", cdecl, dynlib: dllname.} -proc Label*(title: cstring): PIhandle {. +proc label*(title: cstring): PIhandle {. importc: "IupLabel", cdecl, dynlib: dllname.} -proc List*(action: cstring): PIhandle {. +proc list*(action: cstring): PIhandle {. importc: "IupList", cdecl, dynlib: dllname.} -proc Text*(action: cstring): PIhandle {. +proc text*(action: cstring): PIhandle {. importc: "IupText", cdecl, dynlib: dllname.} -proc MultiLine*(action: cstring): PIhandle {. +proc multiLine*(action: cstring): PIhandle {. importc: "IupMultiLine", cdecl, dynlib: dllname.} -proc Toggle*(title, action: cstring): PIhandle {. +proc toggle*(title, action: cstring): PIhandle {. importc: "IupToggle", cdecl, dynlib: dllname.} -proc Timer*(): PIhandle {. +proc timer*(): PIhandle {. importc: "IupTimer", cdecl, dynlib: dllname.} -proc ProgressBar*(): PIhandle {. +proc progressBar*(): PIhandle {. importc: "IupProgressBar", cdecl, dynlib: dllname.} -proc Val*(theType: cstring): PIhandle {. +proc val*(theType: cstring): PIhandle {. importc: "IupVal", cdecl, dynlib: dllname.} -proc Tabs*(child: PIhandle): PIhandle {. +proc tabs*(child: PIhandle): PIhandle {. importc: "IupTabs", cdecl, dynlib: dllname, varargs.} -proc Tabsv*(children: ptr PIhandle): PIhandle {. +proc tabsv*(children: ptr PIhandle): PIhandle {. importc: "IupTabsv", cdecl, dynlib: dllname.} -proc Tree*(): PIhandle {.importc: "IupTree", cdecl, dynlib: dllname.} +proc tree*(): PIhandle {.importc: "IupTree", cdecl, dynlib: dllname.} -proc Spin*(): PIhandle {.importc: "IupSpin", cdecl, dynlib: dllname.} -proc Spinbox*(child: PIhandle): PIhandle {. +proc spin*(): PIhandle {.importc: "IupSpin", cdecl, dynlib: dllname.} +proc spinbox*(child: PIhandle): PIhandle {. importc: "IupSpinbox", cdecl, dynlib: dllname.} # IupText utilities -proc TextConvertLinColToPos*(ih: PIhandle, lin, col: cint, pos: var cint) {. +proc textConvertLinColToPos*(ih: PIhandle, lin, col: cint, pos: var cint) {. importc: "IupTextConvertLinColToPos", cdecl, dynlib: dllname.} -proc TextConvertPosToLinCol*(ih: PIhandle, pos: cint, lin, col: var cint) {. +proc textConvertPosToLinCol*(ih: PIhandle, pos: cint, lin, col: var cint) {. importc: "IupTextConvertPosToLinCol", cdecl, dynlib: dllname.} -proc ConvertXYToPos*(ih: PIhandle, x, y: cint): cint {. +proc convertXYToPos*(ih: PIhandle, x, y: cint): cint {. importc: "IupConvertXYToPos", cdecl, dynlib: dllname.} # IupTree utilities -proc TreeSetUserId*(ih: PIhandle, id: cint, userid: pointer): cint {. +proc treeSetUserId*(ih: PIhandle, id: cint, userid: pointer): cint {. importc: "IupTreeSetUserId", cdecl, dynlib: dllname, discardable.} -proc TreeGetUserId*(ih: PIhandle, id: cint): pointer {. +proc treeGetUserId*(ih: PIhandle, id: cint): pointer {. importc: "IupTreeGetUserId", cdecl, dynlib: dllname.} -proc TreeGetId*(ih: PIhandle, userid: pointer): cint {. +proc treeGetId*(ih: PIhandle, userid: pointer): cint {. importc: "IupTreeGetId", cdecl, dynlib: dllname.} -proc TreeSetAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {. +proc treeSetAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {. importc: "IupTreeSetAttribute", cdecl, dynlib: dllname.} -proc TreeStoreAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {. +proc treeStoreAttribute*(ih: PIhandle, name: cstring, id: cint, value: cstring) {. importc: "IupTreeStoreAttribute", cdecl, dynlib: dllname.} -proc TreeGetAttribute*(ih: PIhandle, name: cstring, id: cint): cstring {. +proc treeGetAttribute*(ih: PIhandle, name: cstring, id: cint): cstring {. importc: "IupTreeGetAttribute", cdecl, dynlib: dllname.} -proc TreeGetInt*(ih: PIhandle, name: cstring, id: cint): cint {. +proc treeGetInt*(ih: PIhandle, name: cstring, id: cint): cint {. importc: "IupTreeGetInt", cdecl, dynlib: dllname.} -proc TreeGetFloat*(ih: PIhandle, name: cstring, id: cint): cfloat {. +proc treeGetFloat*(ih: PIhandle, name: cstring, id: cint): cfloat {. importc: "IupTreeGetFloat", cdecl, dynlib: dllname.} -proc TreeSetfAttribute*(ih: PIhandle, name: cstring, id: cint, format: cstring) {. +proc treeSetfAttribute*(ih: PIhandle, name: cstring, id: cint, format: cstring) {. importc: "IupTreeSetfAttribute", cdecl, dynlib: dllname, varargs.} @@ -434,516 +434,516 @@ const IUP_MASK_INT* = "[+/-]?/d+" IUP_MASK_UINT* = "/d+" -# from 32 to 126, all character sets are equal, -# the key code i the same as the character code. -const - K_SP* = cint(ord(' ')) - K_exclam* = cint(ord('!')) - K_quotedbl* = cint(ord('\"')) - K_numbersign* = cint(ord('#')) - K_dollar* = cint(ord('$')) - K_percent* = cint(ord('%')) - K_ampersand* = cint(ord('&')) - K_apostrophe* = cint(ord('\'')) - K_parentleft* = cint(ord('(')) - K_parentright* = cint(ord(')')) - K_asterisk* = cint(ord('*')) - K_plus* = cint(ord('+')) - K_comma* = cint(ord(',')) - K_minus* = cint(ord('-')) - K_period* = cint(ord('.')) - K_slash* = cint(ord('/')) - K_0* = cint(ord('0')) - K_1* = cint(ord('1')) - K_2* = cint(ord('2')) - K_3* = cint(ord('3')) - K_4* = cint(ord('4')) - K_5* = cint(ord('5')) - K_6* = cint(ord('6')) - K_7* = cint(ord('7')) - K_8* = cint(ord('8')) - K_9* = cint(ord('9')) - K_colon* = cint(ord(':')) - K_semicolon* = cint(ord(';')) - K_less* = cint(ord('<')) - K_equal* = cint(ord('=')) - K_greater* = cint(ord('>')) - K_question* = cint(ord('?')) - K_at* = cint(ord('@')) - K_upperA* = cint(ord('A')) - K_upperB* = cint(ord('B')) - K_upperC* = cint(ord('C')) - K_upperD* = cint(ord('D')) - K_upperE* = cint(ord('E')) - K_upperF* = cint(ord('F')) - K_upperG* = cint(ord('G')) - K_upperH* = cint(ord('H')) - K_upperI* = cint(ord('I')) - K_upperJ* = cint(ord('J')) - K_upperK* = cint(ord('K')) - K_upperL* = cint(ord('L')) - K_upperM* = cint(ord('M')) - K_upperN* = cint(ord('N')) - K_upperO* = cint(ord('O')) - K_upperP* = cint(ord('P')) - K_upperQ* = cint(ord('Q')) - K_upperR* = cint(ord('R')) - K_upperS* = cint(ord('S')) - K_upperT* = cint(ord('T')) - K_upperU* = cint(ord('U')) - K_upperV* = cint(ord('V')) - K_upperW* = cint(ord('W')) - K_upperX* = cint(ord('X')) - K_upperY* = cint(ord('Y')) - K_upperZ* = cint(ord('Z')) - K_bracketleft* = cint(ord('[')) - K_backslash* = cint(ord('\\')) - K_bracketright* = cint(ord(']')) - K_circum* = cint(ord('^')) - K_underscore* = cint(ord('_')) - K_grave* = cint(ord('`')) - K_lowera* = cint(ord('a')) - K_lowerb* = cint(ord('b')) - K_lowerc* = cint(ord('c')) - K_lowerd* = cint(ord('d')) - K_lowere* = cint(ord('e')) - K_lowerf* = cint(ord('f')) - K_lowerg* = cint(ord('g')) - K_lowerh* = cint(ord('h')) - K_loweri* = cint(ord('i')) - K_lowerj* = cint(ord('j')) - K_lowerk* = cint(ord('k')) - K_lowerl* = cint(ord('l')) - K_lowerm* = cint(ord('m')) - K_lowern* = cint(ord('n')) - K_lowero* = cint(ord('o')) - K_lowerp* = cint(ord('p')) - K_lowerq* = cint(ord('q')) - K_lowerr* = cint(ord('r')) - K_lowers* = cint(ord('s')) - K_lowert* = cint(ord('t')) - K_loweru* = cint(ord('u')) - K_lowerv* = cint(ord('v')) - K_lowerw* = cint(ord('w')) - K_lowerx* = cint(ord('x')) - K_lowery* = cint(ord('y')) - K_lowerz* = cint(ord('z')) - K_braceleft* = cint(ord('{')) - K_bar* = cint(ord('|')) - K_braceright* = cint(ord('}')) - K_tilde* = cint(ord('~')) - -proc isPrint*(c: cint): bool = return c > 31 and c < 127 - -# also define the escape sequences that have keys associated -const - K_BS* = cint(ord('\b')) - K_TAB* = cint(ord('\t')) - K_LF* = cint(10) - K_CR* = cint(13) - -# IUP Extended Key Codes, range start at 128 -# Modifiers use 256 interval -# These key code definitions are specific to IUP - -proc isXkey*(c: cint): bool = return c > 128 -proc isShiftXkey*(c: cint): bool = return c > 256 and c < 512 -proc isCtrlXkey*(c: cint): bool = return c > 512 and c < 768 -proc isAltXkey*(c: cint): bool = return c > 768 and c < 1024 -proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280 - -proc IUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128) -proc IUPsxCODE*(c: cint): cint = +# from 32 to 126, all character sets are equal, +# the key code i the same as the character code. +const + K_SP* = cint(ord(' ')) + K_exclam* = cint(ord('!')) + K_quotedbl* = cint(ord('\"')) + K_numbersign* = cint(ord('#')) + K_dollar* = cint(ord('$')) + K_percent* = cint(ord('%')) + K_ampersand* = cint(ord('&')) + K_apostrophe* = cint(ord('\'')) + K_parentleft* = cint(ord('(')) + K_parentright* = cint(ord(')')) + K_asterisk* = cint(ord('*')) + K_plus* = cint(ord('+')) + K_comma* = cint(ord(',')) + K_minus* = cint(ord('-')) + K_period* = cint(ord('.')) + K_slash* = cint(ord('/')) + K_0* = cint(ord('0')) + K_1* = cint(ord('1')) + K_2* = cint(ord('2')) + K_3* = cint(ord('3')) + K_4* = cint(ord('4')) + K_5* = cint(ord('5')) + K_6* = cint(ord('6')) + K_7* = cint(ord('7')) + K_8* = cint(ord('8')) + K_9* = cint(ord('9')) + K_colon* = cint(ord(':')) + K_semicolon* = cint(ord(';')) + K_less* = cint(ord('<')) + K_equal* = cint(ord('=')) + K_greater* = cint(ord('>')) + K_question* = cint(ord('?')) + K_at* = cint(ord('@')) + K_upperA* = cint(ord('A')) + K_upperB* = cint(ord('B')) + K_upperC* = cint(ord('C')) + K_upperD* = cint(ord('D')) + K_upperE* = cint(ord('E')) + K_upperF* = cint(ord('F')) + K_upperG* = cint(ord('G')) + K_upperH* = cint(ord('H')) + K_upperI* = cint(ord('I')) + K_upperJ* = cint(ord('J')) + K_upperK* = cint(ord('K')) + K_upperL* = cint(ord('L')) + K_upperM* = cint(ord('M')) + K_upperN* = cint(ord('N')) + K_upperO* = cint(ord('O')) + K_upperP* = cint(ord('P')) + K_upperQ* = cint(ord('Q')) + K_upperR* = cint(ord('R')) + K_upperS* = cint(ord('S')) + K_upperT* = cint(ord('T')) + K_upperU* = cint(ord('U')) + K_upperV* = cint(ord('V')) + K_upperW* = cint(ord('W')) + K_upperX* = cint(ord('X')) + K_upperY* = cint(ord('Y')) + K_upperZ* = cint(ord('Z')) + K_bracketleft* = cint(ord('[')) + K_backslash* = cint(ord('\\')) + K_bracketright* = cint(ord(']')) + K_circum* = cint(ord('^')) + K_underscore* = cint(ord('_')) + K_grave* = cint(ord('`')) + K_lowera* = cint(ord('a')) + K_lowerb* = cint(ord('b')) + K_lowerc* = cint(ord('c')) + K_lowerd* = cint(ord('d')) + K_lowere* = cint(ord('e')) + K_lowerf* = cint(ord('f')) + K_lowerg* = cint(ord('g')) + K_lowerh* = cint(ord('h')) + K_loweri* = cint(ord('i')) + K_lowerj* = cint(ord('j')) + K_lowerk* = cint(ord('k')) + K_lowerl* = cint(ord('l')) + K_lowerm* = cint(ord('m')) + K_lowern* = cint(ord('n')) + K_lowero* = cint(ord('o')) + K_lowerp* = cint(ord('p')) + K_lowerq* = cint(ord('q')) + K_lowerr* = cint(ord('r')) + K_lowers* = cint(ord('s')) + K_lowert* = cint(ord('t')) + K_loweru* = cint(ord('u')) + K_lowerv* = cint(ord('v')) + K_lowerw* = cint(ord('w')) + K_lowerx* = cint(ord('x')) + K_lowery* = cint(ord('y')) + K_lowerz* = cint(ord('z')) + K_braceleft* = cint(ord('{')) + K_bar* = cint(ord('|')) + K_braceright* = cint(ord('}')) + K_tilde* = cint(ord('~')) + +proc isPrint*(c: cint): bool = return c > 31 and c < 127 + +# also define the escape sequences that have keys associated +const + K_BS* = cint(ord('\b')) + K_TAB* = cint(ord('\t')) + K_LF* = cint(10) + K_CR* = cint(13) + +# IUP Extended Key Codes, range start at 128 +# Modifiers use 256 interval +# These key code definitions are specific to IUP + +proc isXkey*(c: cint): bool = return c > 128 +proc isShiftXkey*(c: cint): bool = return c > 256 and c < 512 +proc isCtrlXkey*(c: cint): bool = return c > 512 and c < 768 +proc isAltXkey*(c: cint): bool = return c > 768 and c < 1024 +proc isSysXkey*(c: cint): bool = return c > 1024 and c < 1280 + +proc iUPxCODE*(c: cint): cint = return c + cint(128) # Normal (must be above 128) +proc iUPsxCODE*(c: cint): cint = return c + cint(256) # Shift (must have range to include the standard keys and the normal # extended keys, so must be above 256 -proc IUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl -proc IUPmxCODE*(c: cint): cint = return c + cint(768) # Alt -proc IUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple) - -const - IUP_NUMMAXCODES* = 1280 ## 5*256=1280 Normal+Shift+Ctrl+Alt+Sys - - K_HOME* = IUPxCODE(1) - K_UP* = IUPxCODE(2) - K_PGUP* = IUPxCODE(3) - K_LEFT* = IUPxCODE(4) - K_MIDDLE* = IUPxCODE(5) - K_RIGHT* = IUPxCODE(6) - K_END* = IUPxCODE(7) - K_DOWN* = IUPxCODE(8) - K_PGDN* = IUPxCODE(9) - K_INS* = IUPxCODE(10) - K_DEL* = IUPxCODE(11) - K_PAUSE* = IUPxCODE(12) - K_ESC* = IUPxCODE(13) - K_ccedilla* = IUPxCODE(14) - K_F1* = IUPxCODE(15) - K_F2* = IUPxCODE(16) - K_F3* = IUPxCODE(17) - K_F4* = IUPxCODE(18) - K_F5* = IUPxCODE(19) - K_F6* = IUPxCODE(20) - K_F7* = IUPxCODE(21) - K_F8* = IUPxCODE(22) - K_F9* = IUPxCODE(23) - K_F10* = IUPxCODE(24) - K_F11* = IUPxCODE(25) - K_F12* = IUPxCODE(26) - K_Print* = IUPxCODE(27) - K_Menu* = IUPxCODE(28) - - K_acute* = IUPxCODE(29) # no Shift/Ctrl/Alt - - K_sHOME* = IUPsxCODE(K_HOME) - K_sUP* = IUPsxCODE(K_UP) - K_sPGUP* = IUPsxCODE(K_PGUP) - K_sLEFT* = IUPsxCODE(K_LEFT) - K_sMIDDLE* = IUPsxCODE(K_MIDDLE) - K_sRIGHT* = IUPsxCODE(K_RIGHT) - K_sEND* = IUPsxCODE(K_END) - K_sDOWN* = IUPsxCODE(K_DOWN) - K_sPGDN* = IUPsxCODE(K_PGDN) - K_sINS* = IUPsxCODE(K_INS) - K_sDEL* = IUPsxCODE(K_DEL) - K_sSP* = IUPsxCODE(K_SP) - K_sTAB* = IUPsxCODE(K_TAB) - K_sCR* = IUPsxCODE(K_CR) - K_sBS* = IUPsxCODE(K_BS) - K_sPAUSE* = IUPsxCODE(K_PAUSE) - K_sESC* = IUPsxCODE(K_ESC) - K_sCcedilla* = IUPsxCODE(K_ccedilla) - K_sF1* = IUPsxCODE(K_F1) - K_sF2* = IUPsxCODE(K_F2) - K_sF3* = IUPsxCODE(K_F3) - K_sF4* = IUPsxCODE(K_F4) - K_sF5* = IUPsxCODE(K_F5) - K_sF6* = IUPsxCODE(K_F6) - K_sF7* = IUPsxCODE(K_F7) - K_sF8* = IUPsxCODE(K_F8) - K_sF9* = IUPsxCODE(K_F9) - K_sF10* = IUPsxCODE(K_F10) - K_sF11* = IUPsxCODE(K_F11) - K_sF12* = IUPsxCODE(K_F12) - K_sPrint* = IUPsxCODE(K_Print) - K_sMenu* = IUPsxCODE(K_Menu) - - K_cHOME* = IUPcxCODE(K_HOME) - K_cUP* = IUPcxCODE(K_UP) - K_cPGUP* = IUPcxCODE(K_PGUP) - K_cLEFT* = IUPcxCODE(K_LEFT) - K_cMIDDLE* = IUPcxCODE(K_MIDDLE) - K_cRIGHT* = IUPcxCODE(K_RIGHT) - K_cEND* = IUPcxCODE(K_END) - K_cDOWN* = IUPcxCODE(K_DOWN) - K_cPGDN* = IUPcxCODE(K_PGDN) - K_cINS* = IUPcxCODE(K_INS) - K_cDEL* = IUPcxCODE(K_DEL) - K_cSP* = IUPcxCODE(K_SP) - K_cTAB* = IUPcxCODE(K_TAB) - K_cCR* = IUPcxCODE(K_CR) - K_cBS* = IUPcxCODE(K_BS) - K_cPAUSE* = IUPcxCODE(K_PAUSE) - K_cESC* = IUPcxCODE(K_ESC) - K_cCcedilla* = IUPcxCODE(K_ccedilla) - K_cF1* = IUPcxCODE(K_F1) - K_cF2* = IUPcxCODE(K_F2) - K_cF3* = IUPcxCODE(K_F3) - K_cF4* = IUPcxCODE(K_F4) - K_cF5* = IUPcxCODE(K_F5) - K_cF6* = IUPcxCODE(K_F6) - K_cF7* = IUPcxCODE(K_F7) - K_cF8* = IUPcxCODE(K_F8) - K_cF9* = IUPcxCODE(K_F9) - K_cF10* = IUPcxCODE(K_F10) - K_cF11* = IUPcxCODE(K_F11) - K_cF12* = IUPcxCODE(K_F12) - K_cPrint* = IUPcxCODE(K_Print) - K_cMenu* = IUPcxCODE(K_Menu) - - K_mHOME* = IUPmxCODE(K_HOME) - K_mUP* = IUPmxCODE(K_UP) - K_mPGUP* = IUPmxCODE(K_PGUP) - K_mLEFT* = IUPmxCODE(K_LEFT) - K_mMIDDLE* = IUPmxCODE(K_MIDDLE) - K_mRIGHT* = IUPmxCODE(K_RIGHT) - K_mEND* = IUPmxCODE(K_END) - K_mDOWN* = IUPmxCODE(K_DOWN) - K_mPGDN* = IUPmxCODE(K_PGDN) - K_mINS* = IUPmxCODE(K_INS) - K_mDEL* = IUPmxCODE(K_DEL) - K_mSP* = IUPmxCODE(K_SP) - K_mTAB* = IUPmxCODE(K_TAB) - K_mCR* = IUPmxCODE(K_CR) - K_mBS* = IUPmxCODE(K_BS) - K_mPAUSE* = IUPmxCODE(K_PAUSE) - K_mESC* = IUPmxCODE(K_ESC) - K_mCcedilla* = IUPmxCODE(K_ccedilla) - K_mF1* = IUPmxCODE(K_F1) - K_mF2* = IUPmxCODE(K_F2) - K_mF3* = IUPmxCODE(K_F3) - K_mF4* = IUPmxCODE(K_F4) - K_mF5* = IUPmxCODE(K_F5) - K_mF6* = IUPmxCODE(K_F6) - K_mF7* = IUPmxCODE(K_F7) - K_mF8* = IUPmxCODE(K_F8) - K_mF9* = IUPmxCODE(K_F9) - K_mF10* = IUPmxCODE(K_F10) - K_mF11* = IUPmxCODE(K_F11) - K_mF12* = IUPmxCODE(K_F12) - K_mPrint* = IUPmxCODE(K_Print) - K_mMenu* = IUPmxCODE(K_Menu) - - K_yHOME* = IUPyxCODE(K_HOME) - K_yUP* = IUPyxCODE(K_UP) - K_yPGUP* = IUPyxCODE(K_PGUP) - K_yLEFT* = IUPyxCODE(K_LEFT) - K_yMIDDLE* = IUPyxCODE(K_MIDDLE) - K_yRIGHT* = IUPyxCODE(K_RIGHT) - K_yEND* = IUPyxCODE(K_END) - K_yDOWN* = IUPyxCODE(K_DOWN) - K_yPGDN* = IUPyxCODE(K_PGDN) - K_yINS* = IUPyxCODE(K_INS) - K_yDEL* = IUPyxCODE(K_DEL) - K_ySP* = IUPyxCODE(K_SP) - K_yTAB* = IUPyxCODE(K_TAB) - K_yCR* = IUPyxCODE(K_CR) - K_yBS* = IUPyxCODE(K_BS) - K_yPAUSE* = IUPyxCODE(K_PAUSE) - K_yESC* = IUPyxCODE(K_ESC) - K_yCcedilla* = IUPyxCODE(K_ccedilla) - K_yF1* = IUPyxCODE(K_F1) - K_yF2* = IUPyxCODE(K_F2) - K_yF3* = IUPyxCODE(K_F3) - K_yF4* = IUPyxCODE(K_F4) - K_yF5* = IUPyxCODE(K_F5) - K_yF6* = IUPyxCODE(K_F6) - K_yF7* = IUPyxCODE(K_F7) - K_yF8* = IUPyxCODE(K_F8) - K_yF9* = IUPyxCODE(K_F9) - K_yF10* = IUPyxCODE(K_F10) - K_yF11* = IUPyxCODE(K_F11) - K_yF12* = IUPyxCODE(K_F12) - K_yPrint* = IUPyxCODE(K_Print) - K_yMenu* = IUPyxCODE(K_Menu) - - K_sPlus* = IUPsxCODE(K_plus) - K_sComma* = IUPsxCODE(K_comma) - K_sMinus* = IUPsxCODE(K_minus) - K_sPeriod* = IUPsxCODE(K_period) - K_sSlash* = IUPsxCODE(K_slash) - K_sAsterisk* = IUPsxCODE(K_asterisk) - - K_cupperA* = IUPcxCODE(K_upperA) - K_cupperB* = IUPcxCODE(K_upperB) - K_cupperC* = IUPcxCODE(K_upperC) - K_cupperD* = IUPcxCODE(K_upperD) - K_cupperE* = IUPcxCODE(K_upperE) - K_cupperF* = IUPcxCODE(K_upperF) - K_cupperG* = IUPcxCODE(K_upperG) - K_cupperH* = IUPcxCODE(K_upperH) - K_cupperI* = IUPcxCODE(K_upperI) - K_cupperJ* = IUPcxCODE(K_upperJ) - K_cupperK* = IUPcxCODE(K_upperK) - K_cupperL* = IUPcxCODE(K_upperL) - K_cupperM* = IUPcxCODE(K_upperM) - K_cupperN* = IUPcxCODE(K_upperN) - K_cupperO* = IUPcxCODE(K_upperO) - K_cupperP* = IUPcxCODE(K_upperP) - K_cupperQ* = IUPcxCODE(K_upperQ) - K_cupperR* = IUPcxCODE(K_upperR) - K_cupperS* = IUPcxCODE(K_upperS) - K_cupperT* = IUPcxCODE(K_upperT) - K_cupperU* = IUPcxCODE(K_upperU) - K_cupperV* = IUPcxCODE(K_upperV) - K_cupperW* = IUPcxCODE(K_upperW) - K_cupperX* = IUPcxCODE(K_upperX) - K_cupperY* = IUPcxCODE(K_upperY) - K_cupperZ* = IUPcxCODE(K_upperZ) - K_c1* = IUPcxCODE(K_1) - K_c2* = IUPcxCODE(K_2) - K_c3* = IUPcxCODE(K_3) - K_c4* = IUPcxCODE(K_4) - K_c5* = IUPcxCODE(K_5) - K_c6* = IUPcxCODE(K_6) - K_c7* = IUPcxCODE(K_7) - K_c8* = IUPcxCODE(K_8) - K_c9* = IUPcxCODE(K_9) - K_c0* = IUPcxCODE(K_0) - K_cPlus* = IUPcxCODE(K_plus) - K_cComma* = IUPcxCODE(K_comma) - K_cMinus* = IUPcxCODE(K_minus) - K_cPeriod* = IUPcxCODE(K_period) - K_cSlash* = IUPcxCODE(K_slash) - K_cSemicolon* = IUPcxCODE(K_semicolon) - K_cEqual* = IUPcxCODE(K_equal) - K_cBracketleft* = IUPcxCODE(K_bracketleft) - K_cBracketright* = IUPcxCODE(K_bracketright) - K_cBackslash* = IUPcxCODE(K_backslash) - K_cAsterisk* = IUPcxCODE(K_asterisk) - - K_mupperA* = IUPmxCODE(K_upperA) - K_mupperB* = IUPmxCODE(K_upperB) - K_mupperC* = IUPmxCODE(K_upperC) - K_mupperD* = IUPmxCODE(K_upperD) - K_mupperE* = IUPmxCODE(K_upperE) - K_mupperF* = IUPmxCODE(K_upperF) - K_mupperG* = IUPmxCODE(K_upperG) - K_mupperH* = IUPmxCODE(K_upperH) - K_mupperI* = IUPmxCODE(K_upperI) - K_mupperJ* = IUPmxCODE(K_upperJ) - K_mupperK* = IUPmxCODE(K_upperK) - K_mupperL* = IUPmxCODE(K_upperL) - K_mupperM* = IUPmxCODE(K_upperM) - K_mupperN* = IUPmxCODE(K_upperN) - K_mupperO* = IUPmxCODE(K_upperO) - K_mupperP* = IUPmxCODE(K_upperP) - K_mupperQ* = IUPmxCODE(K_upperQ) - K_mupperR* = IUPmxCODE(K_upperR) - K_mupperS* = IUPmxCODE(K_upperS) - K_mupperT* = IUPmxCODE(K_upperT) - K_mupperU* = IUPmxCODE(K_upperU) - K_mupperV* = IUPmxCODE(K_upperV) - K_mupperW* = IUPmxCODE(K_upperW) - K_mupperX* = IUPmxCODE(K_upperX) - K_mupperY* = IUPmxCODE(K_upperY) - K_mupperZ* = IUPmxCODE(K_upperZ) - K_m1* = IUPmxCODE(K_1) - K_m2* = IUPmxCODE(K_2) - K_m3* = IUPmxCODE(K_3) - K_m4* = IUPmxCODE(K_4) - K_m5* = IUPmxCODE(K_5) - K_m6* = IUPmxCODE(K_6) - K_m7* = IUPmxCODE(K_7) - K_m8* = IUPmxCODE(K_8) - K_m9* = IUPmxCODE(K_9) - K_m0* = IUPmxCODE(K_0) - K_mPlus* = IUPmxCODE(K_plus) - K_mComma* = IUPmxCODE(K_comma) - K_mMinus* = IUPmxCODE(K_minus) - K_mPeriod* = IUPmxCODE(K_period) - K_mSlash* = IUPmxCODE(K_slash) - K_mSemicolon* = IUPmxCODE(K_semicolon) - K_mEqual* = IUPmxCODE(K_equal) - K_mBracketleft* = IUPmxCODE(K_bracketleft) - K_mBracketright* = IUPmxCODE(K_bracketright) - K_mBackslash* = IUPmxCODE(K_backslash) - K_mAsterisk* = IUPmxCODE(K_asterisk) - - K_yA* = IUPyxCODE(K_upperA) - K_yB* = IUPyxCODE(K_upperB) - K_yC* = IUPyxCODE(K_upperC) - K_yD* = IUPyxCODE(K_upperD) - K_yE* = IUPyxCODE(K_upperE) - K_yF* = IUPyxCODE(K_upperF) - K_yG* = IUPyxCODE(K_upperG) - K_yH* = IUPyxCODE(K_upperH) - K_yI* = IUPyxCODE(K_upperI) - K_yJ* = IUPyxCODE(K_upperJ) - K_yK* = IUPyxCODE(K_upperK) - K_yL* = IUPyxCODE(K_upperL) - K_yM* = IUPyxCODE(K_upperM) - K_yN* = IUPyxCODE(K_upperN) - K_yO* = IUPyxCODE(K_upperO) - K_yP* = IUPyxCODE(K_upperP) - K_yQ* = IUPyxCODE(K_upperQ) - K_yR* = IUPyxCODE(K_upperR) - K_yS* = IUPyxCODE(K_upperS) - K_yT* = IUPyxCODE(K_upperT) - K_yU* = IUPyxCODE(K_upperU) - K_yV* = IUPyxCODE(K_upperV) - K_yW* = IUPyxCODE(K_upperW) - K_yX* = IUPyxCODE(K_upperX) - K_yY* = IUPyxCODE(K_upperY) - K_yZ* = IUPyxCODE(K_upperZ) - K_y1* = IUPyxCODE(K_1) - K_y2* = IUPyxCODE(K_2) - K_y3* = IUPyxCODE(K_3) - K_y4* = IUPyxCODE(K_4) - K_y5* = IUPyxCODE(K_5) - K_y6* = IUPyxCODE(K_6) - K_y7* = IUPyxCODE(K_7) - K_y8* = IUPyxCODE(K_8) - K_y9* = IUPyxCODE(K_9) - K_y0* = IUPyxCODE(K_0) - K_yPlus* = IUPyxCODE(K_plus) - K_yComma* = IUPyxCODE(K_comma) - K_yMinus* = IUPyxCODE(K_minus) - K_yPeriod* = IUPyxCODE(K_period) - K_ySlash* = IUPyxCODE(K_slash) - K_ySemicolon* = IUPyxCODE(K_semicolon) - K_yEqual* = IUPyxCODE(K_equal) - K_yBracketleft* = IUPyxCODE(K_bracketleft) - K_yBracketright* = IUPyxCODE(K_bracketright) - K_yBackslash* = IUPyxCODE(K_backslash) - K_yAsterisk* = IUPyxCODE(K_asterisk) - -proc ControlsOpen*(): cint {.cdecl, importc: "IupControlsOpen", dynlib: dllname.} -proc ControlsClose*() {.cdecl, importc: "IupControlsClose", dynlib: dllname.} - -proc OldValOpen*() {.cdecl, importc: "IupOldValOpen", dynlib: dllname.} -proc OldTabsOpen*() {.cdecl, importc: "IupOldTabsOpen", dynlib: dllname.} - -proc Colorbar*(): PIhandle {.cdecl, importc: "IupColorbar", dynlib: dllname.} -proc Cells*(): PIhandle {.cdecl, importc: "IupCells", dynlib: dllname.} -proc ColorBrowser*(): PIhandle {.cdecl, importc: "IupColorBrowser", dynlib: dllname.} -proc Gauge*(): PIhandle {.cdecl, importc: "IupGauge", dynlib: dllname.} -proc Dial*(theType: cstring): PIhandle {.cdecl, importc: "IupDial", dynlib: dllname.} -proc Matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.} - -# IupMatrix utilities -proc MatSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint, +proc iUPcxCODE*(c: cint): cint = return c + cint(512) # Ctrl +proc iUPmxCODE*(c: cint): cint = return c + cint(768) # Alt +proc iUPyxCODE*(c: cint): cint = return c + cint(1024) # Sys (Win or Apple) + +const + IUP_NUMMAXCODES* = 1280 ## 5*256=1280 Normal+Shift+Ctrl+Alt+Sys + + K_HOME* = iUPxCODE(1) + K_UP* = iUPxCODE(2) + K_PGUP* = iUPxCODE(3) + K_LEFT* = iUPxCODE(4) + K_MIDDLE* = iUPxCODE(5) + K_RIGHT* = iUPxCODE(6) + K_END* = iUPxCODE(7) + K_DOWN* = iUPxCODE(8) + K_PGDN* = iUPxCODE(9) + K_INS* = iUPxCODE(10) + K_DEL* = iUPxCODE(11) + K_PAUSE* = iUPxCODE(12) + K_ESC* = iUPxCODE(13) + K_ccedilla* = iUPxCODE(14) + K_F1* = iUPxCODE(15) + K_F2* = iUPxCODE(16) + K_F3* = iUPxCODE(17) + K_F4* = iUPxCODE(18) + K_F5* = iUPxCODE(19) + K_F6* = iUPxCODE(20) + K_F7* = iUPxCODE(21) + K_F8* = iUPxCODE(22) + K_F9* = iUPxCODE(23) + K_F10* = iUPxCODE(24) + K_F11* = iUPxCODE(25) + K_F12* = iUPxCODE(26) + K_Print* = iUPxCODE(27) + K_Menu* = iUPxCODE(28) + + K_acute* = iUPxCODE(29) # no Shift/Ctrl/Alt + + K_sHOME* = iUPsxCODE(K_HOME) + K_sUP* = iUPsxCODE(K_UP) + K_sPGUP* = iUPsxCODE(K_PGUP) + K_sLEFT* = iUPsxCODE(K_LEFT) + K_sMIDDLE* = iUPsxCODE(K_MIDDLE) + K_sRIGHT* = iUPsxCODE(K_RIGHT) + K_sEND* = iUPsxCODE(K_END) + K_sDOWN* = iUPsxCODE(K_DOWN) + K_sPGDN* = iUPsxCODE(K_PGDN) + K_sINS* = iUPsxCODE(K_INS) + K_sDEL* = iUPsxCODE(K_DEL) + K_sSP* = iUPsxCODE(K_SP) + K_sTAB* = iUPsxCODE(K_TAB) + K_sCR* = iUPsxCODE(K_CR) + K_sBS* = iUPsxCODE(K_BS) + K_sPAUSE* = iUPsxCODE(K_PAUSE) + K_sESC* = iUPsxCODE(K_ESC) + K_sCcedilla* = iUPsxCODE(K_ccedilla) + K_sF1* = iUPsxCODE(K_F1) + K_sF2* = iUPsxCODE(K_F2) + K_sF3* = iUPsxCODE(K_F3) + K_sF4* = iUPsxCODE(K_F4) + K_sF5* = iUPsxCODE(K_F5) + K_sF6* = iUPsxCODE(K_F6) + K_sF7* = iUPsxCODE(K_F7) + K_sF8* = iUPsxCODE(K_F8) + K_sF9* = iUPsxCODE(K_F9) + K_sF10* = iUPsxCODE(K_F10) + K_sF11* = iUPsxCODE(K_F11) + K_sF12* = iUPsxCODE(K_F12) + K_sPrint* = iUPsxCODE(K_Print) + K_sMenu* = iUPsxCODE(K_Menu) + + K_cHOME* = iUPcxCODE(K_HOME) + K_cUP* = iUPcxCODE(K_UP) + K_cPGUP* = iUPcxCODE(K_PGUP) + K_cLEFT* = iUPcxCODE(K_LEFT) + K_cMIDDLE* = iUPcxCODE(K_MIDDLE) + K_cRIGHT* = iUPcxCODE(K_RIGHT) + K_cEND* = iUPcxCODE(K_END) + K_cDOWN* = iUPcxCODE(K_DOWN) + K_cPGDN* = iUPcxCODE(K_PGDN) + K_cINS* = iUPcxCODE(K_INS) + K_cDEL* = iUPcxCODE(K_DEL) + K_cSP* = iUPcxCODE(K_SP) + K_cTAB* = iUPcxCODE(K_TAB) + K_cCR* = iUPcxCODE(K_CR) + K_cBS* = iUPcxCODE(K_BS) + K_cPAUSE* = iUPcxCODE(K_PAUSE) + K_cESC* = iUPcxCODE(K_ESC) + K_cCcedilla* = iUPcxCODE(K_ccedilla) + K_cF1* = iUPcxCODE(K_F1) + K_cF2* = iUPcxCODE(K_F2) + K_cF3* = iUPcxCODE(K_F3) + K_cF4* = iUPcxCODE(K_F4) + K_cF5* = iUPcxCODE(K_F5) + K_cF6* = iUPcxCODE(K_F6) + K_cF7* = iUPcxCODE(K_F7) + K_cF8* = iUPcxCODE(K_F8) + K_cF9* = iUPcxCODE(K_F9) + K_cF10* = iUPcxCODE(K_F10) + K_cF11* = iUPcxCODE(K_F11) + K_cF12* = iUPcxCODE(K_F12) + K_cPrint* = iUPcxCODE(K_Print) + K_cMenu* = iUPcxCODE(K_Menu) + + K_mHOME* = iUPmxCODE(K_HOME) + K_mUP* = iUPmxCODE(K_UP) + K_mPGUP* = iUPmxCODE(K_PGUP) + K_mLEFT* = iUPmxCODE(K_LEFT) + K_mMIDDLE* = iUPmxCODE(K_MIDDLE) + K_mRIGHT* = iUPmxCODE(K_RIGHT) + K_mEND* = iUPmxCODE(K_END) + K_mDOWN* = iUPmxCODE(K_DOWN) + K_mPGDN* = iUPmxCODE(K_PGDN) + K_mINS* = iUPmxCODE(K_INS) + K_mDEL* = iUPmxCODE(K_DEL) + K_mSP* = iUPmxCODE(K_SP) + K_mTAB* = iUPmxCODE(K_TAB) + K_mCR* = iUPmxCODE(K_CR) + K_mBS* = iUPmxCODE(K_BS) + K_mPAUSE* = iUPmxCODE(K_PAUSE) + K_mESC* = iUPmxCODE(K_ESC) + K_mCcedilla* = iUPmxCODE(K_ccedilla) + K_mF1* = iUPmxCODE(K_F1) + K_mF2* = iUPmxCODE(K_F2) + K_mF3* = iUPmxCODE(K_F3) + K_mF4* = iUPmxCODE(K_F4) + K_mF5* = iUPmxCODE(K_F5) + K_mF6* = iUPmxCODE(K_F6) + K_mF7* = iUPmxCODE(K_F7) + K_mF8* = iUPmxCODE(K_F8) + K_mF9* = iUPmxCODE(K_F9) + K_mF10* = iUPmxCODE(K_F10) + K_mF11* = iUPmxCODE(K_F11) + K_mF12* = iUPmxCODE(K_F12) + K_mPrint* = iUPmxCODE(K_Print) + K_mMenu* = iUPmxCODE(K_Menu) + + K_yHOME* = iUPyxCODE(K_HOME) + K_yUP* = iUPyxCODE(K_UP) + K_yPGUP* = iUPyxCODE(K_PGUP) + K_yLEFT* = iUPyxCODE(K_LEFT) + K_yMIDDLE* = iUPyxCODE(K_MIDDLE) + K_yRIGHT* = iUPyxCODE(K_RIGHT) + K_yEND* = iUPyxCODE(K_END) + K_yDOWN* = iUPyxCODE(K_DOWN) + K_yPGDN* = iUPyxCODE(K_PGDN) + K_yINS* = iUPyxCODE(K_INS) + K_yDEL* = iUPyxCODE(K_DEL) + K_ySP* = iUPyxCODE(K_SP) + K_yTAB* = iUPyxCODE(K_TAB) + K_yCR* = iUPyxCODE(K_CR) + K_yBS* = iUPyxCODE(K_BS) + K_yPAUSE* = iUPyxCODE(K_PAUSE) + K_yESC* = iUPyxCODE(K_ESC) + K_yCcedilla* = iUPyxCODE(K_ccedilla) + K_yF1* = iUPyxCODE(K_F1) + K_yF2* = iUPyxCODE(K_F2) + K_yF3* = iUPyxCODE(K_F3) + K_yF4* = iUPyxCODE(K_F4) + K_yF5* = iUPyxCODE(K_F5) + K_yF6* = iUPyxCODE(K_F6) + K_yF7* = iUPyxCODE(K_F7) + K_yF8* = iUPyxCODE(K_F8) + K_yF9* = iUPyxCODE(K_F9) + K_yF10* = iUPyxCODE(K_F10) + K_yF11* = iUPyxCODE(K_F11) + K_yF12* = iUPyxCODE(K_F12) + K_yPrint* = iUPyxCODE(K_Print) + K_yMenu* = iUPyxCODE(K_Menu) + + K_sPlus* = iUPsxCODE(K_plus) + K_sComma* = iUPsxCODE(K_comma) + K_sMinus* = iUPsxCODE(K_minus) + K_sPeriod* = iUPsxCODE(K_period) + K_sSlash* = iUPsxCODE(K_slash) + K_sAsterisk* = iUPsxCODE(K_asterisk) + + K_cupperA* = iUPcxCODE(K_upperA) + K_cupperB* = iUPcxCODE(K_upperB) + K_cupperC* = iUPcxCODE(K_upperC) + K_cupperD* = iUPcxCODE(K_upperD) + K_cupperE* = iUPcxCODE(K_upperE) + K_cupperF* = iUPcxCODE(K_upperF) + K_cupperG* = iUPcxCODE(K_upperG) + K_cupperH* = iUPcxCODE(K_upperH) + K_cupperI* = iUPcxCODE(K_upperI) + K_cupperJ* = iUPcxCODE(K_upperJ) + K_cupperK* = iUPcxCODE(K_upperK) + K_cupperL* = iUPcxCODE(K_upperL) + K_cupperM* = iUPcxCODE(K_upperM) + K_cupperN* = iUPcxCODE(K_upperN) + K_cupperO* = iUPcxCODE(K_upperO) + K_cupperP* = iUPcxCODE(K_upperP) + K_cupperQ* = iUPcxCODE(K_upperQ) + K_cupperR* = iUPcxCODE(K_upperR) + K_cupperS* = iUPcxCODE(K_upperS) + K_cupperT* = iUPcxCODE(K_upperT) + K_cupperU* = iUPcxCODE(K_upperU) + K_cupperV* = iUPcxCODE(K_upperV) + K_cupperW* = iUPcxCODE(K_upperW) + K_cupperX* = iUPcxCODE(K_upperX) + K_cupperY* = iUPcxCODE(K_upperY) + K_cupperZ* = iUPcxCODE(K_upperZ) + K_c1* = iUPcxCODE(K_1) + K_c2* = iUPcxCODE(K_2) + K_c3* = iUPcxCODE(K_3) + K_c4* = iUPcxCODE(K_4) + K_c5* = iUPcxCODE(K_5) + K_c6* = iUPcxCODE(K_6) + K_c7* = iUPcxCODE(K_7) + K_c8* = iUPcxCODE(K_8) + K_c9* = iUPcxCODE(K_9) + K_c0* = iUPcxCODE(K_0) + K_cPlus* = iUPcxCODE(K_plus) + K_cComma* = iUPcxCODE(K_comma) + K_cMinus* = iUPcxCODE(K_minus) + K_cPeriod* = iUPcxCODE(K_period) + K_cSlash* = iUPcxCODE(K_slash) + K_cSemicolon* = iUPcxCODE(K_semicolon) + K_cEqual* = iUPcxCODE(K_equal) + K_cBracketleft* = iUPcxCODE(K_bracketleft) + K_cBracketright* = iUPcxCODE(K_bracketright) + K_cBackslash* = iUPcxCODE(K_backslash) + K_cAsterisk* = iUPcxCODE(K_asterisk) + + K_mupperA* = iUPmxCODE(K_upperA) + K_mupperB* = iUPmxCODE(K_upperB) + K_mupperC* = iUPmxCODE(K_upperC) + K_mupperD* = iUPmxCODE(K_upperD) + K_mupperE* = iUPmxCODE(K_upperE) + K_mupperF* = iUPmxCODE(K_upperF) + K_mupperG* = iUPmxCODE(K_upperG) + K_mupperH* = iUPmxCODE(K_upperH) + K_mupperI* = iUPmxCODE(K_upperI) + K_mupperJ* = iUPmxCODE(K_upperJ) + K_mupperK* = iUPmxCODE(K_upperK) + K_mupperL* = iUPmxCODE(K_upperL) + K_mupperM* = iUPmxCODE(K_upperM) + K_mupperN* = iUPmxCODE(K_upperN) + K_mupperO* = iUPmxCODE(K_upperO) + K_mupperP* = iUPmxCODE(K_upperP) + K_mupperQ* = iUPmxCODE(K_upperQ) + K_mupperR* = iUPmxCODE(K_upperR) + K_mupperS* = iUPmxCODE(K_upperS) + K_mupperT* = iUPmxCODE(K_upperT) + K_mupperU* = iUPmxCODE(K_upperU) + K_mupperV* = iUPmxCODE(K_upperV) + K_mupperW* = iUPmxCODE(K_upperW) + K_mupperX* = iUPmxCODE(K_upperX) + K_mupperY* = iUPmxCODE(K_upperY) + K_mupperZ* = iUPmxCODE(K_upperZ) + K_m1* = iUPmxCODE(K_1) + K_m2* = iUPmxCODE(K_2) + K_m3* = iUPmxCODE(K_3) + K_m4* = iUPmxCODE(K_4) + K_m5* = iUPmxCODE(K_5) + K_m6* = iUPmxCODE(K_6) + K_m7* = iUPmxCODE(K_7) + K_m8* = iUPmxCODE(K_8) + K_m9* = iUPmxCODE(K_9) + K_m0* = iUPmxCODE(K_0) + K_mPlus* = iUPmxCODE(K_plus) + K_mComma* = iUPmxCODE(K_comma) + K_mMinus* = iUPmxCODE(K_minus) + K_mPeriod* = iUPmxCODE(K_period) + K_mSlash* = iUPmxCODE(K_slash) + K_mSemicolon* = iUPmxCODE(K_semicolon) + K_mEqual* = iUPmxCODE(K_equal) + K_mBracketleft* = iUPmxCODE(K_bracketleft) + K_mBracketright* = iUPmxCODE(K_bracketright) + K_mBackslash* = iUPmxCODE(K_backslash) + K_mAsterisk* = iUPmxCODE(K_asterisk) + + K_yA* = iUPyxCODE(K_upperA) + K_yB* = iUPyxCODE(K_upperB) + K_yC* = iUPyxCODE(K_upperC) + K_yD* = iUPyxCODE(K_upperD) + K_yE* = iUPyxCODE(K_upperE) + K_yF* = iUPyxCODE(K_upperF) + K_yG* = iUPyxCODE(K_upperG) + K_yH* = iUPyxCODE(K_upperH) + K_yI* = iUPyxCODE(K_upperI) + K_yJ* = iUPyxCODE(K_upperJ) + K_yK* = iUPyxCODE(K_upperK) + K_yL* = iUPyxCODE(K_upperL) + K_yM* = iUPyxCODE(K_upperM) + K_yN* = iUPyxCODE(K_upperN) + K_yO* = iUPyxCODE(K_upperO) + K_yP* = iUPyxCODE(K_upperP) + K_yQ* = iUPyxCODE(K_upperQ) + K_yR* = iUPyxCODE(K_upperR) + K_yS* = iUPyxCODE(K_upperS) + K_yT* = iUPyxCODE(K_upperT) + K_yU* = iUPyxCODE(K_upperU) + K_yV* = iUPyxCODE(K_upperV) + K_yW* = iUPyxCODE(K_upperW) + K_yX* = iUPyxCODE(K_upperX) + K_yY* = iUPyxCODE(K_upperY) + K_yZ* = iUPyxCODE(K_upperZ) + K_y1* = iUPyxCODE(K_1) + K_y2* = iUPyxCODE(K_2) + K_y3* = iUPyxCODE(K_3) + K_y4* = iUPyxCODE(K_4) + K_y5* = iUPyxCODE(K_5) + K_y6* = iUPyxCODE(K_6) + K_y7* = iUPyxCODE(K_7) + K_y8* = iUPyxCODE(K_8) + K_y9* = iUPyxCODE(K_9) + K_y0* = iUPyxCODE(K_0) + K_yPlus* = iUPyxCODE(K_plus) + K_yComma* = iUPyxCODE(K_comma) + K_yMinus* = iUPyxCODE(K_minus) + K_yPeriod* = iUPyxCODE(K_period) + K_ySlash* = iUPyxCODE(K_slash) + K_ySemicolon* = iUPyxCODE(K_semicolon) + K_yEqual* = iUPyxCODE(K_equal) + K_yBracketleft* = iUPyxCODE(K_bracketleft) + K_yBracketright* = iUPyxCODE(K_bracketright) + K_yBackslash* = iUPyxCODE(K_backslash) + K_yAsterisk* = iUPyxCODE(K_asterisk) + +proc controlsOpen*(): cint {.cdecl, importc: "IupControlsOpen", dynlib: dllname.} +proc controlsClose*() {.cdecl, importc: "IupControlsClose", dynlib: dllname.} + +proc oldValOpen*() {.cdecl, importc: "IupOldValOpen", dynlib: dllname.} +proc oldTabsOpen*() {.cdecl, importc: "IupOldTabsOpen", dynlib: dllname.} + +proc colorbar*(): PIhandle {.cdecl, importc: "IupColorbar", dynlib: dllname.} +proc cells*(): PIhandle {.cdecl, importc: "IupCells", dynlib: dllname.} +proc colorBrowser*(): PIhandle {.cdecl, importc: "IupColorBrowser", dynlib: dllname.} +proc gauge*(): PIhandle {.cdecl, importc: "IupGauge", dynlib: dllname.} +proc dial*(theType: cstring): PIhandle {.cdecl, importc: "IupDial", dynlib: dllname.} +proc matrix*(action: cstring): PIhandle {.cdecl, importc: "IupMatrix", dynlib: dllname.} + +# IupMatrix utilities +proc matSetAttribute*(ih: PIhandle, name: cstring, lin, col: cint, value: cstring) {. - cdecl, importc: "IupMatSetAttribute", dynlib: dllname.} -proc MatStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint, + cdecl, importc: "IupMatSetAttribute", dynlib: dllname.} +proc matStoreAttribute*(ih: PIhandle, name: cstring, lin, col: cint, value: cstring) {.cdecl, - importc: "IupMatStoreAttribute", dynlib: dllname.} -proc MatGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {. - cdecl, importc: "IupMatGetAttribute", dynlib: dllname.} -proc MatGetInt*(ih: PIhandle, name: cstring, lin, col: cint): cint {. - cdecl, importc: "IupMatGetInt", dynlib: dllname.} -proc MatGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {. - cdecl, importc: "IupMatGetFloat", dynlib: dllname.} -proc MatSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint, + importc: "IupMatStoreAttribute", dynlib: dllname.} +proc matGetAttribute*(ih: PIhandle, name: cstring, lin, col: cint): cstring {. + cdecl, importc: "IupMatGetAttribute", dynlib: dllname.} +proc matGetInt*(ih: PIhandle, name: cstring, lin, col: cint): cint {. + cdecl, importc: "IupMatGetInt", dynlib: dllname.} +proc matGetFloat*(ih: PIhandle, name: cstring, lin, col: cint): cfloat {. + cdecl, importc: "IupMatGetFloat", dynlib: dllname.} +proc matSetfAttribute*(ih: PIhandle, name: cstring, lin, col: cint, format: cstring) {.cdecl, importc: "IupMatSetfAttribute", - dynlib: dllname, varargs.} - -# Used by IupColorbar + dynlib: dllname, varargs.} + +# Used by IupColorbar const - IUP_PRIMARY* = -1 - IUP_SECONDARY* = -2 - -# Initialize PPlot widget class -proc PPlotOpen*() {.cdecl, importc: "IupPPlotOpen", dynlib: dllname.} - -# Create an PPlot widget instance -proc PPlot*: PIhandle {.cdecl, importc: "IupPPlot", dynlib: dllname.} - -# Add dataset to plot -proc PPlotBegin*(ih: PIhandle, strXdata: cint) {. - cdecl, importc: "IupPPlotBegin", dynlib: dllname.} -proc PPlotAdd*(ih: PIhandle, x, y: cfloat) {. - cdecl, importc: "IupPPlotAdd", dynlib: dllname.} -proc PPlotAddStr*(ih: PIhandle, x: cstring, y: cfloat) {. - cdecl, importc: "IupPPlotAddStr", dynlib: dllname.} -proc PPlotEnd*(ih: PIhandle): cint {. - cdecl, importc: "IupPPlotEnd", dynlib: dllname.} - -proc PPlotInsertStr*(ih: PIhandle, index, sample_index: cint, x: cstring, + IUP_PRIMARY* = -1 + IUP_SECONDARY* = -2 + +# Initialize PPlot widget class +proc pPlotOpen*() {.cdecl, importc: "IupPPlotOpen", dynlib: dllname.} + +# Create an PPlot widget instance +proc pPlot*: PIhandle {.cdecl, importc: "IupPPlot", dynlib: dllname.} + +# Add dataset to plot +proc pPlotBegin*(ih: PIhandle, strXdata: cint) {. + cdecl, importc: "IupPPlotBegin", dynlib: dllname.} +proc pPlotAdd*(ih: PIhandle, x, y: cfloat) {. + cdecl, importc: "IupPPlotAdd", dynlib: dllname.} +proc pPlotAddStr*(ih: PIhandle, x: cstring, y: cfloat) {. + cdecl, importc: "IupPPlotAddStr", dynlib: dllname.} +proc pPlotEnd*(ih: PIhandle): cint {. + cdecl, importc: "IupPPlotEnd", dynlib: dllname.} + +proc pPlotInsertStr*(ih: PIhandle, index, sampleIndex: cint, x: cstring, y: cfloat) {.cdecl, importc: "IupPPlotInsertStr", - dynlib: dllname.} -proc PPlotInsert*(ih: PIhandle, index, sample_index: cint, + dynlib: dllname.} +proc pPlotInsert*(ih: PIhandle, index, sampleIndex: cint, x, y: cfloat) {. - cdecl, importc: "IupPPlotInsert", dynlib: dllname.} - -# convert from plot coordinates to pixels -proc PPlotTransform*(ih: PIhandle, x, y: cfloat, ix, iy: var cint) {. - cdecl, importc: "IupPPlotTransform", dynlib: dllname.} - -# Plot on the given device. Uses a "cdCanvas*". -proc PPlotPaintTo*(ih: PIhandle, cnv: pointer) {. - cdecl, importc: "IupPPlotPaintTo", dynlib: dllname.} - + cdecl, importc: "IupPPlotInsert", dynlib: dllname.} + +# convert from plot coordinates to pixels +proc pPlotTransform*(ih: PIhandle, x, y: cfloat, ix, iy: var cint) {. + cdecl, importc: "IupPPlotTransform", dynlib: dllname.} + +# Plot on the given device. Uses a "cdCanvas*". +proc pPlotPaintTo*(ih: PIhandle, cnv: pointer) {. + cdecl, importc: "IupPPlotPaintTo", dynlib: dllname.} + diff --git a/lib/wrappers/libcurl.nim b/lib/wrappers/libcurl.nim index bd8616759..8c962f6cb 100644 --- a/lib/wrappers/libcurl.nim +++ b/lib/wrappers/libcurl.nim @@ -43,10 +43,10 @@ type Pinfotype* = ptr Tinfotype Plock_access* = ptr Tlock_access Plock_data* = ptr Tlock_data - Pmalloc_callback* = ptr tmalloc_callback + Pmalloc_callback* = ptr Tmalloc_callback PNETRC_OPTION* = ptr TNETRC_OPTION Pproxytype* = ptr Tproxytype - Prealloc_callback* = ptr trealloc_callback + Prealloc_callback* = ptr Trealloc_callback Pslist* = ptr Tslist Psocket* = ptr Tsocket PSSL_VERSION* = ptr TSSL_VERSION @@ -309,7 +309,7 @@ type TMsg*{.pure, final.} = object msg*: TMSGEnum easy_handle*: PCurl - whatever*: Pointer #data : record + whatever*: pointer #data : record # case longint of # 0 : ( whatever : pointer ); # 1 : ( result : CURLcode ); @@ -442,7 +442,7 @@ proc slist_append*(slist: Pslist, p: cstring): Pslist{.cdecl, dynlib: libname, importc: "curl_slist_append".} proc slist_free_all*(para1: Pslist){.cdecl, dynlib: libname, importc: "curl_slist_free_all".} -proc getdate*(p: cstring, unused: ptr TTime): TTime{.cdecl, dynlib: libname, +proc getdate*(p: cstring, unused: ptr Time): Time{.cdecl, dynlib: libname, importc: "curl_getdate".} proc share_init*(): PSH{.cdecl, dynlib: libname, importc: "curl_share_init".} proc share_setopt*(para1: PSH, option: TSHoption): TSHcode{.cdecl, varargs, diff --git a/lib/wrappers/libsvm.nim b/lib/wrappers/libsvm.nim index 8dec05bcf..00d5ac73c 100644 --- a/lib/wrappers/libsvm.nim +++ b/lib/wrappers/libsvm.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/wrappers/mysql.nim b/lib/wrappers/mysql.nim index 84d70287f..945e09ecf 100644 --- a/lib/wrappers/mysql.nim +++ b/lib/wrappers/mysql.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this @@ -729,7 +729,7 @@ type len*: int # output length pointer is_null*: Pmy_bool # Pointer to null indicator buffer*: pointer # buffer to get/put data - error*: pmy_bool # set this if you want to track data truncations happened during fetch + error*: PMy_bool # set this if you want to track data truncations happened during fetch buffer_type*: Tenum_field_types # buffer type buffer_length*: int # buffer length, must be set for str/binary # Following are for internal use. Set by mysql_stmt_bind_param @@ -904,7 +904,7 @@ proc shutdown*(MySQL: PMySQL, shutdown_level: Tenum_shutdown_level): cint{.stdca dynlib: lib, importc: "mysql_shutdown".} proc dump_debug_info*(MySQL: PMySQL): cint{.stdcall, dynlib: lib, importc: "mysql_dump_debug_info".} -proc refresh*(MySQL: PMySQL, refresh_options: cuint): cint{.stdcall, dynlib: lib, +proc refresh*(sql: PMySQL, refresh_options: cuint): cint{.stdcall, dynlib: lib, importc: "mysql_refresh".} proc kill*(MySQL: PMySQL, pid: int): cint{.stdcall, dynlib: lib, importc: "mysql_kill".} proc set_server_option*(MySQL: PMySQL, option: Tenum_mysql_set_option): cint{.stdcall, @@ -1040,7 +1040,7 @@ const NO_DATA* = 100 DATA_TRUNCATED* = 101 -proc reload*(MySQL: PMySQL): cint +proc reload*(x: PMySQL): cint when defined(USE_OLD_FUNCTIONS): proc connect*(MySQL: PMySQL, host: cstring, user: cstring, passwd: cstring): PMySQL{.stdcall, dynlib: lib, importc: "mysql_connect".} @@ -1059,7 +1059,7 @@ proc IS_NOT_NULL(n: int32): bool = proc IS_BLOB(n: int32): bool = result = (n and BLOB_FLAG) != 0 -proc IS_NUM_FIELD(f: pst_mysql_field): bool = +proc IS_NUM_FIELD(f: Pst_mysql_field): bool = result = (f.flags and NUM_FLAG) != 0 proc IS_NUM(t: Tenum_field_types): bool = @@ -1071,7 +1071,7 @@ proc INTERNAL_NUM_FIELD(f: Pst_mysql_field): bool = ((f.ftype != FIELD_TYPE_TIMESTAMP) or (f.len == 14) or (f.len == 8)) or (f.ftype == FIELD_TYPE_YEAR) -proc reload(mysql: PMySQL): cint = - result = refresh(mysql, REFRESH_GRANT) +proc reload(x: PMySQL): cint = + result = refresh(x, REFRESH_GRANT) {.pop.} diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 4dc71bffd..abdfcdb52 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -45,7 +45,7 @@ when defined(WINDOWS): const DLLSSLName = "(ssleay32|libssl32).dll" DLLUtilName = "libeay32.dll" - from winlean import TSocketHandle + from winlean import SocketHandle else: const versions = "(|.1.0.0|.0.9.9|.0.9.8|.0.9.7|.0.9.6|.0.9.5|.0.9.4)" @@ -57,20 +57,19 @@ else: const DLLSSLName = "libssl.so" & versions DLLUtilName = "libcrypto.so" & versions - from posix import TSocketHandle + from posix import SocketHandle type SslStruct {.final, pure.} = object SslPtr* = ptr SslStruct PSslPtr* = ptr SslPtr - PSSL_CTX* = SslPtr - PSSL* = SslPtr + SslCtx* = SslPtr PSSL_METHOD* = SslPtr PX509* = SslPtr PX509_NAME* = SslPtr PEVP_MD* = SslPtr PBIO_METHOD* = SslPtr - PBIO* = SslPtr + BIO* = SslPtr EVP_PKEY* = SslPtr PRSA* = SslPtr PASN1_UTCTIME* = SslPtr @@ -85,6 +84,8 @@ type des_key_schedule* = array[1..16, des_ks_struct] +{.deprecated: [PSSL: SslPtr, PSSL_CTX: SslCtx, PBIO: BIO].} + const EVP_MAX_MD_SIZE* = 16 + 20 SSL_ERROR_NONE* = 0 @@ -206,58 +207,59 @@ proc SSLv2_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} proc SSLv3_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_new*(context: PSSL_CTX): PSSL{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_free*(ssl: PSSL){.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_new*(meth: PSSL_METHOD): PSSL_CTX{.cdecl, +proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_free*(ssl: SslPtr){.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_new*(meth: PSSL_METHOD): SslCtx{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_load_verify_locations*(ctx: PSSL_CTX, CAfile: cstring, +proc SSL_CTX_load_verify_locations*(ctx: SslCtx, CAfile: cstring, CApath: cstring): cInt{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_free*(arg0: PSSL_CTX){.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_set_verify*(s: PSSL_CTX, mode: int, cb: proc (a: int, b: pointer): int {.cdecl.}){.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_get_verify_result*(ssl: PSSL): int{.cdecl, +proc SSL_CTX_free*(arg0: SslCtx){.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_set_verify*(s: SslCtx, mode: int, cb: proc (a: int, b: pointer): int {.cdecl.}){.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_get_verify_result*(ssl: SslPtr): int{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_set_cipher_list*(s: PSSLCTX, ciphers: cstring): cint{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_use_certificate_file*(ctx: PSSL_CTX, filename: cstring, typ: cInt): cInt{. +proc SSL_CTX_set_cipher_list*(s: SslCtx, ciphers: cstring): cint{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_CTX_use_certificate_file*(ctx: SslCtx, filename: cstring, typ: cInt): cInt{. stdcall, dynlib: DLLSSLName, importc.} -proc SSL_CTX_use_certificate_chain_file*(ctx: PSSL_CTX, filename: cstring): cInt{. +proc SSL_CTX_use_certificate_chain_file*(ctx: SslCtx, filename: cstring): cInt{. stdcall, dynlib: DLLSSLName, importc.} -proc SSL_CTX_use_PrivateKey_file*(ctx: PSSL_CTX, +proc SSL_CTX_use_PrivateKey_file*(ctx: SslCtx, filename: cstring, typ: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_CTX_check_private_key*(ctx: PSSL_CTX): cInt{.cdecl, dynlib: DLLSSLName, +proc SSL_CTX_check_private_key*(ctx: SslCtx): cInt{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_set_fd*(ssl: PSSL, fd: TSocketHandle): cint{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_set_fd*(ssl: SslPtr, fd: SocketHandle): cint{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_shutdown*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_connect*(ssl: PSSL): cint{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_read*(ssl: PSSL, buf: pointer, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_write*(ssl: PSSL, buf: cstring, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_get_error*(s: PSSL, ret_code: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_accept*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.} -proc SSL_pending*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_shutdown*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_connect*(ssl: SslPtr): cint{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_read*(ssl: SslPtr, buf: pointer, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_write*(ssl: SslPtr, buf: cstring, num: int): cint{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_get_error*(s: SslPtr, ret_code: cInt): cInt{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_accept*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.} +proc SSL_pending*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.} -proc BIO_new_ssl_connect*(ctx: PSSL_CTX): PBIO{.cdecl, +proc BIO_new_ssl_connect*(ctx: SslCtx): BIO{.cdecl, dynlib: DLLSSLName, importc.} -proc BIO_ctrl*(bio: PBIO, cmd: cint, larg: int, arg: cstring): int{.cdecl, +proc BIO_ctrl*(bio: BIO, cmd: cint, larg: int, arg: cstring): int{.cdecl, dynlib: DLLSSLName, importc.} -proc BIO_get_ssl*(bio: PBIO, ssl: ptr PSSL): int = +proc BIO_get_ssl*(bio: BIO, ssl: ptr SslPtr): int = return BIO_ctrl(bio, BIO_C_GET_SSL, 0, cast[cstring](ssl)) -proc BIO_set_conn_hostname*(bio: PBIO, name: cstring): int = +proc BIO_set_conn_hostname*(bio: BIO, name: cstring): int = return BIO_ctrl(bio, BIO_C_SET_CONNECT, 0, name) -proc BIO_do_handshake*(bio: PBIO): int = - return BIO_ctrl(bio, BIO_C_DO_STATE_MACHINE, 0, NIL) -proc BIO_do_connect*(bio: PBIO): int = +proc BIO_do_handshake*(bio: BIO): int = + return BIO_ctrl(bio, BIO_C_DO_STATE_MACHINE, 0, nil) +proc BIO_do_connect*(bio: BIO): int = return BIO_do_handshake(bio) -proc BIO_read*(b: PBIO, data: cstring, length: cInt): cInt{.cdecl, - dynlib: DLLUtilName, importc.} -proc BIO_write*(b: PBIO, data: cstring, length: cInt): cInt{.cdecl, - dynlib: DLLUtilName, importc.} +when not defined(nimfix): + proc BIO_read*(b: BIO, data: cstring, length: cInt): cInt{.cdecl, + dynlib: DLLUtilName, importc.} + proc BIO_write*(b: BIO, data: cstring, length: cInt): cInt{.cdecl, + dynlib: DLLUtilName, importc.} -proc BIO_free*(b: PBIO): cInt{.cdecl, dynlib: DLLUtilName, importc.} +proc BIO_free*(b: BIO): cInt{.cdecl, dynlib: DLLUtilName, importc.} -proc ERR_print_errors_fp*(fp: TFile){.cdecl, dynlib: DLLSSLName, importc.} +proc ERR_print_errors_fp*(fp: File){.cdecl, dynlib: DLLSSLName, importc.} proc ERR_error_string*(e: cInt, buf: cstring): cstring{.cdecl, dynlib: DLLUtilName, importc.} @@ -276,12 +278,40 @@ proc CRYPTO_malloc_init*() = when not defined(windows): CRYPTO_set_mem_functions(alloc, realloc, dealloc) -proc SSL_CTX_ctrl*(ctx: PSSL_CTX, cmd: cInt, larg: int, parg: pointer): int{. +proc SSL_CTX_ctrl*(ctx: SslCtx, cmd: cInt, larg: int, parg: pointer): int{. cdecl, dynlib: DLLSSLName, importc.} -proc SSLCTXSetMode*(ctx: PSSL_CTX, mode: int): int = +proc SSLCTXSetMode*(ctx: SslCtx, mode: int): int = result = SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, mode, nil) +proc bioNew*(b: PBIO_METHOD): BIO{.cdecl, dynlib: DLLUtilName, importc: "BIO_new".} +proc bioFreeAll*(b: BIO){.cdecl, dynlib: DLLUtilName, importc: "BIO_free_all".} +proc bioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc: "BIO_s_mem".} +proc bioCtrlPending*(b: BIO): cInt{.cdecl, dynlib: DLLUtilName, importc: "BIO_ctrl_pending".} +proc bioRead*(b: BIO, Buf: cstring, length: cInt): cInt{.cdecl, + dynlib: DLLUtilName, importc: "BIO_read".} +proc bioWrite*(b: BIO, Buf: cstring, length: cInt): cInt{.cdecl, + dynlib: DLLUtilName, importc: "BIO_write".} + +proc sslSetConnectState*(s: SslPtr) {.cdecl, + dynlib: DLLSSLName, importc: "SSL_set_connect_state".} +proc sslSetAcceptState*(s: SslPtr) {.cdecl, + dynlib: DLLSSLName, importc: "SSL_set_accept_state".} + +proc sslRead*(ssl: SslPtr, buf: cstring, num: cInt): cInt{.cdecl, + dynlib: DLLSSLName, importc: "SSL_read".} +proc sslPeek*(ssl: SslPtr, buf: cstring, num: cInt): cInt{.cdecl, + dynlib: DLLSSLName, importc: "SSL_peek".} +proc sslWrite*(ssl: SslPtr, buf: cstring, num: cInt): cInt{.cdecl, + dynlib: DLLSSLName, importc: "SSL_write".} + +proc sslSetBio*(ssl: SslPtr, rbio, wbio: BIO) {.cdecl, + dynlib: DLLSSLName, importc: "SSL_set_bio".} + +proc sslDoHandshake*(ssl: SslPtr): cint {.cdecl, + dynlib: DLLSSLName, importc: "SSL_do_handshake".} + + when true: discard else: @@ -328,12 +358,7 @@ else: proc SslConnect*(ssl: PSSL): cInt{.cdecl, dynlib: DLLSSLName, importc.} - proc SslRead*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl, - dynlib: DLLSSLName, importc.} - proc SslPeek*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl, - dynlib: DLLSSLName, importc.} - proc SslWrite*(ssl: PSSL, buf: SslPtr, num: cInt): cInt{.cdecl, - dynlib: DLLSSLName, importc.} + proc SslGetVersion*(ssl: PSSL): cstring{.cdecl, dynlib: DLLSSLName, importc.} proc SslGetPeerCertificate*(ssl: PSSL): PX509{.cdecl, dynlib: DLLSSLName, importc.} @@ -393,14 +418,7 @@ else: proc OPENSSLaddallalgorithms*(){.cdecl, dynlib: DLLUtilName, importc.} proc CRYPTOcleanupAllExData*(){.cdecl, dynlib: DLLUtilName, importc.} proc RandScreen*(){.cdecl, dynlib: DLLUtilName, importc.} - proc BioNew*(b: PBIO_METHOD): PBIO{.cdecl, dynlib: DLLUtilName, importc.} - proc BioFreeAll*(b: PBIO){.cdecl, dynlib: DLLUtilName, importc.} - proc BioSMem*(): PBIO_METHOD{.cdecl, dynlib: DLLUtilName, importc.} - proc BioCtrlPending*(b: PBIO): cInt{.cdecl, dynlib: DLLUtilName, importc.} - proc BioRead*(b: PBIO, Buf: cstring, length: cInt): cInt{.cdecl, - dynlib: DLLUtilName, importc.} - proc BioWrite*(b: PBIO, Buf: cstring, length: cInt): cInt{.cdecl, - dynlib: DLLUtilName, importc.} + proc d2iPKCS12bio*(b: PBIO, Pkcs12: SslPtr): SslPtr{.cdecl, dynlib: DLLUtilName, importc.} proc PKCS12parse*(p12: SslPtr, pass: cstring, pkey, cert, ca: var SslPtr): cint{. @@ -448,11 +466,11 @@ type {.pragma: ic, importc: "$1".} {.push callconv:cdecl, dynlib:DLLUtilName.} -proc MD5_Init*(c: var MD5_CTX): cint{.ic.} -proc MD5_Update*(c: var MD5_CTX; data: pointer; len: csize): cint{.ic.} -proc MD5_Final*(md: cstring; c: var MD5_CTX): cint{.ic.} -proc MD5*(d: ptr cuchar; n: csize; md: ptr cuchar): ptr cuchar{.ic.} -proc MD5_Transform*(c: var MD5_CTX; b: ptr cuchar){.ic.} +proc md5_Init*(c: var MD5_CTX): cint{.ic.} +proc md5_Update*(c: var MD5_CTX; data: pointer; len: csize): cint{.ic.} +proc md5_Final*(md: cstring; c: var MD5_CTX): cint{.ic.} +proc md5*(d: ptr cuchar; n: csize; md: ptr cuchar): ptr cuchar{.ic.} +proc md5_Transform*(c: var MD5_CTX; b: ptr cuchar){.ic.} {.pop.} from strutils import toHex,toLower @@ -463,7 +481,7 @@ proc hexStr (buf:cstring): string = for i in 0 .. <16: result.add toHex(buf[i].ord, 2).toLower -proc MD5_File* (file: string): string {.raises:[EIO,Ebase].} = +proc md5_File* (file: string): string {.raises: [IOError,Exception].} = ## Generate MD5 hash for a file. Result is a 32 character # hex string with lowercase characters (like the output # of `md5sum` @@ -483,7 +501,7 @@ proc MD5_File* (file: string): string {.raises:[EIO,Ebase].} = result = hexStr(buf) -proc MD5_Str* (str:string): string {.raises:[EIO].} = +proc md5_Str* (str:string): string {.raises:[IOError].} = ##Generate MD5 hash for a string. Result is a 32 character #hex string with lowercase characters var diff --git a/lib/wrappers/pdcurses.nim b/lib/wrappers/pdcurses.nim index a53289bce..bed69648a 100644 --- a/lib/wrappers/pdcurses.nim +++ b/lib/wrappers/pdcurses.nim @@ -741,7 +741,7 @@ proc getbkgd*(a2: ptr TWINDOW): cunsignedlong{.extdecl, importc: "getbkgd", proc getnstr*(a2: cstring; a3: cint): cint{.extdecl, importc: "getnstr", dynlib: pdcursesdll.} proc getstr*(a2: cstring): cint{.extdecl, importc: "getstr", dynlib: pdcursesdll.} -proc getwin*(a2: TFile): ptr TWINDOW{.extdecl, importc: "getwin", +proc getwin*(a2: File): ptr TWINDOW{.extdecl, importc: "getwin", dynlib: pdcursesdll.} proc halfdelay*(a2: cint): cint{.extdecl, importc: "halfdelay", dynlib: pdcursesdll.} @@ -895,7 +895,7 @@ proc mvwvline*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cunsignedlong; a6: cint) proc napms*(a2: cint): cint{.extdecl, importc: "napms", dynlib: pdcursesdll.} proc newpad*(a2: cint; a3: cint): ptr TWINDOW{.extdecl, importc: "newpad", dynlib: pdcursesdll.} -proc newterm*(a2: cstring; a3: TFile; a4: TFile): ptr TSCREEN{.extdecl, +proc newterm*(a2: cstring; a3: File; a4: File): ptr TSCREEN{.extdecl, importc: "newterm", dynlib: pdcursesdll.} proc newwin*(a2: cint; a3: cint; a4: cint; a5: cint): ptr TWINDOW{.extdecl, importc: "newwin", dynlib: pdcursesdll.} @@ -924,7 +924,7 @@ proc prefresh*(a2: ptr TWINDOW; a3: cint; a4: cint; a5: cint; a6: cint; a7: cint a8: cint): cint{.extdecl, importc: "prefresh", dynlib: pdcursesdll.} proc printw*(a2: cstring): cint{.varargs, extdecl, importc: "printw", dynlib: pdcursesdll.} -proc putwin*(a2: ptr TWINDOW; a3: TFile): cint{.extdecl, importc: "putwin", +proc putwin*(a2: ptr TWINDOW; a3: File): cint{.extdecl, importc: "putwin", dynlib: pdcursesdll.} proc qiflush*(){.extdecl, importc: "qiflush", dynlib: pdcursesdll.} proc raw*(): cint{.extdecl, importc: "raw", dynlib: pdcursesdll.} diff --git a/lib/wrappers/postgres.nim b/lib/wrappers/postgres.nim index ce78d3435..cb39c41bb 100644 --- a/lib/wrappers/postgres.nim +++ b/lib/wrappers/postgres.nim @@ -68,9 +68,9 @@ type dbName*: cstring status*: TConnStatusType errorMessage*: array[0..(ERROR_MSG_LENGTH) - 1, char] - Pfin*: TFile - Pfout*: TFile - Pfdebug*: TFile + Pfin*: File + Pfout*: File + Pfdebug*: File sock*: int32 laddr*: TSockAddr raddr*: TSockAddr @@ -145,184 +145,184 @@ type p*: pointer -proc PQconnectStart*(conninfo: cstring): PPGconn{.cdecl, dynlib: dllName, +proc pqconnectStart*(conninfo: cstring): PPGconn{.cdecl, dynlib: dllName, importc: "PQconnectStart".} -proc PQconnectPoll*(conn: PPGconn): PostgresPollingStatusType{.cdecl, +proc pqconnectPoll*(conn: PPGconn): PostgresPollingStatusType{.cdecl, dynlib: dllName, importc: "PQconnectPoll".} -proc PQconnectdb*(conninfo: cstring): PPGconn{.cdecl, dynlib: dllName, +proc pqconnectdb*(conninfo: cstring): PPGconn{.cdecl, dynlib: dllName, importc: "PQconnectdb".} -proc PQsetdbLogin*(pghost: cstring, pgport: cstring, pgoptions: cstring, +proc pqsetdbLogin*(pghost: cstring, pgport: cstring, pgoptions: cstring, pgtty: cstring, dbName: cstring, login: cstring, pwd: cstring): PPGconn{. cdecl, dynlib: dllName, importc: "PQsetdbLogin".} -proc PQsetdb*(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME: cstring): ppgconn -proc PQfinish*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQfinish".} -proc PQconndefaults*(): PPQconninfoOption{.cdecl, dynlib: dllName, +proc pqsetdb*(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME: cstring): Ppgconn +proc pqfinish*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQfinish".} +proc pqconndefaults*(): PPQconninfoOption{.cdecl, dynlib: dllName, importc: "PQconndefaults".} -proc PQconninfoFree*(connOptions: PPQconninfoOption){.cdecl, dynlib: dllName, +proc pqconninfoFree*(connOptions: PPQconninfoOption){.cdecl, dynlib: dllName, importc: "PQconninfoFree".} -proc PQresetStart*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqresetStart*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQresetStart".} -proc PQresetPoll*(conn: PPGconn): PostgresPollingStatusType{.cdecl, +proc pqresetPoll*(conn: PPGconn): PostgresPollingStatusType{.cdecl, dynlib: dllName, importc: "PQresetPoll".} -proc PQreset*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQreset".} -proc PQrequestCancel*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqreset*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQreset".} +proc pqrequestCancel*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQrequestCancel".} -proc PQdb*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQdb".} -proc PQuser*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQuser".} -proc PQpass*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQpass".} -proc PQhost*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQhost".} -proc PQport*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQport".} -proc PQtty*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQtty".} -proc PQoptions*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, +proc pqdb*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQdb".} +proc pquser*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQuser".} +proc pqpass*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQpass".} +proc pqhost*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQhost".} +proc pqport*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQport".} +proc pqtty*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQtty".} +proc pqoptions*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQoptions".} -proc PQstatus*(conn: PPGconn): TConnStatusType{.cdecl, dynlib: dllName, +proc pqstatus*(conn: PPGconn): TConnStatusType{.cdecl, dynlib: dllName, importc: "PQstatus".} -proc PQtransactionStatus*(conn: PPGconn): PGTransactionStatusType{.cdecl, +proc pqtransactionStatus*(conn: PPGconn): PGTransactionStatusType{.cdecl, dynlib: dllName, importc: "PQtransactionStatus".} -proc PQparameterStatus*(conn: PPGconn, paramName: cstring): cstring{.cdecl, +proc pqparameterStatus*(conn: PPGconn, paramName: cstring): cstring{.cdecl, dynlib: dllName, importc: "PQparameterStatus".} -proc PQprotocolVersion*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqprotocolVersion*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQprotocolVersion".} -proc PQerrorMessage*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, +proc pqerrorMessage*(conn: PPGconn): cstring{.cdecl, dynlib: dllName, importc: "PQerrorMessage".} -proc PQsocket*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqsocket*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQsocket".} -proc PQbackendPID*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqbackendPID*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQbackendPID".} -proc PQclientEncoding*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqclientEncoding*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQclientEncoding".} -proc PQsetClientEncoding*(conn: PPGconn, encoding: cstring): int32{.cdecl, +proc pqsetClientEncoding*(conn: PPGconn, encoding: cstring): int32{.cdecl, dynlib: dllName, importc: "PQsetClientEncoding".} when defined(USE_SSL): # Get the SSL structure associated with a connection - proc PQgetssl*(conn: PPGconn): PSSL{.cdecl, dynlib: dllName, + proc pqgetssl*(conn: PPGconn): PSSL{.cdecl, dynlib: dllName, importc: "PQgetssl".} -proc PQsetErrorVerbosity*(conn: PPGconn, verbosity: PGVerbosity): PGVerbosity{. +proc pqsetErrorVerbosity*(conn: PPGconn, verbosity: PGVerbosity): PGVerbosity{. cdecl, dynlib: dllName, importc: "PQsetErrorVerbosity".} -proc PQtrace*(conn: PPGconn, debug_port: TFile){.cdecl, dynlib: dllName, +proc pqtrace*(conn: PPGconn, debug_port: File){.cdecl, dynlib: dllName, importc: "PQtrace".} -proc PQuntrace*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQuntrace".} -proc PQsetNoticeReceiver*(conn: PPGconn, theProc: PQnoticeReceiver, arg: pointer): PQnoticeReceiver{. +proc pquntrace*(conn: PPGconn){.cdecl, dynlib: dllName, importc: "PQuntrace".} +proc pqsetNoticeReceiver*(conn: PPGconn, theProc: PQnoticeReceiver, arg: pointer): PQnoticeReceiver{. cdecl, dynlib: dllName, importc: "PQsetNoticeReceiver".} -proc PQsetNoticeProcessor*(conn: PPGconn, theProc: PQnoticeProcessor, +proc pqsetNoticeProcessor*(conn: PPGconn, theProc: PQnoticeProcessor, arg: pointer): PQnoticeProcessor{.cdecl, dynlib: dllName, importc: "PQsetNoticeProcessor".} -proc PQexec*(conn: PPGconn, query: cstring): PPGresult{.cdecl, dynlib: dllName, +proc pqexec*(conn: PPGconn, query: cstring): PPGresult{.cdecl, dynlib: dllName, importc: "PQexec".} -proc PQexecParams*(conn: PPGconn, command: cstring, nParams: int32, +proc pqexecParams*(conn: PPGconn, command: cstring, nParams: int32, paramTypes: POid, paramValues: cstringArray, paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{. cdecl, dynlib: dllName, importc: "PQexecParams".} -proc PQprepare*(conn: PPGconn, stmtName, query: cstring, nParams: int32, +proc pqprepare*(conn: PPGconn, stmtName, query: cstring, nParams: int32, paramTypes: POid): PPGresult{.cdecl, dynlib: dllName, importc: "PQprepare".} -proc PQexecPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32, - paramValues: cstringArray, +proc pqexecPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32, + paramValues: cstringArray, paramLengths, paramFormats: ptr int32, resultFormat: int32): PPGresult{. cdecl, dynlib: dllName, importc: "PQexecPrepared".} -proc PQsendQuery*(conn: PPGconn, query: cstring): int32{.cdecl, dynlib: dllName, +proc pqsendQuery*(conn: PPGconn, query: cstring): int32{.cdecl, dynlib: dllName, importc: "PQsendQuery".} -proc PQsendQueryParams*(conn: PPGconn, command: cstring, nParams: int32, +proc pqsendQueryParams*(conn: PPGconn, command: cstring, nParams: int32, paramTypes: POid, paramValues: cstringArray, paramLengths, paramFormats: ptr int32, resultFormat: int32): int32{.cdecl, dynlib: dllName, importc: "PQsendQueryParams".} -proc PQsendQueryPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32, +proc pqsendQueryPrepared*(conn: PPGconn, stmtName: cstring, nParams: int32, paramValues: cstringArray, paramLengths, paramFormats: ptr int32, resultFormat: int32): int32{.cdecl, dynlib: dllName, importc: "PQsendQueryPrepared".} -proc PQgetResult*(conn: PPGconn): PPGresult{.cdecl, dynlib: dllName, +proc pqgetResult*(conn: PPGconn): PPGresult{.cdecl, dynlib: dllName, importc: "PQgetResult".} -proc PQisBusy*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqisBusy*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQisBusy".} -proc PQconsumeInput*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqconsumeInput*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQconsumeInput".} -proc PQnotifies*(conn: PPGconn): PPGnotify{.cdecl, dynlib: dllName, +proc pqnotifies*(conn: PPGconn): PPGnotify{.cdecl, dynlib: dllName, importc: "PQnotifies".} -proc PQputCopyData*(conn: PPGconn, buffer: cstring, nbytes: int32): int32{. +proc pqputCopyData*(conn: PPGconn, buffer: cstring, nbytes: int32): int32{. cdecl, dynlib: dllName, importc: "PQputCopyData".} -proc PQputCopyEnd*(conn: PPGconn, errormsg: cstring): int32{.cdecl, +proc pqputCopyEnd*(conn: PPGconn, errormsg: cstring): int32{.cdecl, dynlib: dllName, importc: "PQputCopyEnd".} -proc PQgetCopyData*(conn: PPGconn, buffer: cstringArray, async: int32): int32{. +proc pqgetCopyData*(conn: PPGconn, buffer: cstringArray, async: int32): int32{. cdecl, dynlib: dllName, importc: "PQgetCopyData".} -proc PQgetline*(conn: PPGconn, str: cstring, len: int32): int32{.cdecl, +proc pqgetline*(conn: PPGconn, str: cstring, len: int32): int32{.cdecl, dynlib: dllName, importc: "PQgetline".} -proc PQputline*(conn: PPGconn, str: cstring): int32{.cdecl, dynlib: dllName, +proc pqputline*(conn: PPGconn, str: cstring): int32{.cdecl, dynlib: dllName, importc: "PQputline".} -proc PQgetlineAsync*(conn: PPGconn, buffer: cstring, bufsize: int32): int32{. +proc pqgetlineAsync*(conn: PPGconn, buffer: cstring, bufsize: int32): int32{. cdecl, dynlib: dllName, importc: "PQgetlineAsync".} -proc PQputnbytes*(conn: PPGconn, buffer: cstring, nbytes: int32): int32{.cdecl, +proc pqputnbytes*(conn: PPGconn, buffer: cstring, nbytes: int32): int32{.cdecl, dynlib: dllName, importc: "PQputnbytes".} -proc PQendcopy*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqendcopy*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQendcopy".} -proc PQsetnonblocking*(conn: PPGconn, arg: int32): int32{.cdecl, +proc pqsetnonblocking*(conn: PPGconn, arg: int32): int32{.cdecl, dynlib: dllName, importc: "PQsetnonblocking".} -proc PQisnonblocking*(conn: PPGconn): int32{.cdecl, dynlib: dllName, +proc pqisnonblocking*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQisnonblocking".} -proc PQflush*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQflush".} -proc PQfn*(conn: PPGconn, fnid: int32, result_buf, result_len: ptr int32, +proc pqflush*(conn: PPGconn): int32{.cdecl, dynlib: dllName, importc: "PQflush".} +proc pqfn*(conn: PPGconn, fnid: int32, result_buf, result_len: ptr int32, result_is_int: int32, args: PPQArgBlock, nargs: int32): PPGresult{. cdecl, dynlib: dllName, importc: "PQfn".} -proc PQresultStatus*(res: PPGresult): TExecStatusType{.cdecl, dynlib: dllName, +proc pqresultStatus*(res: PPGresult): TExecStatusType{.cdecl, dynlib: dllName, importc: "PQresultStatus".} -proc PQresStatus*(status: TExecStatusType): cstring{.cdecl, dynlib: dllName, +proc pqresStatus*(status: TExecStatusType): cstring{.cdecl, dynlib: dllName, importc: "PQresStatus".} -proc PQresultErrorMessage*(res: PPGresult): cstring{.cdecl, dynlib: dllName, +proc pqresultErrorMessage*(res: PPGresult): cstring{.cdecl, dynlib: dllName, importc: "PQresultErrorMessage".} -proc PQresultErrorField*(res: PPGresult, fieldcode: int32): cstring{.cdecl, +proc pqresultErrorField*(res: PPGresult, fieldcode: int32): cstring{.cdecl, dynlib: dllName, importc: "PQresultErrorField".} -proc PQntuples*(res: PPGresult): int32{.cdecl, dynlib: dllName, +proc pqntuples*(res: PPGresult): int32{.cdecl, dynlib: dllName, importc: "PQntuples".} -proc PQnfields*(res: PPGresult): int32{.cdecl, dynlib: dllName, +proc pqnfields*(res: PPGresult): int32{.cdecl, dynlib: dllName, importc: "PQnfields".} -proc PQbinaryTuples*(res: PPGresult): int32{.cdecl, dynlib: dllName, +proc pqbinaryTuples*(res: PPGresult): int32{.cdecl, dynlib: dllName, importc: "PQbinaryTuples".} -proc PQfname*(res: PPGresult, field_num: int32): cstring{.cdecl, +proc pqfname*(res: PPGresult, field_num: int32): cstring{.cdecl, dynlib: dllName, importc: "PQfname".} -proc PQfnumber*(res: PPGresult, field_name: cstring): int32{.cdecl, +proc pqfnumber*(res: PPGresult, field_name: cstring): int32{.cdecl, dynlib: dllName, importc: "PQfnumber".} -proc PQftable*(res: PPGresult, field_num: int32): Oid{.cdecl, dynlib: dllName, +proc pqftable*(res: PPGresult, field_num: int32): Oid{.cdecl, dynlib: dllName, importc: "PQftable".} -proc PQftablecol*(res: PPGresult, field_num: int32): int32{.cdecl, +proc pqftablecol*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, importc: "PQftablecol".} -proc PQfformat*(res: PPGresult, field_num: int32): int32{.cdecl, +proc pqfformat*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, importc: "PQfformat".} -proc PQftype*(res: PPGresult, field_num: int32): Oid{.cdecl, dynlib: dllName, +proc pqftype*(res: PPGresult, field_num: int32): Oid{.cdecl, dynlib: dllName, importc: "PQftype".} -proc PQfsize*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, +proc pqfsize*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, importc: "PQfsize".} -proc PQfmod*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, +proc pqfmod*(res: PPGresult, field_num: int32): int32{.cdecl, dynlib: dllName, importc: "PQfmod".} -proc PQcmdStatus*(res: PPGresult): cstring{.cdecl, dynlib: dllName, +proc pqcmdStatus*(res: PPGresult): cstring{.cdecl, dynlib: dllName, importc: "PQcmdStatus".} -proc PQoidStatus*(res: PPGresult): cstring{.cdecl, dynlib: dllName, +proc pqoidStatus*(res: PPGresult): cstring{.cdecl, dynlib: dllName, importc: "PQoidStatus".} -proc PQoidValue*(res: PPGresult): Oid{.cdecl, dynlib: dllName, +proc pqoidValue*(res: PPGresult): Oid{.cdecl, dynlib: dllName, importc: "PQoidValue".} -proc PQcmdTuples*(res: PPGresult): cstring{.cdecl, dynlib: dllName, +proc pqcmdTuples*(res: PPGresult): cstring{.cdecl, dynlib: dllName, importc: "PQcmdTuples".} -proc PQgetvalue*(res: PPGresult, tup_num: int32, field_num: int32): cstring{. +proc pqgetvalue*(res: PPGresult, tup_num: int32, field_num: int32): cstring{. cdecl, dynlib: dllName, importc: "PQgetvalue".} -proc PQgetlength*(res: PPGresult, tup_num: int32, field_num: int32): int32{. +proc pqgetlength*(res: PPGresult, tup_num: int32, field_num: int32): int32{. cdecl, dynlib: dllName, importc: "PQgetlength".} -proc PQgetisnull*(res: PPGresult, tup_num: int32, field_num: int32): int32{. +proc pqgetisnull*(res: PPGresult, tup_num: int32, field_num: int32): int32{. cdecl, dynlib: dllName, importc: "PQgetisnull".} -proc PQclear*(res: PPGresult){.cdecl, dynlib: dllName, importc: "PQclear".} -proc PQfreemem*(p: pointer){.cdecl, dynlib: dllName, importc: "PQfreemem".} -proc PQmakeEmptyPGresult*(conn: PPGconn, status: TExecStatusType): PPGresult{. +proc pqclear*(res: PPGresult){.cdecl, dynlib: dllName, importc: "PQclear".} +proc pqfreemem*(p: pointer){.cdecl, dynlib: dllName, importc: "PQfreemem".} +proc pqmakeEmptyPGresult*(conn: PPGconn, status: TExecStatusType): PPGresult{. cdecl, dynlib: dllName, importc: "PQmakeEmptyPGresult".} -proc PQescapeString*(till, `from`: cstring, len: int): int{.cdecl, +proc pqescapeString*(till, `from`: cstring, len: int): int{.cdecl, dynlib: dllName, importc: "PQescapeString".} -proc PQescapeBytea*(bintext: cstring, binlen: int, bytealen: var int): cstring{. +proc pqescapeBytea*(bintext: cstring, binlen: int, bytealen: var int): cstring{. cdecl, dynlib: dllName, importc: "PQescapeBytea".} -proc PQunescapeBytea*(strtext: cstring, retbuflen: var int): cstring{.cdecl, +proc pqunescapeBytea*(strtext: cstring, retbuflen: var int): cstring{.cdecl, dynlib: dllName, importc: "PQunescapeBytea".} -proc PQprint*(fout: TFile, res: PPGresult, ps: PPQprintOpt){.cdecl, +proc pqprint*(fout: File, res: PPGresult, ps: PPQprintOpt){.cdecl, dynlib: dllName, importc: "PQprint".} -proc PQdisplayTuples*(res: PPGresult, fp: TFile, fillAlign: int32, +proc pqdisplayTuples*(res: PPGresult, fp: File, fillAlign: int32, fieldSep: cstring, printHeader: int32, quiet: int32){. cdecl, dynlib: dllName, importc: "PQdisplayTuples".} -proc PQprintTuples*(res: PPGresult, fout: TFile, printAttName: int32, +proc pqprintTuples*(res: PPGresult, fout: File, printAttName: int32, terseOutput: int32, width: int32){.cdecl, dynlib: dllName, importc: "PQprintTuples".} proc lo_open*(conn: PPGconn, lobjId: Oid, mode: int32): int32{.cdecl, @@ -345,8 +345,8 @@ proc lo_import*(conn: PPGconn, filename: cstring): Oid{.cdecl, dynlib: dllName, importc: "lo_import".} proc lo_export*(conn: PPGconn, lobjId: Oid, filename: cstring): int32{.cdecl, dynlib: dllName, importc: "lo_export".} -proc PQmblen*(s: cstring, encoding: int32): int32{.cdecl, dynlib: dllName, +proc pqmblen*(s: cstring, encoding: int32): int32{.cdecl, dynlib: dllName, importc: "PQmblen".} -proc PQenv2encoding*(): int32{.cdecl, dynlib: dllName, importc: "PQenv2encoding".} -proc PQsetdb(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME: cstring): ppgconn = - result = PQsetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, "", "") +proc pqenv2encoding*(): int32{.cdecl, dynlib: dllName, importc: "PQenv2encoding".} +proc pqsetdb(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME: cstring): PPgConn = + result = pqSetdbLogin(M_PGHOST, M_PGPORT, M_PGOPT, M_PGTTY, M_DBNAME, "", "") diff --git a/lib/wrappers/readline/history.nim b/lib/wrappers/readline/history.nim index 12dfa2707..caa857ceb 100644 --- a/lib/wrappers/readline/history.nim +++ b/lib/wrappers/readline/history.nim @@ -142,7 +142,7 @@ proc history_get*(a2: cint): ptr THIST_ENTRY{.cdecl, importc: "history_get", # Return the timestamp associated with the HIST_ENTRY * passed as an # argument -proc history_get_time*(a2: ptr THIST_ENTRY): TTime{.cdecl, +proc history_get_time*(a2: ptr THIST_ENTRY): Time{.cdecl, importc: "history_get_time", dynlib: historyDll.} # Return the number of bytes that the primary history entries are using. # This just adds up the lengths of the_history->lines. diff --git a/lib/wrappers/readline/readline.nim b/lib/wrappers/readline/readline.nim index bbe416534..5a319243e 100644 --- a/lib/wrappers/readline/readline.nim +++ b/lib/wrappers/readline/readline.nim @@ -776,7 +776,7 @@ proc execute_next*(a2: cint): cint{.cdecl, importc: "rl_execute_next", proc clear_pending_input*(): cint{.cdecl, importc: "rl_clear_pending_input", dynlib: readlineDll.} proc read_key*(): cint{.cdecl, importc: "rl_read_key", dynlib: readlineDll.} -proc getc*(a2: TFile): cint{.cdecl, importc: "rl_getc", dynlib: readlineDll.} +proc getc*(a2: File): cint{.cdecl, importc: "rl_getc", dynlib: readlineDll.} proc set_keyboard_input_timeout*(a2: cint): cint{.cdecl, importc: "rl_set_keyboard_input_timeout", dynlib: readlineDll.} # `Public' utility functions . @@ -881,8 +881,8 @@ when false: # The name of the terminal to use. var terminal_name*{.importc: "rl_terminal_name", dynlib: readlineDll.}: cstring # The input and output streams. - var instream*{.importc: "rl_instream", dynlib: readlineDll.}: TFile - var outstream*{.importc: "rl_outstream", dynlib: readlineDll.}: TFile + var instream*{.importc: "rl_instream", dynlib: readlineDll.}: File + var outstream*{.importc: "rl_outstream", dynlib: readlineDll.}: File # If non-zero, Readline gives values of LINES and COLUMNS from the environment # greater precedence than values fetched from the kernel when computing the # screen dimensions. @@ -1184,8 +1184,8 @@ type insmode*: cint edmode*: cint kseqlen*: cint - inf*: TFile - outf*: TFile + inf*: File + outf*: File pendingin*: cint theMacro*: cstring # signal state catchsigs*: cint diff --git a/lib/wrappers/readline/rltypedefs.nim b/lib/wrappers/readline/rltypedefs.nim index 202cf925d..847834e80 100644 --- a/lib/wrappers/readline/rltypedefs.nim +++ b/lib/wrappers/readline/rltypedefs.nim @@ -48,7 +48,7 @@ type # Input function type type - Tgetc_func* = proc (a2: TFile): cint{.cdecl.} + Tgetc_func* = proc (a2: File): cint{.cdecl.} # Generic function that takes a character buffer (which could be the readline # line buffer) and an index into it (which could be rl_point) and returns diff --git a/lib/wrappers/sdl/sdl.nim b/lib/wrappers/sdl/sdl.nim index 1c88bc14e..449b651f9 100644 --- a/lib/wrappers/sdl/sdl.nim +++ b/lib/wrappers/sdl/sdl.nim @@ -250,14 +250,14 @@ # SDL_GL_MULTISAMPLESAMPLES # # Add DLL/Shared object functions -# function SDL_LoadObject( const sofile : PChar ) : Pointer; +# function SDL_LoadObject( const sofile : PChar ) : pointer; # -# function SDL_LoadFunction( handle : Pointer; const name : PChar ) : Pointer; +# function SDL_LoadFunction( handle : pointer; const name : PChar ) : pointer; # -# procedure SDL_UnloadObject( handle : Pointer ); +# procedure SDL_UnloadObject( handle : pointer ); # # Added function to create RWops from const memory: SDL_RWFromConstMem() -# function SDL_RWFromConstMem(const mem: Pointer; size: Integer) : PSDL_RWops; +# function SDL_RWFromConstMem(const mem: pointer; size: Integer) : PSDL_RWops; # # Ported SDL_cpuinfo.h so Now you can test for Specific CPU types. # @@ -752,12 +752,12 @@ const # Enumeration of valid key mods (possibly OR'd tog type THandle* = int #SDL_types.h types # Basic data types - TBool* = enum + TBool* = enum sdlFALSE, sdlTRUE PUInt8Array* = ptr TUInt8Array TUInt8Array* = array[0..high(int) shr 1, byte] - PUInt16* = ptr UInt16 - PUInt32* = ptr UInt32 + PUInt16* = ptr uint16 + PUInt32* = ptr uint32 PUInt64* = ptr UInt64 UInt64*{.final.} = object hi*: int32 @@ -771,12 +771,12 @@ type TGrabMode* = int32 # SDL_error.h types Terrorcode* = enum ENOMEM, EFREAD, EFWRITE, EFSEEK, LASTERROR - errorcode* = Terrorcode + Errorcode* = Terrorcode TArg*{.final.} = object buf*: array[0..ERR_MAX_STRLEN - 1, int8] Perror* = ptr Terror - Terror*{.final.} = object # This is a numeric value corresponding to the current error + TError*{.final.} = object # This is a numeric value corresponding to the current error # SDL_rwops.h types # This is the read/write operation structure -- very basic # some helper types to handle the unions @@ -790,8 +790,8 @@ type args*: array[0..ERR_MAX_ARGS - 1, TArg] TStdio*{.final.} = object - autoclose*: int # FILE * is only defined in Kylix so we use a simple Pointer - fp*: Pointer + autoclose*: int # FILE * is only defined in Kylix so we use a simple pointer + fp*: pointer TMem*{.final.} = object base*: ptr byte @@ -800,9 +800,9 @@ type PRWops* = ptr TRWops # now the pointer to function types TSeek* = proc (context: PRWops, offset: int, whence: int): int{.cdecl.} - TRead* = proc (context: PRWops, thePtr: Pointer, size: int, maxnum: int): int{. + TRead* = proc (context: PRWops, thePtr: pointer, size: int, maxnum: int): int{. cdecl.} - TWrite* = proc (context: PRWops, thePtr: Pointer, size: int, num: int): int{. + TWrite* = proc (context: PRWops, thePtr: pointer, size: int, num: int): int{. cdecl.} TClose* = proc (context: PRWops): int{.cdecl.} # the variant record itself TRWops*{.final.} = object @@ -817,27 +817,27 @@ type RWops* = TRWops # SDL_timer.h types # Function prototype for the timer callback function TTimerCallback* = proc (interval: int32): int32{.cdecl.} - TNewTimerCallback* = proc (interval: int32, param: Pointer): int32{.cdecl.} + TNewTimerCallback* = proc (interval: int32, param: pointer): int32{.cdecl.} PTimerID* = ptr TTimerID TTimerID*{.final.} = object interval*: int32 callback*: TNewTimerCallback - param*: Pointer - last_alarm*: int32 + param*: pointer + lastAlarm*: int32 next*: PTimerID - TAudioSpecCallback* = proc (userdata: Pointer, stream: ptr byte, length: int){. + TAudioSpecCallback* = proc (userdata: pointer, stream: ptr byte, length: int){. cdecl.} # SDL_audio.h types # The calculated values in this structure are calculated by SDL_OpenAudio() PAudioSpec* = ptr TAudioSpec TAudioSpec*{.final.} = object # A structure to hold a set of audio conversion filters and buffers freq*: int # DSP frequency -- samples per second - format*: UInt16 # Audio data format + format*: uint16 # Audio data format channels*: byte # Number of channels: 1 mono, 2 stereo silence*: byte # Audio buffer silence value (calculated) - samples*: UInt16 # Audio buffer size in samples - padding*: UInt16 # Necessary for some compile environments + samples*: uint16 # Audio buffer size in samples + padding*: uint16 # Necessary for some compile environments size*: int32 # Audio buffer size in bytes (calculated) # This function is called when the audio device needs more data. # 'stream' is a pointer to the audio data buffer @@ -845,28 +845,28 @@ type # Once the callback returns, the buffer will no longer be valid. # Stereo samples are stored in a LRLRLR ordering. callback*: TAudioSpecCallback - userdata*: Pointer + userdata*: pointer PAudioCVT* = ptr TAudioCVT PAudioCVTFilter* = ptr TAudioCVTFilter TAudioCVTFilter*{.final.} = object cvt*: PAudioCVT - format*: UInt16 + format*: uint16 PAudioCVTFilterArray* = ptr TAudioCVTFilterArray TAudioCVTFilterArray* = array[0..9, PAudioCVTFilter] TAudioCVT*{.final.} = object needed*: int # Set to 1 if conversion possible - src_format*: UInt16 # Source audio format - dst_format*: UInt16 # Target audio format - rate_incr*: float64 # Rate conversion increment + srcFormat*: uint16 # Source audio format + dstFormat*: uint16 # Target audio format + rateIncr*: float64 # Rate conversion increment buf*: ptr byte # Buffer to hold entire audio data length*: int # Length of original audio buffer - len_cvt*: int # Length of converted audio buffer - len_mult*: int # buffer must be len*len_mult big - len_ratio*: float64 # Given len, final size is len*len_ratio + lenCvt*: int # Length of converted audio buffer + lenMult*: int # buffer must be len*len_mult big + lenRatio*: float64 # Given len, final size is len*len_ratio filters*: TAudioCVTFilterArray - filter_index*: int # Current audio conversion function + filterIndex*: int # Current audio conversion function TAudiostatus* = enum # SDL_cdrom.h types AUDIO_STOPPED, AUDIO_PLAYING, AUDIO_PAUSED @@ -876,7 +876,7 @@ type TCDTrack*{.final.} = object # This structure is only current as of the last call to SDL_CDStatus() id*: byte # Track number theType*: byte # Data or audio track - unused*: UInt16 + unused*: uint16 len*: int32 # Length, in frames, of this track offset*: int32 # Offset, in frames, from start of disk @@ -886,8 +886,8 @@ type status*: TCDStatus # Current drive status # The rest of this structure is only valid if there's a CD in drive numtracks*: int # Number of tracks on disk - cur_track*: int # Current track position - cur_frame*: int # Current frame offset within current track + curTrack*: int # Current track position + curFrame*: int # Current frame offset within current track track*: array[0..MAX_TRACKS, TCDTrack] PTransAxis* = ptr TTransAxis @@ -895,7 +895,7 @@ type offset*: int scale*: float32 - PJoystick_hwdata* = ptr TJoystick_hwdata + PJoystickHwdata* = ptr TJoystickHwdata TJoystick_hwdata*{.final.} = object # joystick ID id*: int # values used to translate device-specific coordinates into SDL-standard ranges transaxis*: array[0..5, TTransAxis] @@ -918,8 +918,8 @@ type balls*: PBallDelta # Current ball motion deltas nbuttons*: int # Number of buttons on the joystick buttons*: ptr byte # Current button states - hwdata*: PJoystick_hwdata # Driver dependent information - ref_count*: int # Reference count for multiple opens + hwdata*: PJoystickHwdata # Driver dependent information + refCount*: int # Reference count for multiple opens Pversion* = ptr Tversion Tversion*{.final.} = object # SDL_keyboard.h types @@ -945,7 +945,7 @@ type scancode*: byte # hardware specific scancode sym*: TKey # SDL virtual keysym modifier*: TMod # current key modifiers - unicode*: UInt16 # translated character + unicode*: uint16 # translated character TEventAction* = enum # Application visibility event structure ADDEVENT, PEEKEVENT, GETEVENT @@ -971,7 +971,7 @@ type kind*: TEventKind which*: byte # The mouse device index state*: byte # The current button state - x*, y*: UInt16 # The X/Y coordinates of the mouse + x*, y*: uint16 # The X/Y coordinates of the mouse xrel*: int16 # The relative motion in the X direction yrel*: int16 # The relative motion in the Y direction @@ -982,8 +982,8 @@ type which*: byte # The mouse device index button*: byte # The mouse button index state*: byte # SDL_PRESSED or SDL_RELEASED - x*: UInt16 # The X coordinates of the mouse at press time - y*: UInt16 # The Y coordinates of the mouse at press time + x*: uint16 # The X coordinates of the mouse at press time + y*: uint16 # The Y coordinates of the mouse at press time PJoyAxisEvent* = ptr TJoyAxisEvent TJoyAxisEvent*{.final.} = object # SDL_JOYAXISMOTION @@ -1036,8 +1036,8 @@ type TUserEvent*{.final.} = object # SDL_USEREVENT through SDL_NUMEVENTS-1 kind*: TEventKind code*: cint # User defined event code - data1*: Pointer # User defined data pointer - data2*: Pointer # User defined data pointer + data1*: pointer # User defined data pointer + data2*: pointer # User defined data pointer when defined(Unix): @@ -1051,7 +1051,7 @@ when defined(WINDOWS): version*: Tversion hwnd*: THandle # The window for the message msg*: int # The type of message - w_Param*: int32 # WORD message parameter + wParam*: int32 # WORD message parameter lParam*: int32 # LONG message parameter elif defined(Unix): @@ -1090,8 +1090,8 @@ elif defined(Unix): # any X11 functions using the display variable. # They lock the event thread, so should not be # called around event functions or from event filters. - lock_func*: Pointer - unlock_func*: Pointer # Introduced in SDL 1.0.2 + lock_func*: pointer + unlock_func*: pointer # Introduced in SDL 1.0.2 fswindow*: TWindow # The X11 fullscreen window wmwindow*: TWindow # The X11 managed input window @@ -1135,7 +1135,7 @@ type PRect* = ptr TRect TRect*{.final.} = object x*, y*: int16 - w*, h*: UInt16 + w*, h*: uint16 Rect* = TRect PColor* = ptr TColor @@ -1155,34 +1155,34 @@ type PPixelFormat* = ptr TPixelFormat TPixelFormat*{.final.} = object # The structure passed to the low level blit functions palette*: PPalette - BitsPerPixel*: byte - BytesPerPixel*: byte - Rloss*: byte - Gloss*: byte - Bloss*: byte - Aloss*: byte - Rshift*: byte - Gshift*: byte - Bshift*: byte - Ashift*: byte - RMask*: int32 - GMask*: int32 - BMask*: int32 - AMask*: int32 + bitsPerPixel*: byte + bytesPerPixel*: byte + rloss*: byte + gloss*: byte + bloss*: byte + aloss*: byte + rshift*: byte + gshift*: byte + bshift*: byte + ashift*: byte + rMask*: int32 + gMask*: int32 + bMask*: int32 + aMask*: int32 colorkey*: int32 # RGB color key information alpha*: byte # Alpha value information (per-surface alpha) PBlitInfo* = ptr TBlitInfo TBlitInfo*{.final.} = object # typedef for private surface blitting functions - s_pixels*: ptr byte - s_width*: int - s_height*: int - s_skip*: int - d_pixels*: ptr byte - d_width*: int - d_height*: int - d_skip*: int - aux_data*: Pointer + sPixels*: ptr byte + sWidth*: int + sHeight*: int + sSkip*: int + dPixels*: ptr byte + dWidth*: int + dHeight*: int + dSkip*: int + auxData*: pointer src*: PPixelFormat table*: ptr byte dst*: PPixelFormat @@ -1194,30 +1194,30 @@ type flags*: int32 # Read-only format*: PPixelFormat # Read-only w*, h*: cint # Read-only - pitch*: UInt16 # Read-only - pixels*: Pointer # Read-write + pitch*: uint16 # Read-only + pixels*: pointer # Read-write offset*: cint # Private - hwdata*: Pointer #TPrivate_hwdata; Hardware-specific surface info + hwdata*: pointer #TPrivate_hwdata; Hardware-specific surface info # clipping information: - clip_rect*: TRect # Read-only + clipRect*: TRect # Read-only unused1*: int32 # for binary compatibility # Allow recursive locks locked*: int32 # Private # info for fast blit mapping to other surfaces - Blitmap*: Pointer # PSDL_BlitMap; // Private + blitmap*: pointer # PSDL_BlitMap; // Private # format version, bumped at every change to invalidate blit maps - format_version*: cint # Private + formatVersion*: cint # Private refcount*: cint PVideoInfo* = ptr TVideoInfo TVideoInfo*{.final.} = object # The YUV hardware video overlay - hw_available*: byte - blit_hw*: byte - UnusedBits3*: byte # Unused at this point - video_mem*: int32 # The total amount of video memory (in K) + hwAvailable*: byte + blitHw*: byte + unusedBits3*: byte # Unused at this point + videoMem*: int32 # The total amount of video memory (in K) vfmt*: PPixelFormat # Value: The format of the video surface - current_w*: int32 # Value: The current video mode width - current_h*: int32 # Value: The current video mode height + currentW*: int32 # Value: The current video mode width + currentH*: int32 # Value: The current video mode height POverlay* = ptr TOverlay TOverlay*{.final.} = object # Public enumeration for setting the OpenGL window attributes. @@ -1226,7 +1226,7 @@ type planes*: int # Number of planes in the overlay. Usually either 1 or 3 pitches*: PUInt16 # An array of pitches, one for each plane. Pitch is the length of a row in bytes. pixels*: ptr ptr byte # An array of pointers to the data of each plane. The overlay should be locked before these pointers are used. - hw_overlay*: int32 # This will be set to 1 if the overlay is hardware accelerated. + hwOverlay*: int32 # This will be set to 1 if the overlay is hardware accelerated. TGLAttr* = enum GL_RED_SIZE, GL_GREEN_SIZE, GL_BLUE_SIZE, GL_ALPHA_SIZE, GL_BUFFER_SIZE, @@ -1237,11 +1237,11 @@ type PCursor* = ptr TCursor TCursor*{.final.} = object # SDL_mutex.h types area*: TRect # The area of the mouse cursor - hot_x*, hot_y*: int16 # The "tip" of the cursor + hotX*, hot_y*: int16 # The "tip" of the cursor data*: ptr byte # B/W cursor data mask*: ptr byte # B/W cursor mask save*: array[1..2, ptr byte] # Place to save cursor area - wm_cursor*: Pointer # Window-manager cursor + wmCursor*: pointer # Window-manager cursor type @@ -1250,7 +1250,7 @@ type Psemaphore* = ptr Tsemaphore Tsemaphore*{.final.} = object PSem* = ptr TSem - TSem* = TSemaphore + TSem* = Tsemaphore PCond* = ptr TCond TCond*{.final.} = object # SDL_thread.h types @@ -1267,8 +1267,8 @@ type # This is the system-independent thread info struc threadid*: int32 handle*: TSYS_ThreadHandle status*: int - errbuf*: TError - data*: Pointer + errbuf*: Terror + data*: pointer PKeyStateArr* = ptr TKeyStateArr TKeyStateArr* = array[0..65000, byte] # Types required so we don't need to use Windows.pas @@ -1282,24 +1282,24 @@ type # This is the system-independent thread info struc TWordArray* = array[0..16383, int16] # Generic procedure pointer type TEventSeq = set[TEventKind] -template evconv(procName: expr, ptrName: typeDesc, assertions: TEventSeq): stmt {.immediate.} = +template evconv(procName: expr, ptrName: typedesc, assertions: TEventSeq): stmt {.immediate.} = proc `procName`*(event: PEvent): ptrName = assert(contains(assertions, event.kind)) result = cast[ptrName](event) -evconv(EvActive, PActiveEvent, {ACTIVEEVENT}) -evconv(EvKeyboard, PKeyboardEvent, {KEYDOWN, KEYUP}) -evconv(EvMouseMotion, PMouseMotionEvent, {MOUSEMOTION}) -evconv(EvMouseButton, PMouseButtonEvent, {MOUSEBUTTONDOWN, MOUSEBUTTONUP}) -evconv(EvJoyAxis, PJoyAxisEvent,{JOYAXISMOTION}) -evconv(EvJoyBall, PJoyBallEvent, {JOYBALLMOTION}) -evconv(EvJoyHat, PJoyHatEvent, {JOYHATMOTION}) -evconv(EvJoyButton, PJoyButtonEvent, {JOYBUTTONDOWN, JOYBUTTONUP}) -evconv(EvResize, PResizeEvent, {VIDEORESIZE}) -evconv(EvExpose, PExposeEvent, {VIDEOEXPOSE}) -evconv(EvQuit, PQuitEvent, {QUITEV}) -evconv(EvUser, PUserEvent, {USEREVENT}) -evconv(EvSysWM, PSysWMEvent, {SYSWMEVENT}) +evconv(evActive, PActiveEvent, {ACTIVEEVENT}) +evconv(evKeyboard, PKeyboardEvent, {KEYDOWN, KEYUP}) +evconv(evMouseMotion, PMouseMotionEvent, {MOUSEMOTION}) +evconv(evMouseButton, PMouseButtonEvent, {MOUSEBUTTONDOWN, MOUSEBUTTONUP}) +evconv(evJoyAxis, PJoyAxisEvent,{JOYAXISMOTION}) +evconv(evJoyBall, PJoyBallEvent, {JOYBALLMOTION}) +evconv(evJoyHat, PJoyHatEvent, {JOYHATMOTION}) +evconv(evJoyButton, PJoyButtonEvent, {JOYBUTTONDOWN, JOYBUTTONUP}) +evconv(evResize, PResizeEvent, {VIDEORESIZE}) +evconv(evExpose, PExposeEvent, {VIDEOEXPOSE}) +evconv(evQuit, PQuitEvent, {QUITEV}) +evconv(evUser, PUserEvent, {USEREVENT}) +evconv(evSysWM, PSysWMEvent, {SYSWMEVENT}) #------------------------------------------------------------------------------ # initialization @@ -1309,73 +1309,72 @@ evconv(EvSysWM, PSysWMEvent, {SYSWMEVENT}) # Unless the SDL_INIT_NOPARACHUTE flag is set, it will install cleanup # signal handlers for some commonly ignored fatal signals (like SIGSEGV) -proc Init*(flags: int32): int{.cdecl, importc: "SDL_Init", dynlib: LibName.} +proc init*(flags: int32): int{.cdecl, importc: "SDL_Init", dynlib: LibName.} # This function initializes specific SDL subsystems -proc InitSubSystem*(flags: int32): int{.cdecl, importc: "SDL_InitSubSystem", +proc initSubSystem*(flags: int32): int{.cdecl, importc: "SDL_InitSubSystem", dynlib: LibName.} # This function cleans up specific SDL subsystems -proc QuitSubSystem*(flags: int32){.cdecl, importc: "SDL_QuitSubSystem", +proc quitSubSystem*(flags: int32){.cdecl, importc: "SDL_QuitSubSystem", dynlib: LibName.} # This function returns mask of the specified subsystems which have # been initialized. # If 'flags' is 0, it returns a mask of all initialized subsystems. -proc WasInit*(flags: int32): int32{.cdecl, importc: "SDL_WasInit", +proc wasInit*(flags: int32): int32{.cdecl, importc: "SDL_WasInit", dynlib: LibName.} # This function cleans up all initialized subsystems and unloads the # dynamically linked library. You should call it upon all exit conditions. -proc Quit*(){.cdecl, importc: "SDL_Quit", dynlib: LibName.} +proc quit*(){.cdecl, importc: "SDL_Quit", dynlib: LibName.} when defined(WINDOWS): # This should be called from your WinMain() function, if any - proc RegisterApp*(name: cstring, style: int32, h_Inst: Pointer): int{.cdecl, + proc registerApp*(name: cstring, style: int32, hInst: pointer): int{.cdecl, importc: "SDL_RegisterApp", dynlib: LibName.} -proc TableSize*(table: cstring): int +proc tableSize*(table: cstring): int #------------------------------------------------------------------------------ # error-handling #------------------------------------------------------------------------------ # Public functions -proc GetError*(): cstring{.cdecl, importc: "SDL_GetError", dynlib: LibName.} -proc SetError*(fmt: cstring){.cdecl, importc: "SDL_SetError", dynlib: LibName.} -proc ClearError*(){.cdecl, importc: "SDL_ClearError", dynlib: LibName.} -when not (defined(WINDOWS)): - proc Error*(Code: Terrorcode){.cdecl, importc: "SDL_Error", dynlib: LibName.} -proc OutOfMemory*() +proc getError*(): cstring{.cdecl, importc: "SDL_GetError", dynlib: LibName.} +proc setError*(fmt: cstring){.cdecl, importc: "SDL_SetError", dynlib: LibName.} +proc clearError*(){.cdecl, importc: "SDL_ClearError", dynlib: LibName.} +when not (defined(WINDOWS)): + proc error*(Code: Terrorcode){.cdecl, importc: "SDL_Error", dynlib: LibName.} #------------------------------------------------------------------------------ # io handling #------------------------------------------------------------------------------ # Functions to create SDL_RWops structures from various data sources -proc RWFromFile*(filename, mode: cstring): PRWops{.cdecl, +proc rwFromFile*(filename, mode: cstring): PRWops{.cdecl, importc: "SDL_RWFromFile", dynlib: LibName.} -proc FreeRW*(area: PRWops){.cdecl, importc: "SDL_FreeRW", dynlib: LibName.} +proc freeRW*(area: PRWops){.cdecl, importc: "SDL_FreeRW", dynlib: LibName.} #fp is FILE *fp ??? -proc RWFromFP*(fp: Pointer, autoclose: int): PRWops{.cdecl, +proc rwFromFP*(fp: pointer, autoclose: int): PRWops{.cdecl, importc: "SDL_RWFromFP", dynlib: LibName.} -proc RWFromMem*(mem: Pointer, size: int): PRWops{.cdecl, +proc rwFromMem*(mem: pointer, size: int): PRWops{.cdecl, importc: "SDL_RWFromMem", dynlib: LibName.} -proc RWFromConstMem*(mem: Pointer, size: int): PRWops{.cdecl, +proc rwFromConstMem*(mem: pointer, size: int): PRWops{.cdecl, importc: "SDL_RWFromConstMem", dynlib: LibName.} -proc AllocRW*(): PRWops{.cdecl, importc: "SDL_AllocRW", dynlib: LibName.} -proc RWSeek*(context: PRWops, offset: int, whence: int): int -proc RWTell*(context: PRWops): int -proc RWRead*(context: PRWops, theptr: Pointer, size: int, n: int): int -proc RWWrite*(context: PRWops, theptr: Pointer, size: int, n: int): int -proc RWClose*(context: PRWops): int +proc allocRW*(): PRWops{.cdecl, importc: "SDL_AllocRW", dynlib: LibName.} +proc rwSeek*(context: PRWops, offset: int, whence: int): int +proc rwTell*(context: PRWops): int +proc rwRead*(context: PRWops, theptr: pointer, size: int, n: int): int +proc rwWrite*(context: PRWops, theptr: pointer, size: int, n: int): int +proc rwClose*(context: PRWops): int #------------------------------------------------------------------------------ # time-handling #------------------------------------------------------------------------------ # Get the number of milliseconds since the SDL library initialization. # Note that this value wraps if the program runs for more than ~49 days. -proc GetTicks*(): int32{.cdecl, importc: "SDL_GetTicks", dynlib: LibName.} +proc getTicks*(): int32{.cdecl, importc: "SDL_GetTicks", dynlib: LibName.} # Wait a specified number of milliseconds before returning -proc Delay*(msec: int32){.cdecl, importc: "SDL_Delay", dynlib: LibName.} +proc delay*(msec: int32){.cdecl, importc: "SDL_Delay", dynlib: LibName.} # Add a new timer to the pool of timers already running. # Returns a timer ID, or NULL when an error occurs. -proc AddTimer*(interval: int32, callback: TNewTimerCallback, param: Pointer): PTimerID{. +proc addTimer*(interval: int32, callback: TNewTimerCallback, param: pointer): PTimerID{. cdecl, importc: "SDL_AddTimer", dynlib: LibName.} # Remove one of the multiple timers knowing its ID. # Returns a boolean value indicating success. -proc RemoveTimer*(t: PTimerID): TBool{.cdecl, importc: "SDL_RemoveTimer", +proc removeTimer*(t: PTimerID): TBool{.cdecl, importc: "SDL_RemoveTimer", dynlib: LibName.} -proc SetTimer*(interval: int32, callback: TTimerCallback): int{.cdecl, +proc setTimer*(interval: int32, callback: TTimerCallback): int{.cdecl, importc: "SDL_SetTimer", dynlib: LibName.} #------------------------------------------------------------------------------ # audio-routines @@ -1383,13 +1382,13 @@ proc SetTimer*(interval: int32, callback: TTimerCallback): int{.cdecl, # These functions are used internally, and should not be used unless you # have a specific need to specify the audio driver you want to use. # You should normally use SDL_Init() or SDL_InitSubSystem(). -proc AudioInit*(driver_name: cstring): int{.cdecl, importc: "SDL_AudioInit", +proc audioInit*(driverName: cstring): int{.cdecl, importc: "SDL_AudioInit", dynlib: LibName.} -proc AudioQuit*(){.cdecl, importc: "SDL_AudioQuit", dynlib: LibName.} +proc audioQuit*(){.cdecl, importc: "SDL_AudioQuit", dynlib: LibName.} # This function fills the given character buffer with the name of the - # current audio driver, and returns a Pointer to it if the audio driver has + # current audio driver, and returns a pointer to it if the audio driver has # been initialized. It returns NULL if no driver has been initialized. -proc AudioDriverName*(namebuf: cstring, maxlen: int): cstring{.cdecl, +proc audioDriverName*(namebuf: cstring, maxlen: int): cstring{.cdecl, importc: "SDL_AudioDriverName", dynlib: LibName.} # This function opens the audio device with the desired parameters, and # returns 0 if successful, placing the actual hardware parameters in the @@ -1430,17 +1429,17 @@ proc AudioDriverName*(namebuf: cstring, maxlen: int): cstring{.cdecl, # for your audio callback function to be called. Since the audio driver # may modify the requested size of the audio buffer, you should allocate # any local mixing buffers after you open the audio device. -proc OpenAudio*(desired, obtained: PAudioSpec): int{.cdecl, +proc openAudio*(desired, obtained: PAudioSpec): int{.cdecl, importc: "SDL_OpenAudio", dynlib: LibName.} # Get the current audio state: -proc GetAudioStatus*(): TAudiostatus{.cdecl, importc: "SDL_GetAudioStatus", +proc getAudioStatus*(): TAudiostatus{.cdecl, importc: "SDL_GetAudioStatus", dynlib: LibName.} # This function pauses and unpauses the audio callback processing. # It should be called with a parameter of 0 after opening the audio # device to start playing sound. This is so you can safely initialize # data for your callback function after opening the audio device. # Silence will be written to the audio device during the pause. -proc PauseAudio*(pause_on: int){.cdecl, importc: "SDL_PauseAudio", +proc pauseAudio*(pauseOn: int){.cdecl, importc: "SDL_PauseAudio", dynlib: LibName.} # This function loads a WAVE from the data source, automatically freeing # that source if 'freesrc' is non-zero. For example, to load a WAVE file, @@ -1457,22 +1456,22 @@ proc PauseAudio*(pause_on: int){.cdecl, importc: "SDL_PauseAudio", # This function returns NULL and sets the SDL error message if the # wave file cannot be opened, uses an unknown data format, or is # corrupt. Currently raw and MS-ADPCM WAVE files are supported. -proc LoadWAV_RW*(src: PRWops, freesrc: int, spec: PAudioSpec, audio_buf: ptr byte, +proc loadWAV_RW*(src: PRWops, freesrc: int, spec: PAudioSpec, audioBuf: ptr byte, audiolen: PUInt32): PAudioSpec{.cdecl, importc: "SDL_LoadWAV_RW", dynlib: LibName.} # Compatibility convenience function -- loads a WAV from a file -proc LoadWAV*(filename: cstring, spec: PAudioSpec, audio_buf: ptr byte, +proc loadWAV*(filename: cstring, spec: PAudioSpec, audioBuf: ptr byte, audiolen: PUInt32): PAudioSpec # This function frees data previously allocated with SDL_LoadWAV_RW() -proc FreeWAV*(audio_buf: ptr byte){.cdecl, importc: "SDL_FreeWAV", dynlib: LibName.} +proc freeWAV*(audioBuf: ptr byte){.cdecl, importc: "SDL_FreeWAV", dynlib: LibName.} # This function takes a source format and rate and a destination format # and rate, and initializes the 'cvt' structure with information needed # by SDL_ConvertAudio() to convert a buffer of audio data from one format # to the other. # This function returns 0, or -1 if there was an error. -proc BuildAudioCVT*(cvt: PAudioCVT, src_format: UInt16, src_channels: byte, - src_rate: int, dst_format: UInt16, dst_channels: byte, - dst_rate: int): int{.cdecl, importc: "SDL_BuildAudioCVT", +proc buildAudioCVT*(cvt: PAudioCVT, srcFormat: uint16, srcChannels: byte, + srcRate: int, dstFormat: uint16, dstChannels: byte, + dstRate: int): int{.cdecl, importc: "SDL_BuildAudioCVT", dynlib: LibName.} # Once you have initialized the 'cvt' structure using SDL_BuildAudioCVT(), # created an audio buffer cvt->buf, and filled it with cvt->len bytes of @@ -1481,45 +1480,45 @@ proc BuildAudioCVT*(cvt: PAudioCVT, src_format: UInt16, src_channels: byte, # The data conversion may expand the size of the audio data, so the buffer # cvt->buf should be allocated after the cvt structure is initialized by # SDL_BuildAudioCVT(), and should be cvt->len*cvt->len_mult bytes long. -proc ConvertAudio*(cvt: PAudioCVT): int{.cdecl, importc: "SDL_ConvertAudio", +proc convertAudio*(cvt: PAudioCVT): int{.cdecl, importc: "SDL_ConvertAudio", dynlib: LibName.} # This takes two audio buffers of the playing audio format and mixes # them, performing addition, volume adjustment, and overflow clipping. # The volume ranges from 0 - 128, and should be set to SDL_MIX_MAXVOLUME # for full audio volume. Note this does not change hardware volume. # This is provided for convenience -- you can mix your own audio data. -proc MixAudio*(dst, src: ptr byte, length: int32, volume: int){.cdecl, +proc mixAudio*(dst, src: ptr byte, length: int32, volume: int){.cdecl, importc: "SDL_MixAudio", dynlib: LibName.} # The lock manipulated by these functions protects the callback function. # During a LockAudio/UnlockAudio pair, you can be guaranteed that the # callback function is not running. Do not call these from the callback # function or you will cause deadlock. -proc LockAudio*(){.cdecl, importc: "SDL_LockAudio", dynlib: LibName.} -proc UnlockAudio*(){.cdecl, importc: "SDL_UnlockAudio", dynlib: LibName.} +proc lockAudio*(){.cdecl, importc: "SDL_LockAudio", dynlib: LibName.} +proc unlockAudio*(){.cdecl, importc: "SDL_UnlockAudio", dynlib: LibName.} # This function shuts down audio processing and closes the audio device. -proc CloseAudio*(){.cdecl, importc: "SDL_CloseAudio", dynlib: LibName.} +proc closeAudio*(){.cdecl, importc: "SDL_CloseAudio", dynlib: LibName.} #------------------------------------------------------------------------------ # CD-routines #------------------------------------------------------------------------------ # Returns the number of CD-ROM drives on the system, or -1 if # SDL_Init() has not been called with the SDL_INIT_CDROM flag. -proc CDNumDrives*(): int{.cdecl, importc: "SDL_CDNumDrives", dynlib: LibName.} +proc cdNumDrives*(): int{.cdecl, importc: "SDL_CDNumDrives", dynlib: LibName.} # Returns a human-readable, system-dependent identifier for the CD-ROM. # Example: # "/dev/cdrom" # "E:" # "/dev/disk/ide/1/master" -proc CDName*(drive: int): cstring{.cdecl, importc: "SDL_CDName", dynlib: LibName.} +proc cdName*(drive: int): cstring{.cdecl, importc: "SDL_CDName", dynlib: LibName.} # Opens a CD-ROM drive for access. It returns a drive handle on success, # or NULL if the drive was invalid or busy. This newly opened CD-ROM # becomes the default CD used when other CD functions are passed a NULL # CD-ROM handle. # Drives are numbered starting with 0. Drive 0 is the system default CD-ROM. -proc CDOpen*(drive: int): PCD{.cdecl, importc: "SDL_CDOpen", dynlib: LibName.} +proc cdOpen*(drive: int): PCD{.cdecl, importc: "SDL_CDOpen", dynlib: LibName.} # This function returns the current status of the given drive. # If the drive has a CD in it, the table of contents of the CD and current # play position of the CD will be stored in the SDL_CD structure. -proc CDStatus*(cdrom: PCD): TCDStatus{.cdecl, importc: "SDL_CDStatus", +proc cdStatus*(cdrom: PCD): TCDStatus{.cdecl, importc: "SDL_CDStatus", dynlib: LibName.} # Play the given CD starting at 'start_track' and 'start_frame' for 'ntracks' # tracks and 'nframes' frames. If both 'ntrack' and 'nframe' are 0, play @@ -1542,95 +1541,89 @@ proc CDStatus*(cdrom: PCD): TCDStatus{.cdecl, importc: "SDL_CDStatus", # SDL_CDPlayTracks(cdrom, 0, 0, 2, 10); # # This function returns 0, or -1 if there was an error. -proc CDPlayTracks*(cdrom: PCD, start_track: int, start_frame: int, ntracks: int, +proc cdPlayTracks*(cdrom: PCD, startTrack: int, startFrame: int, ntracks: int, nframes: int): int{.cdecl, importc: "SDL_CDPlayTracks", dynlib: LibName.} # Play the given CD starting at 'start' frame for 'length' frames. # It returns 0, or -1 if there was an error. -proc CDPlay*(cdrom: PCD, start: int, len: int): int{.cdecl, +proc cdPlay*(cdrom: PCD, start: int, len: int): int{.cdecl, importc: "SDL_CDPlay", dynlib: LibName.} # Pause play -- returns 0, or -1 on error -proc CDPause*(cdrom: PCD): int{.cdecl, importc: "SDL_CDPause", dynlib: LibName.} +proc cdPause*(cdrom: PCD): int{.cdecl, importc: "SDL_CDPause", dynlib: LibName.} # Resume play -- returns 0, or -1 on error -proc CDResume*(cdrom: PCD): int{.cdecl, importc: "SDL_CDResume", dynlib: LibName.} +proc cdResume*(cdrom: PCD): int{.cdecl, importc: "SDL_CDResume", dynlib: LibName.} # Stop play -- returns 0, or -1 on error -proc CDStop*(cdrom: PCD): int{.cdecl, importc: "SDL_CDStop", dynlib: LibName.} +proc cdStop*(cdrom: PCD): int{.cdecl, importc: "SDL_CDStop", dynlib: LibName.} # Eject CD-ROM -- returns 0, or -1 on error -proc CDEject*(cdrom: PCD): int{.cdecl, importc: "SDL_CDEject", dynlib: LibName.} +proc cdEject*(cdrom: PCD): int{.cdecl, importc: "SDL_CDEject", dynlib: LibName.} # Closes the handle for the CD-ROM drive -proc CDClose*(cdrom: PCD){.cdecl, importc: "SDL_CDClose", dynlib: LibName.} +proc cdClose*(cdrom: PCD){.cdecl, importc: "SDL_CDClose", dynlib: LibName.} # Given a status, returns true if there's a disk in the drive -proc CDInDrive*(status: TCDStatus): bool - # Conversion functions from frames to Minute/Second/Frames and vice versa -proc FRAMES_TO_MSF*(frames: int, M: var int, S: var int, F: var int) -proc MSF_TO_FRAMES*(M: int, S: int, F: int): int - #------------------------------------------------------------------------------ - # JoyStick-routines - #------------------------------------------------------------------------------ - # Count the number of joysticks attached to the system -proc NumJoysticks*(): int{.cdecl, importc: "SDL_NumJoysticks", dynlib: LibName.} +proc cdInDrive*(status: TCDStatus): bool + +proc numJoysticks*(): int{.cdecl, importc: "SDL_NumJoysticks", dynlib: LibName.} # Get the implementation dependent name of a joystick. # This can be called before any joysticks are opened. # If no name can be found, this function returns NULL. -proc JoystickName*(index: int): cstring{.cdecl, importc: "SDL_JoystickName", +proc joystickName*(index: int): cstring{.cdecl, importc: "SDL_JoystickName", dynlib: LibName.} # Open a joystick for use - the index passed as an argument refers to # the N'th joystick on the system. This index is the value which will # identify this joystick in future joystick events. # # This function returns a joystick identifier, or NULL if an error occurred. -proc JoystickOpen*(index: int): PJoystick{.cdecl, importc: "SDL_JoystickOpen", +proc joystickOpen*(index: int): PJoystick{.cdecl, importc: "SDL_JoystickOpen", dynlib: LibName.} # Returns 1 if the joystick has been opened, or 0 if it has not. -proc JoystickOpened*(index: int): int{.cdecl, importc: "SDL_JoystickOpened", +proc joystickOpened*(index: int): int{.cdecl, importc: "SDL_JoystickOpened", dynlib: LibName.} # Get the device index of an opened joystick. -proc JoystickIndex*(joystick: PJoystick): int{.cdecl, +proc joystickIndex*(joystick: PJoystick): int{.cdecl, importc: "SDL_JoystickIndex", dynlib: LibName.} # Get the number of general axis controls on a joystick -proc JoystickNumAxes*(joystick: PJoystick): int{.cdecl, +proc joystickNumAxes*(joystick: PJoystick): int{.cdecl, importc: "SDL_JoystickNumAxes", dynlib: LibName.} # Get the number of trackballs on a joystick # Joystick trackballs have only relative motion events associated # with them and their state cannot be polled. -proc JoystickNumBalls*(joystick: PJoystick): int{.cdecl, +proc joystickNumBalls*(joystick: PJoystick): int{.cdecl, importc: "SDL_JoystickNumBalls", dynlib: LibName.} # Get the number of POV hats on a joystick -proc JoystickNumHats*(joystick: PJoystick): int{.cdecl, +proc joystickNumHats*(joystick: PJoystick): int{.cdecl, importc: "SDL_JoystickNumHats", dynlib: LibName.} # Get the number of buttons on a joystick -proc JoystickNumButtons*(joystick: PJoystick): int{.cdecl, +proc joystickNumButtons*(joystick: PJoystick): int{.cdecl, importc: "SDL_JoystickNumButtons", dynlib: LibName.} # Update the current state of the open joysticks. # This is called automatically by the event loop if any joystick # events are enabled. -proc JoystickUpdate*(){.cdecl, importc: "SDL_JoystickUpdate", dynlib: LibName.} +proc joystickUpdate*(){.cdecl, importc: "SDL_JoystickUpdate", dynlib: LibName.} # Enable/disable joystick event polling. # If joystick events are disabled, you must call SDL_JoystickUpdate() # yourself and check the state of the joystick when you want joystick # information. # The state can be one of SDL_QUERY, SDL_ENABLE or SDL_IGNORE. -proc JoystickEventState*(state: int): int{.cdecl, +proc joystickEventState*(state: int): int{.cdecl, importc: "SDL_JoystickEventState", dynlib: LibName.} # Get the current state of an axis control on a joystick # The state is a value ranging from -32768 to 32767. # The axis indices start at index 0. -proc JoystickGetAxis*(joystick: PJoystick, axis: int): int16{.cdecl, +proc joystickGetAxis*(joystick: PJoystick, axis: int): int16{.cdecl, importc: "SDL_JoystickGetAxis", dynlib: LibName.} # The hat indices start at index 0. -proc JoystickGetHat*(joystick: PJoystick, hat: int): byte{.cdecl, +proc joystickGetHat*(joystick: PJoystick, hat: int): byte{.cdecl, importc: "SDL_JoystickGetHat", dynlib: LibName.} # Get the ball axis change since the last poll # This returns 0, or -1 if you passed it invalid parameters. # The ball indices start at index 0. -proc JoystickGetBall*(joystick: PJoystick, ball: int, dx: var int, dy: var int): int{. +proc joystickGetBall*(joystick: PJoystick, ball: int, dx: var int, dy: var int): int{. cdecl, importc: "SDL_JoystickGetBall", dynlib: LibName.} # Get the current state of a button on a joystick # The button indices start at index 0. -proc JoystickGetButton*(joystick: PJoystick, Button: int): byte{.cdecl, +proc joystickGetButton*(joystick: PJoystick, button: int): byte{.cdecl, importc: "SDL_JoystickGetButton", dynlib: LibName.} # Close a joystick previously opened with SDL_JoystickOpen() -proc JoystickClose*(joystick: PJoystick){.cdecl, importc: "SDL_JoystickClose", +proc joystickClose*(joystick: PJoystick){.cdecl, importc: "SDL_JoystickClose", dynlib: LibName.} #------------------------------------------------------------------------------ # event-handling @@ -1638,7 +1631,7 @@ proc JoystickClose*(joystick: PJoystick){.cdecl, importc: "SDL_JoystickClose", # Pumps the event loop, gathering events from the input devices. # This function updates the event queue and internal input device state. # This should only be run in the thread that sets the video mode. -proc PumpEvents*(){.cdecl, importc: "SDL_PumpEvents", dynlib: LibName.} +proc pumpEvents*(){.cdecl, importc: "SDL_PumpEvents", dynlib: LibName.} # Checks the event queue for messages and optionally returns them. # If 'action' is SDL_ADDEVENT, up to 'numevents' events will be added to # the back of the event queue. @@ -1650,20 +1643,20 @@ proc PumpEvents*(){.cdecl, importc: "SDL_PumpEvents", dynlib: LibName.} # removed from the queue. # This function returns the number of events actually stored, or -1 # if there was an error. This function is thread-safe. -proc PeepEvents*(events: PEvent, numevents: int, action: Teventaction, +proc peepEvents*(events: PEvent, numevents: int, action: TEventAction, mask: int32): int{.cdecl, importc: "SDL_PeepEvents", dynlib: LibName.} # Polls for currently pending events, and returns 1 if there are any pending # events, or 0 if there are none available. If 'event' is not NULL, the next # event is removed from the queue and stored in that area. -proc PollEvent*(event: PEvent): int{.cdecl, importc: "SDL_PollEvent", +proc pollEvent*(event: PEvent): int{.cdecl, importc: "SDL_PollEvent", dynlib: LibName.} # Waits indefinitely for the next available event, returning 1, or 0 if there # was an error while waiting for events. If 'event' is not NULL, the next # event is removed from the queue and stored in that area. -proc WaitEvent*(event: PEvent): int{.cdecl, importc: "SDL_WaitEvent", +proc waitEvent*(event: PEvent): int{.cdecl, importc: "SDL_WaitEvent", dynlib: LibName.} -proc PushEvent*(event: PEvent): int{.cdecl, importc: "SDL_PushEvent", +proc pushEvent*(event: PEvent): int{.cdecl, importc: "SDL_PushEvent", dynlib: LibName.} # If the filter returns 1, then the event will be added to the internal queue. # If it returns 0, then the event will be dropped from the queue, but the @@ -1679,11 +1672,11 @@ proc PushEvent*(event: PEvent): int{.cdecl, importc: "SDL_PushEvent", # be closed, otherwise the window will remain open if possible. # If the quit event is generated by an interrupt signal, it will bypass the # internal queue and be delivered to the application at the next event poll. -proc SetEventFilter*(filter: TEventFilter){.cdecl, +proc setEventFilter*(filter: TEventFilter){.cdecl, importc: "SDL_SetEventFilter", dynlib: LibName.} # Return the current event filter - can be used to "chain" filters. # If there is no event filter set, this function returns NULL. -proc GetEventFilter*(): TEventFilter{.cdecl, importc: "SDL_GetEventFilter", +proc getEventFilter*(): TEventFilter{.cdecl, importc: "SDL_GetEventFilter", dynlib: LibName.} # This function allows you to set the state of processing certain events. # If 'state' is set to SDL_IGNORE, that event will be automatically dropped @@ -1691,26 +1684,26 @@ proc GetEventFilter*(): TEventFilter{.cdecl, importc: "SDL_GetEventFilter", # If 'state' is set to SDL_ENABLE, that event will be processed normally. # If 'state' is set to SDL_QUERY, SDL_EventState() will return the # current processing state of the specified event. -proc EventState*(theType: byte, state: int): byte{.cdecl, +proc eventState*(theType: byte, state: int): byte{.cdecl, importc: "SDL_EventState", dynlib: LibName.} #------------------------------------------------------------------------------ # Version Routines #------------------------------------------------------------------------------ # This macro can be used to fill a version structure with the compile-time # version of the SDL library. -proc VERSION*(X: var TVersion) +proc version*(x: var Tversion) # This macro turns the version numbers into a numeric value: # (1,2,3) -> (1203) # This assumes that there will never be more than 100 patchlevels -proc VERSIONNUM*(X, Y, Z: int): int +proc versionnum*(x, y, z: int): int # This is the version number macro for the current SDL version -proc COMPILEDVERSION*(): int +proc compiledversion*(): int # This macro will evaluate to true if compiled with SDL at least X.Y.Z -proc VERSION_ATLEAST*(X: int, Y: int, Z: int): bool +proc versionAtleast*(x, y, z: int): bool # This function gets the version of the dynamically linked SDL library. # it should NOT be used to fill a version structure, instead you should # use the SDL_Version() macro. -proc Linked_Version*(): Pversion{.cdecl, importc: "SDL_Linked_Version", +proc linkedVersion*(): PVersion{.cdecl, importc: "SDL_Linked_Version", dynlib: LibName.} #------------------------------------------------------------------------------ # video @@ -1727,25 +1720,25 @@ proc Linked_Version*(): Pversion{.cdecl, importc: "SDL_Linked_Version", # If you use both sound and video in your application, you need to call # SDL_Init() before opening the sound device, otherwise under Win32 DirectX, # you won't be able to set full-screen display modes. -proc VideoInit*(driver_name: cstring, flags: int32): int{.cdecl, +proc videoInit*(driverName: cstring, flags: int32): int{.cdecl, importc: "SDL_VideoInit", dynlib: LibName.} -proc VideoQuit*(){.cdecl, importc: "SDL_VideoQuit", dynlib: LibName.} +proc videoQuit*(){.cdecl, importc: "SDL_VideoQuit", dynlib: LibName.} # This function fills the given character buffer with the name of the # video driver, and returns a pointer to it if the video driver has # been initialized. It returns NULL if no driver has been initialized. -proc VideoDriverName*(namebuf: cstring, maxlen: int): cstring{.cdecl, +proc videoDriverName*(namebuf: cstring, maxlen: int): cstring{.cdecl, importc: "SDL_VideoDriverName", dynlib: LibName.} # This function returns a pointer to the current display surface. # If SDL is doing format conversion on the display surface, this # function returns the publicly visible surface, not the real video # surface. -proc GetVideoSurface*(): PSurface{.cdecl, importc: "SDL_GetVideoSurface", +proc getVideoSurface*(): PSurface{.cdecl, importc: "SDL_GetVideoSurface", dynlib: LibName.} # This function returns a read-only pointer to information about the # video hardware. If this is called before SDL_SetVideoMode(), the 'vfmt' # member of the returned structure will contain the pixel format of the # "best" video mode. -proc GetVideoInfo*(): PVideoInfo{.cdecl, importc: "SDL_GetVideoInfo", +proc getVideoInfo*(): PVideoInfo{.cdecl, importc: "SDL_GetVideoInfo", dynlib: LibName.} # Check to see if a particular video mode is supported. # It returns 0 if the requested mode is not supported under any bit depth, @@ -1756,7 +1749,7 @@ proc GetVideoInfo*(): PVideoInfo{.cdecl, importc: "SDL_GetVideoInfo", # # The arguments to SDL_VideoModeOK() are the same ones you would pass to # SDL_SetVideoMode() -proc VideoModeOK*(width, height, bpp: int, flags: int32): int{.cdecl, +proc videoModeOK*(width, height, bpp: int, flags: int32): int{.cdecl, importc: "SDL_VideoModeOK", importc: "SDL_VideoModeOK", dynlib: LibName.} # Return a pointer to an array of available screen dimensions for the # given format and video flags, sorted largest to smallest. Returns @@ -1765,7 +1758,7 @@ proc VideoModeOK*(width, height, bpp: int, flags: int32): int{.cdecl, # # if 'format' is NULL, the mode list will be for the format given # by SDL_GetVideoInfo( ) - > vfmt -proc ListModes*(format: PPixelFormat, flags: int32): PPSDL_Rect{.cdecl, +proc listModes*(format: PPixelFormat, flags: int32): PPSDL_Rect{.cdecl, importc: "SDL_ListModes", dynlib: LibName.} # Set up a video mode with the specified width, height and bits-per-pixel. # @@ -1808,15 +1801,15 @@ proc ListModes*(format: PPixelFormat, flags: int32): PPSDL_Rect{.cdecl, # applications that redraw the entire screen on every update. # # This function returns the video framebuffer surface, or NULL if it fails. -proc SetVideoMode*(width, height, bpp: int, flags: uint32): PSurface{.cdecl, +proc setVideoMode*(width, height, bpp: int, flags: uint32): PSurface{.cdecl, importc: "SDL_SetVideoMode", dynlib: LibName.} # Makes sure the given list of rectangles is updated on the given screen. # If 'x', 'y', 'w' and 'h' are all 0, SDL_UpdateRect will update the entire # screen. # These functions should not be called while 'screen' is locked. -proc UpdateRects*(screen: PSurface, numrects: int, rects: PRect){.cdecl, +proc updateRects*(screen: PSurface, numrects: int, rects: PRect){.cdecl, importc: "SDL_UpdateRects", dynlib: LibName.} -proc UpdateRect*(screen: PSurface, x, y: int32, w, h: int32){.cdecl, +proc updateRect*(screen: PSurface, x, y: int32, w, h: int32){.cdecl, importc: "SDL_UpdateRect", dynlib: LibName.} # On hardware that supports double-buffering, this function sets up a flip # and returns. The hardware will wait for vertical retrace, and then swap @@ -1826,14 +1819,14 @@ proc UpdateRect*(screen: PSurface, x, y: int32, w, h: int32){.cdecl, # The SDL_DOUBLEBUF flag must have been passed to SDL_SetVideoMode() when # setting the video mode for this function to perform hardware flipping. # This function returns 0 if successful, or -1 if there was an error. -proc Flip*(screen: PSurface): int{.cdecl, importc: "SDL_Flip", dynlib: LibName.} +proc flip*(screen: PSurface): int{.cdecl, importc: "SDL_Flip", dynlib: LibName.} # Set the gamma correction for each of the color channels. # The gamma values range (approximately) between 0.1 and 10.0 # # If this function isn't supported directly by the hardware, it will # be emulated using gamma ramps, if available. If successful, this # function returns 0, otherwise it returns -1. -proc SetGamma*(redgamma: float32, greengamma: float32, bluegamma: float32): int{. +proc setGamma*(redgamma: float32, greengamma: float32, bluegamma: float32): int{. cdecl, importc: "SDL_SetGamma", dynlib: LibName.} # Set the gamma translation table for the red, green, and blue channels # of the video hardware. Each table is an array of 256 16-bit quantities, @@ -1845,7 +1838,7 @@ proc SetGamma*(redgamma: float32, greengamma: float32, bluegamma: float32): int{ # If the call succeeds, it will return 0. If the display driver or # hardware does not support gamma translation, or otherwise fails, # this function will return -1. -proc SetGammaRamp*(redtable: PUInt16, greentable: PUInt16, bluetable: PUInt16): int{. +proc setGammaRamp*(redtable: PUInt16, greentable: PUInt16, bluetable: PUInt16): int{. cdecl, importc: "SDL_SetGammaRamp", dynlib: LibName.} # Retrieve the current values of the gamma translation tables. # @@ -1854,7 +1847,7 @@ proc SetGammaRamp*(redtable: PUInt16, greentable: PUInt16, bluetable: PUInt16): # If the call succeeds, it will return 0. If the display driver or # hardware does not support gamma translation, or otherwise fails, # this function will return -1. -proc GetGammaRamp*(redtable: PUInt16, greentable: PUInt16, bluetable: PUInt16): int{. +proc getGammaRamp*(redtable: PUInt16, greentable: PUInt16, bluetable: PUInt16): int{. cdecl, importc: "SDL_GetGammaRamp", dynlib: LibName.} # Sets a portion of the colormap for the given 8-bit surface. If 'surface' # is not a palettized surface, this function does nothing, returning 0. @@ -1869,7 +1862,7 @@ proc GetGammaRamp*(redtable: PUInt16, greentable: PUInt16, bluetable: PUInt16): # will always return 1, and the palette is guaranteed to be set the way # you desire, even if the window colormap has to be warped or run under # emulation. -proc SetColors*(surface: PSurface, colors: PColor, firstcolor: int, ncolors: int): int{. +proc setColors*(surface: PSurface, colors: PColor, firstcolor: int, ncolors: int): int{. cdecl, importc: "SDL_SetColors", dynlib: LibName.} # Sets a portion of the colormap for a given 8-bit surface. # 'flags' is one or both of: @@ -1885,20 +1878,20 @@ proc SetColors*(surface: PSurface, colors: PColor, firstcolor: int, ncolors: int # # SDL_SetColors() is equivalent to calling this function with # flags = (SDL_LOGPAL or SDL_PHYSPAL). -proc SetPalette*(surface: PSurface, flags: int, colors: PColor, firstcolor: int, +proc setPalette*(surface: PSurface, flags: int, colors: PColor, firstcolor: int, ncolors: int): int{.cdecl, importc: "SDL_SetPalette", dynlib: LibName.} # Maps an RGB triple to an opaque pixel value for a given pixel format -proc MapRGB*(format: PPixelFormat, r: byte, g: byte, b: byte): int32{.cdecl, +proc mapRGB*(format: PPixelFormat, r: byte, g: byte, b: byte): int32{.cdecl, importc: "SDL_MapRGB", dynlib: LibName.} # Maps an RGBA quadruple to a pixel value for a given pixel format -proc MapRGBA*(format: PPixelFormat, r: byte, g: byte, b: byte, a: byte): int32{. +proc mapRGBA*(format: PPixelFormat, r: byte, g: byte, b: byte, a: byte): int32{. cdecl, importc: "SDL_MapRGBA", dynlib: LibName.} # Maps a pixel value into the RGB components for a given pixel format -proc GetRGB*(pixel: int32, fmt: PPixelFormat, r: ptr byte, g: ptr byte, b: ptr byte){. +proc getRGB*(pixel: int32, fmt: PPixelFormat, r: ptr byte, g: ptr byte, b: ptr byte){. cdecl, importc: "SDL_GetRGB", dynlib: LibName.} # Maps a pixel value into the RGBA components for a given pixel format -proc GetRGBA*(pixel: int32, fmt: PPixelFormat, r: ptr byte, g: ptr byte, b: ptr byte, +proc getRGBA*(pixel: int32, fmt: PPixelFormat, r: ptr byte, g: ptr byte, b: ptr byte, a: ptr byte){.cdecl, importc: "SDL_GetRGBA", dynlib: LibName.} # Allocate and free an RGB surface (must be called after SDL_SetVideoMode) # If the depth is 4 or 8 bits, an empty palette is allocated for the surface. @@ -1932,17 +1925,17 @@ proc GetRGBA*(pixel: int32, fmt: PPixelFormat, r: ptr byte, g: ptr byte, b: ptr # will be set in the flags member of the returned surface. If for some # reason the surface could not be placed in video memory, it will not have # the SDL_HWSURFACE flag set, and will be created in system memory instead. -proc AllocSurface*(flags: int32, width, height, depth: int, - RMask, GMask, BMask, AMask: int32): PSurface -proc CreateRGBSurface*(flags: int32, width, height, depth: int, - RMask, GMask, BMask, AMask: int32): PSurface{.cdecl, +proc allocSurface*(flags: int32, width, height, depth: int, + rMask, gMask, bMask, aMask: int32): PSurface +proc createRGBSurface*(flags: int32, width, height, depth: int, + rMask, gMask, bMask, aMask: int32): PSurface{.cdecl, importc: "SDL_CreateRGBSurface", dynlib: LibName.} -proc CreateRGBSurfaceFrom*(pixels: Pointer, width, height, depth, pitch: int, - RMask, GMask, BMask, AMask: int32): PSurface{.cdecl, +proc createRGBSurfaceFrom*(pixels: pointer, width, height, depth, pitch: int, + rMask, gMask, bMask, aMask: int32): PSurface{.cdecl, importc: "SDL_CreateRGBSurfaceFrom", dynlib: LibName.} -proc FreeSurface*(surface: PSurface){.cdecl, importc: "SDL_FreeSurface", +proc freeSurface*(surface: PSurface){.cdecl, importc: "SDL_FreeSurface", dynlib: LibName.} -proc MustLock*(Surface: PSurface): bool +proc mustLock*(surface: PSurface): bool # SDL_LockSurface() sets up a surface for directly accessing the pixels. # Between calls to SDL_LockSurface()/SDL_UnlockSurface(), you can write # to and read from 'surface->pixels', using the pixel format stored in @@ -1959,25 +1952,25 @@ proc MustLock*(Surface: PSurface): bool # pairs, as critical system locks may be held during this time. # # SDL_LockSurface() returns 0, or -1 if the surface couldn't be locked. -proc LockSurface*(surface: PSurface): int{.cdecl, importc: "SDL_LockSurface", +proc lockSurface*(surface: PSurface): int{.cdecl, importc: "SDL_LockSurface", dynlib: LibName.} -proc UnlockSurface*(surface: PSurface){.cdecl, importc: "SDL_UnlockSurface", +proc unlockSurface*(surface: PSurface){.cdecl, importc: "SDL_UnlockSurface", dynlib: LibName.} # Load a surface from a seekable SDL data source (memory or file.) # If 'freesrc' is non-zero, the source will be closed after being read. # Returns the new surface, or NULL if there was an error. # The new surface should be freed with SDL_FreeSurface(). -proc LoadBMP_RW*(src: PRWops, freesrc: int): PSurface{.cdecl, +proc loadBMP_RW*(src: PRWops, freesrc: int): PSurface{.cdecl, importc: "SDL_LoadBMP_RW", dynlib: LibName.} # Convenience macro -- load a surface from a file -proc LoadBMP*(filename: cstring): PSurface +proc loadBMP*(filename: cstring): PSurface # Save a surface to a seekable SDL data source (memory or file.) # If 'freedst' is non-zero, the source will be closed after being written. # Returns 0 if successful or -1 if there was an error. -proc SaveBMP_RW*(surface: PSurface, dst: PRWops, freedst: int): int{.cdecl, +proc saveBMP_RW*(surface: PSurface, dst: PRWops, freedst: int): int{.cdecl, importc: "SDL_SaveBMP_RW", dynlib: LibName.} # Convenience macro -- save a surface to a file -proc SaveBMP*(surface: PSurface, filename: cstring): int +proc saveBMP*(surface: PSurface, filename: cstring): int # Sets the color key (transparent pixel) in a blittable surface. # If 'flag' is SDL_SRCCOLORKEY (optionally OR'd with SDL_RLEACCEL), # 'key' will be the transparent pixel in the source image of a blit. @@ -1985,7 +1978,7 @@ proc SaveBMP*(surface: PSurface, filename: cstring): int # and removes RLE acceleration if absent. # If 'flag' is 0, this function clears any current color key. # This function returns 0, or -1 if there was an error. -proc SetColorKey*(surface: PSurface, flag, key: int32): int{.cdecl, +proc setColorKey*(surface: PSurface, flag, key: int32): int{.cdecl, importc: "SDL_SetColorKey", dynlib: LibName.} # This function sets the alpha value for the entire surface, as opposed to # using the alpha component of each pixel. This value measures the range @@ -1998,7 +1991,7 @@ proc SetColorKey*(surface: PSurface, flag, key: int32): int{.cdecl, # If 'flag' is SDL_SRCALPHA, alpha blending is enabled for the surface. # OR:ing the flag with SDL_RLEACCEL requests RLE acceleration for the # surface; if SDL_RLEACCEL is not specified, the RLE accel will be removed. -proc SetAlpha*(surface: PSurface, flag: int32, alpha: byte): int{.cdecl, +proc setAlpha*(surface: PSurface, flag: int32, alpha: byte): int{.cdecl, importc: "SDL_SetAlpha", dynlib: LibName.} # Sets the clipping rectangle for the destination surface in a blit. # @@ -2010,12 +2003,12 @@ proc SetAlpha*(surface: PSurface, flag: int32, alpha: byte): int{.cdecl, # # Note that blits are automatically clipped to the edges of the source # and destination surfaces. -proc SetClipRect*(surface: PSurface, rect: PRect){.cdecl, +proc setClipRect*(surface: PSurface, rect: PRect){.cdecl, importc: "SDL_SetClipRect", dynlib: LibName.} # Gets the clipping rectangle for the destination surface in a blit. # 'rect' must be a pointer to a valid rectangle which will be filled # with the correct values. -proc GetClipRect*(surface: PSurface, rect: PRect){.cdecl, +proc getClipRect*(surface: PSurface, rect: PRect){.cdecl, importc: "SDL_GetClipRect", dynlib: LibName.} # Creates a new surface of the specified format, and then copies and maps # the given surface to it so the blit of the converted surface will be as @@ -2027,7 +2020,7 @@ proc GetClipRect*(surface: PSurface, rect: PRect){.cdecl, # surface. # # This function is used internally by SDL_DisplayFormat(). -proc ConvertSurface*(src: PSurface, fmt: PPixelFormat, flags: int32): PSurface{. +proc convertSurface*(src: PSurface, fmt: PPixelFormat, flags: int32): PSurface{. cdecl, importc: "SDL_ConvertSurface", dynlib: LibName.} # # This performs a fast blit from the source surface to the destination @@ -2098,14 +2091,14 @@ proc ConvertSurface*(src: PSurface, fmt: PPixelFormat, flags: int32): PSurface{. # to the video memory again. # You should call SDL_BlitSurface() unless you know exactly how SDL # blitting works internally and how to use the other blit functions. -proc BlitSurface*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int +proc blitSurface*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int # This is the public blit function, SDL_BlitSurface(), and it performs # rectangle validation and clipping before passing it to SDL_LowerBlit() -proc UpperBlit*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int{. +proc upperBlit*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int{. cdecl, importc: "SDL_UpperBlit", dynlib: LibName.} # This is a semi-private blit function and it performs low-level surface # blitting only. -proc LowerBlit*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int{. +proc lowerBlit*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int{. cdecl, importc: "SDL_LowerBlit", dynlib: LibName.} # This function performs a fast fill of the given rectangle with 'color' # The given rectangle is clipped to the destination surface clip area @@ -2114,7 +2107,7 @@ proc LowerBlit*(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): i # The color should be a pixel of the format used by the surface, and # can be generated by the SDL_MapRGB() function. # This function returns 0 on success, or -1 on error. -proc FillRect*(dst: PSurface, dstrect: PRect, color: int32): int{.cdecl, +proc fillRect*(dst: PSurface, dstrect: PRect, color: int32): int{.cdecl, importc: "SDL_FillRect", dynlib: LibName.} # This function takes a surface and copies it to a new surface of the # pixel format and colors of the video framebuffer, suitable for fast @@ -2125,7 +2118,7 @@ proc FillRect*(dst: PSurface, dstrect: PRect, color: int32): int{.cdecl, # calling this function. # # If the conversion fails or runs out of memory, it returns NULL -proc DisplayFormat*(surface: PSurface): PSurface{.cdecl, +proc displayFormat*(surface: PSurface): PSurface{.cdecl, importc: "SDL_DisplayFormat", dynlib: LibName.} # This function takes a surface and copies it to a new surface of the # pixel format and colors of the video framebuffer (if possible), @@ -2137,7 +2130,7 @@ proc DisplayFormat*(surface: PSurface): PSurface{.cdecl, # calling this function. # # If the conversion fails or runs out of memory, it returns NULL -proc DisplayFormatAlpha*(surface: PSurface): PSurface{.cdecl, +proc displayFormatAlpha*(surface: PSurface): PSurface{.cdecl, importc: "SDL_DisplayFormatAlpha", dynlib: LibName.} #* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #* YUV video surface overlay functions */ @@ -2146,23 +2139,23 @@ proc DisplayFormatAlpha*(surface: PSurface): PSurface{.cdecl, # Calling the returned surface an overlay is something of a misnomer because # the contents of the display surface underneath the area where the overlay # is shown is undefined - it may be overwritten with the converted YUV data. -proc CreateYUVOverlay*(width: int, height: int, format: int32, +proc createYUVOverlay*(width: int, height: int, format: int32, display: PSurface): POverlay{.cdecl, importc: "SDL_CreateYUVOverlay", dynlib: LibName.} # Lock an overlay for direct access, and unlock it when you are done -proc LockYUVOverlay*(Overlay: POverlay): int{.cdecl, +proc lockYUVOverlay*(overlay: POverlay): int{.cdecl, importc: "SDL_LockYUVOverlay", dynlib: LibName.} -proc UnlockYUVOverlay*(Overlay: POverlay){.cdecl, +proc unlockYUVOverlay*(overlay: POverlay){.cdecl, importc: "SDL_UnlockYUVOverlay", dynlib: LibName.} # Blit a video overlay to the display surface. # The contents of the video surface underneath the blit destination are # not defined. # The width and height of the destination rectangle may be different from # that of the overlay, but currently only 2x scaling is supported. -proc DisplayYUVOverlay*(Overlay: POverlay, dstrect: PRect): int{.cdecl, +proc displayYUVOverlay*(overlay: POverlay, dstrect: PRect): int{.cdecl, importc: "SDL_DisplayYUVOverlay", dynlib: LibName.} # Free a video overlay -proc FreeYUVOverlay*(Overlay: POverlay){.cdecl, importc: "SDL_FreeYUVOverlay", +proc freeYUVOverlay*(overlay: POverlay){.cdecl, importc: "SDL_FreeYUVOverlay", dynlib: LibName.} #------------------------------------------------------------------------------ # OpenGL Routines @@ -2175,13 +2168,13 @@ proc FreeYUVOverlay*(Overlay: POverlay){.cdecl, importc: "SDL_FreeYUVOverlay", # your program from the dynamic library using SDL_GL_GetProcAddress(). # # This is disabled in default builds of SDL. -proc GL_LoadLibrary*(filename: cstring): int{.cdecl, +proc glLoadLibrary*(filename: cstring): int{.cdecl, importc: "SDL_GL_LoadLibrary", dynlib: LibName.} # Get the address of a GL function (for extension functions) -proc GL_GetProcAddress*(procname: cstring): Pointer{.cdecl, +proc glGetProcAddress*(procname: cstring): pointer{.cdecl, importc: "SDL_GL_GetProcAddress", dynlib: LibName.} # Set an attribute of the OpenGL subsystem before intialization. -proc GL_SetAttribute*(attr: TGLAttr, value: int): int{.cdecl, +proc glSetAttribute*(attr: TGLAttr, value: int): int{.cdecl, importc: "SDL_GL_SetAttribute", dynlib: LibName.} # Get an attribute of the OpenGL subsystem from the windowing # interface, such as glX. This is of course different from getting @@ -2190,34 +2183,34 @@ proc GL_SetAttribute*(attr: TGLAttr, value: int): int{.cdecl, # # Developers should track the values they pass into SDL_GL_SetAttribute # themselves if they want to retrieve these values. -proc GL_GetAttribute*(attr: TGLAttr, value: var int): int{.cdecl, +proc glGetAttribute*(attr: TGLAttr, value: var int): int{.cdecl, importc: "SDL_GL_GetAttribute", dynlib: LibName.} # Swap the OpenGL buffers, if double-buffering is supported. -proc GL_SwapBuffers*(){.cdecl, importc: "SDL_GL_SwapBuffers", dynlib: LibName.} +proc glSwapBuffers*(){.cdecl, importc: "SDL_GL_SwapBuffers", dynlib: LibName.} # Internal functions that should not be called unless you have read # and understood the source code for these functions. -proc GL_UpdateRects*(numrects: int, rects: PRect){.cdecl, +proc glUpdateRects*(numrects: int, rects: PRect){.cdecl, importc: "SDL_GL_UpdateRects", dynlib: LibName.} -proc GL_Lock*(){.cdecl, importc: "SDL_GL_Lock", dynlib: LibName.} -proc GL_Unlock*(){.cdecl, importc: "SDL_GL_Unlock", dynlib: LibName.} +proc glLock*(){.cdecl, importc: "SDL_GL_Lock", dynlib: LibName.} +proc glUnlock*(){.cdecl, importc: "SDL_GL_Unlock", dynlib: LibName.} #* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * #* These functions allow interaction with the window manager, if any. * #* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # Sets/Gets the title and icon text of the display window -proc WM_GetCaption*(title: var cstring, icon: var cstring){.cdecl, +proc wmGetCaption*(title: var cstring, icon: var cstring){.cdecl, importc: "SDL_WM_GetCaption", dynlib: LibName.} -proc WM_SetCaption*(title: cstring, icon: cstring){.cdecl, +proc wmSetCaption*(title: cstring, icon: cstring){.cdecl, importc: "SDL_WM_SetCaption", dynlib: LibName.} # Sets the icon for the display window. # This function must be called before the first call to SDL_SetVideoMode(). # It takes an icon surface, and a mask in MSB format. # If 'mask' is NULL, the entire icon surface will be used as the icon. -proc WM_SetIcon*(icon: PSurface, mask: byte){.cdecl, importc: "SDL_WM_SetIcon", +proc wmSetIcon*(icon: PSurface, mask: byte){.cdecl, importc: "SDL_WM_SetIcon", dynlib: LibName.} # This function iconifies the window, and returns 1 if it succeeded. # If the function succeeds, it generates an SDL_APPACTIVE loss event. # This function is a noop and returns 0 in non-windowed environments. -proc WM_IconifyWindow*(): int{.cdecl, importc: "SDL_WM_IconifyWindow", +proc wmIconifyWindow*(): int{.cdecl, importc: "SDL_WM_IconifyWindow", dynlib: LibName.} # Toggle fullscreen mode without changing the contents of the screen. # If the display surface does not require locking before accessing @@ -2232,12 +2225,12 @@ proc WM_IconifyWindow*(): int{.cdecl, importc: "SDL_WM_IconifyWindow", # set, then the display will be windowed by default where supported. # # This is currently only implemented in the X11 video driver. -proc WM_ToggleFullScreen*(surface: PSurface): int{.cdecl, +proc wmToggleFullScreen*(surface: PSurface): int{.cdecl, importc: "SDL_WM_ToggleFullScreen", dynlib: LibName.} # Grabbing means that the mouse is confined to the application window, # and nearly all keyboard input is passed directly to the application, # and not interpreted by a window manager, if any. -proc WM_GrabInput*(mode: TGrabMode): TGrabMode{.cdecl, +proc wmGrabInput*(mode: TGrabMode): TGrabMode{.cdecl, importc: "SDL_WM_GrabInput", dynlib: LibName.} #------------------------------------------------------------------------------ # mouse-routines @@ -2246,16 +2239,16 @@ proc WM_GrabInput*(mode: TGrabMode): TGrabMode{.cdecl, # The current button state is returned as a button bitmask, which can # be tested using the SDL_BUTTON(X) macros, and x and y are set to the # current mouse cursor position. You can pass NULL for either x or y. -proc GetMouseState*(x: var int, y: var int): byte{.cdecl, +proc getMouseState*(x: var int, y: var int): byte{.cdecl, importc: "SDL_GetMouseState", dynlib: LibName.} # Retrieve the current state of the mouse. # The current button state is returned as a button bitmask, which can # be tested using the SDL_BUTTON(X) macros, and x and y are set to the # mouse deltas since the last call to SDL_GetRelativeMouseState(). -proc GetRelativeMouseState*(x: var int, y: var int): byte{.cdecl, +proc getRelativeMouseState*(x: var int, y: var int): byte{.cdecl, importc: "SDL_GetRelativeMouseState", dynlib: LibName.} # Set the position of the mouse cursor (generates a mouse motion event) -proc WarpMouse*(x, y: UInt16){.cdecl, importc: "SDL_WarpMouse", dynlib: LibName.} +proc warpMouse*(x, y: uint16){.cdecl, importc: "SDL_WarpMouse", dynlib: LibName.} # Create a cursor using the specified data and mask (in MSB format). # The cursor width must be a multiple of 8 bits. # @@ -2267,26 +2260,26 @@ proc WarpMouse*(x, y: UInt16){.cdecl, importc: "SDL_WarpMouse", dynlib: LibName. # 1 0 Inverted color if possible, black if not. # # Cursors created with this function must be freed with SDL_FreeCursor(). -proc CreateCursor*(data, mask: ptr byte, w, h, hot_x, hot_y: int): PCursor{.cdecl, +proc createCursor*(data, mask: ptr byte, w, h, hotX, hotY: int): PCursor{.cdecl, importc: "SDL_CreateCursor", dynlib: LibName.} # Set the currently active cursor to the specified one. # If the cursor is currently visible, the change will be immediately # represented on the display. -proc SetCursor*(cursor: PCursor){.cdecl, importc: "SDL_SetCursor", +proc setCursor*(cursor: PCursor){.cdecl, importc: "SDL_SetCursor", dynlib: LibName.} # Returns the currently active cursor. -proc GetCursor*(): PCursor{.cdecl, importc: "SDL_GetCursor", dynlib: LibName.} +proc getCursor*(): PCursor{.cdecl, importc: "SDL_GetCursor", dynlib: LibName.} # Deallocates a cursor created with SDL_CreateCursor(). -proc FreeCursor*(cursor: PCursor){.cdecl, importc: "SDL_FreeCursor", +proc freeCursor*(cursor: PCursor){.cdecl, importc: "SDL_FreeCursor", dynlib: LibName.} # Toggle whether or not the cursor is shown on the screen. # The cursor start off displayed, but can be turned off. # SDL_ShowCursor() returns 1 if the cursor was being displayed # before the call, or 0 if it was not. You can query the current # state by passing a 'toggle' value of -1. -proc ShowCursor*(toggle: int): int{.cdecl, importc: "SDL_ShowCursor", +proc showCursor*(toggle: int): int{.cdecl, importc: "SDL_ShowCursor", dynlib: LibName.} -proc BUTTON*(Button: int): int +proc button*(b: int): int #------------------------------------------------------------------------------ # Keyboard-routines #------------------------------------------------------------------------------ @@ -2296,12 +2289,12 @@ proc BUTTON*(Button: int): int # If 'enable' is 0, translation is disabled. # If 'enable' is -1, the translation state is not changed. # It returns the previous state of keyboard translation. -proc EnableUNICODE*(enable: int): int{.cdecl, importc: "SDL_EnableUNICODE", +proc enableUNICODE*(enable: int): int{.cdecl, importc: "SDL_EnableUNICODE", dynlib: LibName.} # If 'delay' is set to 0, keyboard repeat is disabled. -proc EnableKeyRepeat*(delay: int, interval: int): int{.cdecl, +proc enableKeyRepeat*(delay: int, interval: int): int{.cdecl, importc: "SDL_EnableKeyRepeat", dynlib: LibName.} -proc GetKeyRepeat*(delay: PInteger, interval: PInteger){.cdecl, +proc getKeyRepeat*(delay: PInteger, interval: PInteger){.cdecl, importc: "SDL_GetKeyRepeat", dynlib: LibName.} # Get a snapshot of the current state of the keyboard. # Returns an array of keystates, indexed by the SDLK_* syms. @@ -2309,16 +2302,16 @@ proc GetKeyRepeat*(delay: PInteger, interval: PInteger){.cdecl, # # byte *keystate = SDL_GetKeyState(NULL); # if ( keystate[SDLK_RETURN] ) ... <RETURN> is pressed -proc GetKeyState*(numkeys: pointer): ptr byte{.cdecl, importc: "SDL_GetKeyState", +proc getKeyState*(numkeys: pointer): ptr byte{.cdecl, importc: "SDL_GetKeyState", dynlib: LibName.} # Get the current key modifier state -proc GetModState*(): TMod{.cdecl, importc: "SDL_GetModState", dynlib: LibName.} +proc getModState*(): TMod{.cdecl, importc: "SDL_GetModState", dynlib: LibName.} # Set the current key modifier state # This does not change the keyboard state, only the key modifier flags. -proc SetModState*(modstate: TMod){.cdecl, importc: "SDL_SetModState", +proc setModState*(modstate: TMod){.cdecl, importc: "SDL_SetModState", dynlib: LibName.} # Get the name of an SDL virtual keysym -proc GetKeyName*(key: TKey): cstring{.cdecl, importc: "SDL_GetKeyName", +proc getKeyName*(key: TKey): cstring{.cdecl, importc: "SDL_GetKeyName", dynlib: LibName.} #------------------------------------------------------------------------------ # Active Routines @@ -2327,96 +2320,96 @@ proc GetKeyName*(key: TKey): cstring{.cdecl, importc: "SDL_GetKeyName", # bitwise combination of SDL_APPMOUSEFOCUS, SDL_APPINPUTFOCUS, and # SDL_APPACTIVE. If SDL_APPACTIVE is set, then the user is able to # see your application, otherwise it has been iconified or disabled. -proc GetAppState*(): byte{.cdecl, importc: "SDL_GetAppState", dynlib: LibName.} +proc getAppState*(): byte{.cdecl, importc: "SDL_GetAppState", dynlib: LibName.} # Mutex functions # Create a mutex, initialized unlocked -proc CreateMutex*(): PMutex{.cdecl, importc: "SDL_CreateMutex", dynlib: LibName.} +proc createMutex*(): PMutex{.cdecl, importc: "SDL_CreateMutex", dynlib: LibName.} # Lock the mutex (Returns 0, or -1 on error) -proc mutexP*(mutex: Pmutex): int{.cdecl, importc: "SDL_mutexP", dynlib: LibName.} -proc LockMutex*(mutex: Pmutex): int +proc mutexP*(mutex: PMutex): int{.cdecl, importc: "SDL_mutexP", dynlib: LibName.} +proc lockMutex*(mutex: PMutex): int # Unlock the mutex (Returns 0, or -1 on error) -proc mutexV*(mutex: Pmutex): int{.cdecl, importc: "SDL_mutexV", dynlib: LibName.} -proc UnlockMutex*(mutex: Pmutex): int +proc mutexV*(mutex: PMutex): int{.cdecl, importc: "SDL_mutexV", dynlib: LibName.} +proc unlockMutex*(mutex: PMutex): int # Destroy a mutex -proc DestroyMutex*(mutex: Pmutex){.cdecl, importc: "SDL_DestroyMutex", +proc destroyMutex*(mutex: PMutex){.cdecl, importc: "SDL_DestroyMutex", dynlib: LibName.} # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # Semaphore functions # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # Create a semaphore, initialized with value, returns NULL on failure. -proc CreateSemaphore*(initial_value: int32): PSem{.cdecl, +proc createSemaphore*(initialValue: int32): PSem{.cdecl, importc: "SDL_CreateSemaphore", dynlib: LibName.} # Destroy a semaphore -proc DestroySemaphore*(sem: Psem){.cdecl, importc: "SDL_DestroySemaphore", +proc destroySemaphore*(sem: PSem){.cdecl, importc: "SDL_DestroySemaphore", dynlib: LibName.} # This function suspends the calling thread until the semaphore pointed # to by sem has a positive count. It then atomically decreases the semaphore # count. -proc SemWait*(sem: Psem): int{.cdecl, importc: "SDL_SemWait", dynlib: LibName.} +proc semWait*(sem: PSem): int{.cdecl, importc: "SDL_SemWait", dynlib: LibName.} # Non-blocking variant of SDL_SemWait(), returns 0 if the wait succeeds, # SDL_MUTEX_TIMEDOUT if the wait would block, and -1 on error. -proc SemTryWait*(sem: Psem): int{.cdecl, importc: "SDL_SemTryWait", +proc semTryWait*(sem: PSem): int{.cdecl, importc: "SDL_SemTryWait", dynlib: LibName.} # Variant of SDL_SemWait() with a timeout in milliseconds, returns 0 if # the wait succeeds, SDL_MUTEX_TIMEDOUT if the wait does not succeed in # the allotted time, and -1 on error. # On some platforms this function is implemented by looping with a delay # of 1 ms, and so should be avoided if possible. -proc SemWaitTimeout*(sem: Psem, ms: int32): int{.cdecl, +proc semWaitTimeout*(sem: PSem, ms: int32): int{.cdecl, importc: "SDL_SemWaitTimeout", dynlib: LibName.} # Atomically increases the semaphore's count (not blocking), returns 0, # or -1 on error. -proc SemPost*(sem: Psem): int{.cdecl, importc: "SDL_SemPost", dynlib: LibName.} +proc semPost*(sem: PSem): int{.cdecl, importc: "SDL_SemPost", dynlib: LibName.} # Returns the current count of the semaphore -proc SemValue*(sem: Psem): int32{.cdecl, importc: "SDL_SemValue", +proc semValue*(sem: PSem): int32{.cdecl, importc: "SDL_SemValue", dynlib: LibName.} # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # Condition variable functions # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # Create a condition variable -proc CreateCond*(): PCond{.cdecl, importc: "SDL_CreateCond", dynlib: LibName.} +proc createCond*(): PCond{.cdecl, importc: "SDL_CreateCond", dynlib: LibName.} # Destroy a condition variable -proc DestroyCond*(cond: PCond){.cdecl, importc: "SDL_DestroyCond", +proc destroyCond*(cond: PCond){.cdecl, importc: "SDL_DestroyCond", dynlib: LibName.} # Restart one of the threads that are waiting on the condition variable, # returns 0 or -1 on error. -proc CondSignal*(cond: Pcond): int{.cdecl, importc: "SDL_CondSignal", +proc condSignal*(cond: PCond): int{.cdecl, importc: "SDL_CondSignal", dynlib: LibName.} # Restart all threads that are waiting on the condition variable, # returns 0 or -1 on error. -proc CondBroadcast*(cond: Pcond): int{.cdecl, importc: "SDL_CondBroadcast", +proc condBroadcast*(cond: PCond): int{.cdecl, importc: "SDL_CondBroadcast", dynlib: LibName.} # Wait on the condition variable, unlocking the provided mutex. # The mutex must be locked before entering this function! # Returns 0 when it is signaled, or -1 on error. -proc CondWait*(cond: Pcond, mut: Pmutex): int{.cdecl, importc: "SDL_CondWait", +proc condWait*(cond: PCond, mut: PMutex): int{.cdecl, importc: "SDL_CondWait", dynlib: LibName.} # Waits for at most 'ms' milliseconds, and returns 0 if the condition # variable is signaled, SDL_MUTEX_TIMEDOUT if the condition is not # signaled in the allotted time, and -1 on error. # On some platforms this function is implemented by looping with a delay # of 1 ms, and so should be avoided if possible. -proc CondWaitTimeout*(cond: Pcond, mut: Pmutex, ms: int32): int{.cdecl, +proc condWaitTimeout*(cond: PCond, mut: PMutex, ms: int32): int{.cdecl, importc: "SDL_CondWaitTimeout", dynlib: LibName.} # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # Condition variable functions # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * # Create a thread -proc CreateThread*(fn, data: Pointer): PThread{.cdecl, +proc createThread*(fn, data: pointer): PThread{.cdecl, importc: "SDL_CreateThread", dynlib: LibName.} # Get the 32-bit thread identifier for the current thread -proc ThreadID*(): int32{.cdecl, importc: "SDL_ThreadID", dynlib: LibName.} +proc threadID*(): int32{.cdecl, importc: "SDL_ThreadID", dynlib: LibName.} # Get the 32-bit thread identifier for the specified thread, # equivalent to SDL_ThreadID() if the specified thread is NULL. -proc GetThreadID*(thread: PThread): int32{.cdecl, importc: "SDL_GetThreadID", +proc getThreadID*(thread: PThread): int32{.cdecl, importc: "SDL_GetThreadID", dynlib: LibName.} # Wait for a thread to finish. # The return code for the thread function is placed in the area # pointed to by 'status', if 'status' is not NULL. -proc WaitThread*(thread: PThread, status: var int){.cdecl, +proc waitThread*(thread: PThread, status: var int){.cdecl, importc: "SDL_WaitThread", dynlib: LibName.} # Forcefully kill a thread without worrying about its state -proc KillThread*(thread: PThread){.cdecl, importc: "SDL_KillThread", +proc killThread*(thread: PThread){.cdecl, importc: "SDL_KillThread", dynlib: LibName.} #------------------------------------------------------------------------------ # Get Environment Routines @@ -2427,7 +2420,7 @@ proc KillThread*(thread: PThread){.cdecl, importc: "SDL_KillThread", # * returns 1 if the function is implemented. If it's not implemented, or # * the version member of the 'info' structure is invalid, it returns 0. # * -proc GetWMInfo*(info: PSysWMinfo): int{.cdecl, importc: "SDL_GetWMInfo", +proc getWMInfo*(info: PSysWMinfo): int{.cdecl, importc: "SDL_GetWMInfo", dynlib: LibName.} #------------------------------------------------------------------------------ #SDL_loadso.h @@ -2435,115 +2428,111 @@ proc GetWMInfo*(info: PSysWMinfo): int{.cdecl, importc: "SDL_GetWMInfo", # * to the object handle (or NULL if there was an error). # * The 'sofile' parameter is a system dependent name of the object file. # * -proc LoadObject*(sofile: cstring): Pointer{.cdecl, importc: "SDL_LoadObject", +proc loadObject*(sofile: cstring): pointer{.cdecl, importc: "SDL_LoadObject", dynlib: LibName.} #* Given an object handle, this function looks up the address of the # * named function in the shared object and returns it. This address # * is no longer valid after calling SDL_UnloadObject(). # * -proc LoadFunction*(handle: Pointer, name: cstring): Pointer{.cdecl, +proc loadFunction*(handle: pointer, name: cstring): pointer{.cdecl, importc: "SDL_LoadFunction", dynlib: LibName.} #* Unload a shared object from memory * -proc UnloadObject*(handle: Pointer){.cdecl, importc: "SDL_UnloadObject", +proc unloadObject*(handle: pointer){.cdecl, importc: "SDL_UnloadObject", dynlib: LibName.} #------------------------------------------------------------------------------ -proc Swap32*(D: int32): int32 +proc swap32*(d: int32): int32 # Bitwise Checking functions -proc IsBitOn*(value: int, bit: int8): bool -proc TurnBitOn*(value: int, bit: int8): int -proc TurnBitOff*(value: int, bit: int8): int +proc isBitOn*(value: int, bit: int8): bool +proc turnBitOn*(value: int, bit: int8): int +proc turnBitOff*(value: int, bit: int8): int # implementation -proc TABLESIZE(table: cstring): int = - Result = SizeOf(table) div SizeOf(table[0]) +proc tablesize(table: cstring): int = + result = sizeOf(table) div sizeOf(table[0]) -proc OutOfMemory() = - when not (defined(WINDOWS)): Error(ENOMEM) - -proc RWSeek(context: PRWops, offset: int, whence: int): int = - Result = context.seek(context, offset, whence) +proc rwSeek(context: PRWops, offset: int, whence: int): int = + result = context.seek(context, offset, whence) -proc RWTell(context: PRWops): int = - Result = context.seek(context, 0, 1) +proc rwTell(context: PRWops): int = + result = context.seek(context, 0, 1) -proc RWRead(context: PRWops, theptr: Pointer, size: int, n: int): int = - Result = context.read(context, theptr, size, n) +proc rwRead(context: PRWops, theptr: pointer, size: int, n: int): int = + result = context.read(context, theptr, size, n) -proc RWWrite(context: PRWops, theptr: Pointer, size: int, n: int): int = - Result = context.write(context, theptr, size, n) +proc rwWrite(context: PRWops, theptr: pointer, size: int, n: int): int = + result = context.write(context, theptr, size, n) -proc RWClose(context: PRWops): int = - Result = context.closeFile(context) +proc rwClose(context: PRWops): int = + result = context.closeFile(context) -proc LoadWAV(filename: cstring, spec: PAudioSpec, audio_buf: ptr byte, +proc loadWAV(filename: cstring, spec: PAudioSpec, audioBuf: ptr byte, audiolen: PUInt32): PAudioSpec = - Result = LoadWAV_RW(RWFromFile(filename, "rb"), 1, spec, audio_buf, audiolen) + result = loadWAV_RW(rWFromFile(filename, "rb"), 1, spec, audioBuf, audiolen) -proc CDInDrive(status: TCDStatus): bool = - Result = ord(status) > ord(CD_ERROR) +proc cdInDrive(status: TCDStatus): bool = + result = ord(status) > ord(CD_ERROR) -proc FRAMES_TO_MSF(frames: int, M: var int, S: var int, F: var int) = - var value: int - value = frames - F = value mod CD_FPS +proc framesToMsf*(frames: int; m, s, f: var int) = + var value = frames + f = value mod CD_FPS value = value div CD_FPS - S = value mod 60 + s = value mod 60 value = value div 60 - M = value + m = value -proc MSF_TO_FRAMES(M: int, S: int, F: int): int = - Result = M * 60 * CD_FPS + S * CD_FPS + F +proc msfToFrames*(m, s, f: int): int = + result = m * 60 * CD_FPS + s * CD_FPS + f -proc VERSION(X: var TVersion) = - X.major = MAJOR_VERSION - X.minor = MINOR_VERSION - X.patch = PATCHLEVEL +proc version(x: var Tversion) = + x.major = MAJOR_VERSION + x.minor = MINOR_VERSION + x.patch = PATCHLEVEL -proc VERSIONNUM(X, Y, Z: int): int = - Result = X * 1000 + Y * 100 + Z +proc versionnum(x, y, z: int): int = + result = x * 1000 + y * 100 + z -proc COMPILEDVERSION(): int = - Result = VERSIONNUM(MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL) +proc compiledversion(): int = + result = versionnum(MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL) -proc VERSION_ATLEAST(X, Y, Z: int): bool = - Result = (COMPILEDVERSION() >= VERSIONNUM(X, Y, Z)) +proc versionAtleast(x, y, z: int): bool = + result = (compiledversion() >= versionnum(x, y, z)) -proc LoadBMP(filename: cstring): PSurface = - Result = LoadBMP_RW(RWFromFile(filename, "rb"), 1) +proc loadBMP(filename: cstring): PSurface = + result = loadBMP_RW(rWFromFile(filename, "rb"), 1) -proc SaveBMP(surface: PSurface, filename: cstring): int = - Result = SaveBMP_RW(surface, RWFromFile(filename, "wb"), 1) +proc saveBMP(surface: PSurface, filename: cstring): int = + result = saveBMP_RW(surface, rWFromFile(filename, "wb"), 1) -proc BlitSurface(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int = - Result = UpperBlit(src, srcrect, dst, dstrect) +proc blitSurface(src: PSurface, srcrect: PRect, dst: PSurface, dstrect: PRect): int = + result = upperBlit(src, srcrect, dst, dstrect) -proc AllocSurface(flags: int32, width, height, depth: int, - RMask, GMask, BMask, AMask: int32): PSurface = - Result = CreateRGBSurface(flags, width, height, depth, RMask, GMask, BMask, - AMask) +proc allocSurface(flags: int32, width, height, depth: int, + rMask, gMask, bMask, aMask: int32): PSurface = + result = createRGBSurface(flags, width, height, depth, rMask, gMask, bMask, + aMask) -proc MustLock(Surface: PSurface): bool = - Result = ((surface[].offset != 0) or - ((surface[].flags and (HWSURFACE or ASYNCBLIT or RLEACCEL)) != 0)) +proc mustLock(surface: PSurface): bool = + result = ((surface.offset != 0) or + ((surface.flags and (HWSURFACE or ASYNCBLIT or RLEACCEL)) != 0)) -proc LockMutex(mutex: Pmutex): int = - Result = mutexP(mutex) +proc lockMutex(mutex: PMutex): int = + result = mutexP(mutex) -proc UnlockMutex(mutex: Pmutex): int = - Result = mutexV(mutex) +proc unlockMutex(mutex: PMutex): int = + result = mutexV(mutex) -proc BUTTON(Button: int): int = - Result = PRESSED shl (Button - 1) +proc button(b: int): int = + result = PRESSED shl (b - 1) -proc Swap32(D: int32): int32 = - Result = ((D shl 24) or ((D shl 8) and 0x00FF0000) or - ((D shr 8) and 0x0000FF00) or (D shr 24)) +proc swap32(d: int32): int32 = + result = ((d shl 24) or ((d shl 8) and 0x00FF0000) or + ((d shr 8) and 0x0000FF00) or (d shr 24)) -proc IsBitOn(value: int, bit: int8): bool = +proc isBitOn(value: int, bit: int8): bool = result = ((value and (1 shl ze(bit))) != 0) -proc TurnBitOn(value: int, bit: int8): int = +proc turnBitOn(value: int, bit: int8): int = result = (value or (1 shl ze(bit))) -proc TurnBitOff(value: int, bit: int8): int = +proc turnBitOff(value: int, bit: int8): int = result = (value and not (1 shl ze(bit))) diff --git a/lib/wrappers/sdl/sdl_gfx.nim b/lib/wrappers/sdl/sdl_gfx.nim index cf36c4989..5523ad0a2 100644 --- a/lib/wrappers/sdl/sdl_gfx.nim +++ b/lib/wrappers/sdl/sdl_gfx.nim @@ -39,10 +39,10 @@ const # Some rates in Hz type PFPSmanager* = ptr TFPSmanager TFPSmanager*{.final.} = object # ---- Structures - framecount*: Uint32 + framecount*: uint32 rateticks*: float32 - lastticks*: Uint32 - rate*: Uint32 + lastticks*: uint32 + rate*: uint32 PColorRGBA* = ptr TColorRGBA TColorRGBA*{.final.} = object @@ -79,102 +79,102 @@ proc framerateDelay*(manager: PFPSmanager){.cdecl, # # Note: all ___Color routines expect the color to be in format 0xRRGGBBAA # Pixel -proc pixelColor*(dst: PSurface, x: int16, y: int16, color: Uint32): cint{. +proc pixelColor*(dst: PSurface, x: int16, y: int16, color: uint32): cint{. cdecl, importc: "pixelColor", dynlib: gfxLibName.} proc pixelRGBA*(dst: PSurface, x: int16, y: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "pixelRGBA", dynlib: gfxLibName.} # Horizontal line -proc hlineColor*(dst: PSurface, x1: int16, x2: int16, y: int16, color: Uint32): cint{. +proc hlineColor*(dst: PSurface, x1: int16, x2: int16, y: int16, color: uint32): cint{. cdecl, importc: "hlineColor", dynlib: gfxLibName.} proc hlineRGBA*(dst: PSurface, x1: int16, x2: int16, y: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "hlineRGBA", dynlib: gfxLibName.} # Vertical line -proc vlineColor*(dst: PSurface, x: int16, y1: int16, y2: int16, color: Uint32): cint{. +proc vlineColor*(dst: PSurface, x: int16, y1: int16, y2: int16, color: uint32): cint{. cdecl, importc: "vlineColor", dynlib: gfxLibName.} proc vlineRGBA*(dst: PSurface, x: int16, y1: int16, y2: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "vlineRGBA", dynlib: gfxLibName.} # Rectangle proc rectangleColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, - y2: int16, color: Uint32): cint{.cdecl, + y2: int16, color: uint32): cint{.cdecl, importc: "rectangleColor", dynlib: gfxLibName.} proc rectangleRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, r: byte, g: byte, b: byte, a: byte): cint{. cdecl, importc: "rectangleRGBA", dynlib: gfxLibName.} # Filled rectangle (Box) proc boxColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, - color: Uint32): cint{.cdecl, importc: "boxColor", + color: uint32): cint{.cdecl, importc: "boxColor", dynlib: gfxLibName.} proc boxRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "boxRGBA", dynlib: gfxLibName.} # Line proc lineColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, - color: Uint32): cint{.cdecl, importc: "lineColor", + color: uint32): cint{.cdecl, importc: "lineColor", dynlib: gfxLibName.} proc lineRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "lineRGBA", dynlib: gfxLibName.} # AA Line proc aalineColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, - color: Uint32): cint{.cdecl, importc: "aalineColor", + color: uint32): cint{.cdecl, importc: "aalineColor", dynlib: gfxLibName.} proc aalineRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "aalineRGBA", dynlib: gfxLibName.} # Circle -proc circleColor*(dst: PSurface, x: int16, y: int16, r: int16, color: Uint32): cint{. +proc circleColor*(dst: PSurface, x: int16, y: int16, r: int16, color: uint32): cint{. cdecl, importc: "circleColor", dynlib: gfxLibName.} proc circleRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "circleRGBA", dynlib: gfxLibName.} # AA Circle proc aacircleColor*(dst: PSurface, x: int16, y: int16, r: int16, - color: Uint32): cint{.cdecl, importc: "aacircleColor", + color: uint32): cint{.cdecl, importc: "aacircleColor", dynlib: gfxLibName.} proc aacircleRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "aacircleRGBA", dynlib: gfxLibName.} # Filled Circle proc filledCircleColor*(dst: PSurface, x: int16, y: int16, r: int16, - color: Uint32): cint{.cdecl, + color: uint32): cint{.cdecl, importc: "filledCircleColor", dynlib: gfxLibName.} proc filledCircleRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "filledCircleRGBA", dynlib: gfxLibName.} # Ellipse proc ellipseColor*(dst: PSurface, x: int16, y: int16, rx: int16, ry: int16, - color: Uint32): cint{.cdecl, importc: "ellipseColor", + color: uint32): cint{.cdecl, importc: "ellipseColor", dynlib: gfxLibName.} proc ellipseRGBA*(dst: PSurface, x: int16, y: int16, rx: int16, ry: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "ellipseRGBA", dynlib: gfxLibName.} # AA Ellipse proc aaellipseColor*(dst: PSurface, xc: int16, yc: int16, rx: int16, - ry: int16, color: Uint32): cint{.cdecl, + ry: int16, color: uint32): cint{.cdecl, importc: "aaellipseColor", dynlib: gfxLibName.} proc aaellipseRGBA*(dst: PSurface, x: int16, y: int16, rx: int16, ry: int16, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "aaellipseRGBA", dynlib: gfxLibName.} # Filled Ellipse proc filledEllipseColor*(dst: PSurface, x: int16, y: int16, rx: int16, - ry: int16, color: Uint32): cint{.cdecl, + ry: int16, color: uint32): cint{.cdecl, importc: "filledEllipseColor", dynlib: gfxLibName.} proc filledEllipseRGBA*(dst: PSurface, x: int16, y: int16, rx: int16, ry: int16, r: byte, g: byte, b: byte, a: byte): cint{. cdecl, importc: "filledEllipseRGBA", dynlib: gfxLibName.} # Pie proc pieColor*(dst: PSurface, x: int16, y: int16, rad: int16, start: int16, - finish: int16, color: Uint32): cint{.cdecl, importc: "pieColor", + finish: int16, color: uint32): cint{.cdecl, importc: "pieColor", dynlib: gfxLibName.} proc pieRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, start: int16, finish: int16, r: byte, g: byte, b: byte, a: byte): cint{. cdecl, importc: "pieRGBA", dynlib: gfxLibName.} # Filled Pie proc filledPieColor*(dst: PSurface, x: int16, y: int16, rad: int16, - start: int16, finish: int16, color: Uint32): cint{.cdecl, + start: int16, finish: int16, color: uint32): cint{.cdecl, importc: "filledPieColor", dynlib: gfxLibName.} proc filledPieRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, start: int16, finish: int16, r: byte, g: byte, b: byte, @@ -182,14 +182,14 @@ proc filledPieRGBA*(dst: PSurface, x: int16, y: int16, rad: int16, dynlib: gfxLibName.} # Trigon proc trigonColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, - x3: int16, y3: int16, color: Uint32): cint{.cdecl, + x3: int16, y3: int16, color: uint32): cint{.cdecl, importc: "trigonColor", dynlib: gfxLibName.} proc trigonRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, x3: int16, y3: int16, r: byte, g: byte, b: byte, a: byte): cint{. cdecl, importc: "trigonRGBA", dynlib: gfxLibName.} # AA-Trigon proc aatrigonColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, - y2: int16, x3: int16, y3: int16, color: Uint32): cint{. + y2: int16, x3: int16, y3: int16, color: uint32): cint{. cdecl, importc: "aatrigonColor", dynlib: gfxLibName.} proc aatrigonRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, x3: int16, y3: int16, r: byte, g: byte, @@ -197,7 +197,7 @@ proc aatrigonRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, dynlib: gfxLibName.} # Filled Trigon proc filledTrigonColor*(dst: PSurface, x1: int16, y1: int16, x2: int16, - y2: int16, x3: int16, y3: int16, color: Uint32): cint{. + y2: int16, x3: int16, y3: int16, color: uint32): cint{. cdecl, importc: "filledTrigonColor", dynlib: gfxLibName.} proc filledTrigonRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, y2: int16, x3: int16, y3: int16, r: byte, g: byte, @@ -205,21 +205,21 @@ proc filledTrigonRGBA*(dst: PSurface, x1: int16, y1: int16, x2: int16, importc: "filledTrigonRGBA", dynlib: gfxLibName.} # Polygon proc polygonColor*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, - color: Uint32): cint{.cdecl, importc: "polygonColor", + color: uint32): cint{.cdecl, importc: "polygonColor", dynlib: gfxLibName.} proc polygonRGBA*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "polygonRGBA", dynlib: gfxLibName.} # AA-Polygon proc aapolygonColor*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, - color: Uint32): cint{.cdecl, importc: "aapolygonColor", + color: uint32): cint{.cdecl, importc: "aapolygonColor", dynlib: gfxLibName.} proc aapolygonRGBA*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "aapolygonRGBA", dynlib: gfxLibName.} # Filled Polygon proc filledPolygonColor*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, - color: Uint32): cint{.cdecl, + color: uint32): cint{.cdecl, importc: "filledPolygonColor", dynlib: gfxLibName.} proc filledPolygonRGBA*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, @@ -227,23 +227,23 @@ proc filledPolygonRGBA*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, # Bezier # s = number of steps proc bezierColor*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, s: cint, - color: Uint32): cint{.cdecl, importc: "bezierColor", + color: uint32): cint{.cdecl, importc: "bezierColor", dynlib: gfxLibName.} proc bezierRGBA*(dst: PSurface, vx: ptr int16, vy: ptr int16, n: cint, s: cint, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "bezierRGBA", dynlib: gfxLibName.} # Characters/Strings -proc characterColor*(dst: PSurface, x: int16, y: int16, c: char, color: Uint32): cint{. +proc characterColor*(dst: PSurface, x: int16, y: int16, c: char, color: uint32): cint{. cdecl, importc: "characterColor", dynlib: gfxLibName.} proc characterRGBA*(dst: PSurface, x: int16, y: int16, c: char, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "characterRGBA", dynlib: gfxLibName.} -proc stringColor*(dst: PSurface, x: int16, y: int16, c: cstring, color: Uint32): cint{. +proc stringColor*(dst: PSurface, x: int16, y: int16, c: cstring, color: uint32): cint{. cdecl, importc: "stringColor", dynlib: gfxLibName.} proc stringRGBA*(dst: PSurface, x: int16, y: int16, c: cstring, r: byte, g: byte, b: byte, a: byte): cint{.cdecl, importc: "stringRGBA", dynlib: gfxLibName.} -proc gfxPrimitivesSetFont*(fontdata: Pointer, cw: cint, ch: cint){.cdecl, +proc gfxPrimitivesSetFont*(fontdata: pointer, cw: cint, ch: cint){.cdecl, importc: "gfxPrimitivesSetFont", dynlib: gfxLibName.} # # @@ -271,132 +271,132 @@ proc imageFilterMMXon*(){.cdecl, importc: "SDL_imageFilterMMXon", # -1 Error (internal error, parameter error) # # SDL_imageFilterAdd: D = saturation255(S1 + S2) -proc imageFilterAdd*(Src1: cstring, Src2: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterAdd*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterAdd", dynlib: gfxLibName.} # SDL_imageFilterMean: D = S1/2 + S2/2 -proc imageFilterMean*(Src1: cstring, Src2: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterMean*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterMean", dynlib: gfxLibName.} # SDL_imageFilterSub: D = saturation0(S1 - S2) -proc imageFilterSub*(Src1: cstring, Src2: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterSub*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterSub", dynlib: gfxLibName.} # SDL_imageFilterAbsDiff: D = | S1 - S2 | -proc imageFilterAbsDiff*(Src1: cstring, Src2: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterAbsDiff*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterAbsDiff", dynlib: gfxLibName.} # SDL_imageFilterMult: D = saturation(S1 * S2) -proc imageFilterMult*(Src1: cstring, Src2: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterMult*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterMult", dynlib: gfxLibName.} # SDL_imageFilterMultNor: D = S1 * S2 (non-MMX) -proc imageFilterMultNor*(Src1: cstring, Src2: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterMultNor*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterMultNor", dynlib: gfxLibName.} # SDL_imageFilterMultDivby2: D = saturation255(S1/2 * S2) -proc imageFilterMultDivby2*(Src1: cstring, Src2: cstring, Dest: cstring, +proc imageFilterMultDivby2*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.cdecl, importc: "SDL_imageFilterMultDivby2", dynlib: gfxLibName.} # SDL_imageFilterMultDivby4: D = saturation255(S1/2 * S2/2) -proc imageFilterMultDivby4*(Src1: cstring, Src2: cstring, Dest: cstring, +proc imageFilterMultDivby4*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{.cdecl, importc: "SDL_imageFilterMultDivby4", dynlib: gfxLibName.} # SDL_imageFilterBitAnd: D = S1 & S2 -proc imageFilterBitAnd*(Src1: cstring, Src2: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterBitAnd*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterBitAnd", dynlib: gfxLibName.} # SDL_imageFilterBitOr: D = S1 | S2 -proc imageFilterBitOr*(Src1: cstring, Src2: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterBitOr*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterBitOr", dynlib: gfxLibName.} # SDL_imageFilterDiv: D = S1 / S2 (non-MMX) -proc imageFilterDiv*(Src1: cstring, Src2: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterDiv*(src1: cstring, src2: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterDiv", dynlib: gfxLibName.} # SDL_imageFilterBitNegation: D = !S -proc imageFilterBitNegation*(Src1: cstring, Dest: cstring, len: cint): cint{. +proc imageFilterBitNegation*(src1: cstring, dest: cstring, len: cint): cint{. cdecl, importc: "SDL_imageFilterBitNegation", dynlib: gfxLibName.} # SDL_imageFilterAddByte: D = saturation255(S + C) -proc imageFilterAddByte*(Src1: cstring, Dest: cstring, len: cint, C: char): cint{. +proc imageFilterAddByte*(src1: cstring, dest: cstring, len: cint, c: char): cint{. cdecl, importc: "SDL_imageFilterAddByte", dynlib: gfxLibName.} # SDL_imageFilterAddUint: D = saturation255(S + (uint)C) -proc imageFilterAddUint*(Src1: cstring, Dest: cstring, len: cint, C: cint): cint{. +proc imageFilterAddUint*(src1: cstring, dest: cstring, len: cint, c: cint): cint{. cdecl, importc: "SDL_imageFilterAddUint", dynlib: gfxLibName.} # SDL_imageFilterAddByteToHalf: D = saturation255(S/2 + C) -proc imageFilterAddByteToHalf*(Src1: cstring, Dest: cstring, len: cint, C: char): cint{. +proc imageFilterAddByteToHalf*(src1: cstring, dest: cstring, len: cint, c: char): cint{. cdecl, importc: "SDL_imageFilterAddByteToHalf", dynlib: gfxLibName.} # SDL_imageFilterSubByte: D = saturation0(S - C) -proc imageFilterSubByte*(Src1: cstring, Dest: cstring, len: cint, C: char): cint{. +proc imageFilterSubByte*(src1: cstring, dest: cstring, len: cint, c: char): cint{. cdecl, importc: "SDL_imageFilterSubByte", dynlib: gfxLibName.} # SDL_imageFilterSubUint: D = saturation0(S - (uint)C) -proc imageFilterSubUint*(Src1: cstring, Dest: cstring, len: cint, C: cint): cint{. +proc imageFilterSubUint*(src1: cstring, dest: cstring, len: cint, c: cint): cint{. cdecl, importc: "SDL_imageFilterSubUint", dynlib: gfxLibName.} # SDL_imageFilterShiftRight: D = saturation0(S >> N) -proc imageFilterShiftRight*(Src1: cstring, Dest: cstring, len: cint, N: char): cint{. +proc imageFilterShiftRight*(src1: cstring, dest: cstring, len: cint, n: char): cint{. cdecl, importc: "SDL_imageFilterShiftRight", dynlib: gfxLibName.} # SDL_imageFilterShiftRightUint: D = saturation0((uint)S >> N) -proc imageFilterShiftRightUint*(Src1: cstring, Dest: cstring, len: cint, N: char): cint{. +proc imageFilterShiftRightUint*(src1: cstring, dest: cstring, len: cint, n: char): cint{. cdecl, importc: "SDL_imageFilterShiftRightUint", dynlib: gfxLibName.} # SDL_imageFilterMultByByte: D = saturation255(S * C) -proc imageFilterMultByByte*(Src1: cstring, Dest: cstring, len: cint, C: char): cint{. +proc imageFilterMultByByte*(src1: cstring, dest: cstring, len: cint, c: char): cint{. cdecl, importc: "SDL_imageFilterMultByByte", dynlib: gfxLibName.} # SDL_imageFilterShiftRightAndMultByByte: D = saturation255((S >> N) * C) -proc imageFilterShiftRightAndMultByByte*(Src1: cstring, Dest: cstring, len: cint, - N: char, C: char): cint{.cdecl, +proc imageFilterShiftRightAndMultByByte*(src1: cstring, dest: cstring, len: cint, + n: char, c: char): cint{.cdecl, importc: "SDL_imageFilterShiftRightAndMultByByte", dynlib: gfxLibName.} # SDL_imageFilterShiftLeftByte: D = (S << N) -proc imageFilterShiftLeftByte*(Src1: cstring, Dest: cstring, len: cint, N: char): cint{. +proc imageFilterShiftLeftByte*(src1: cstring, dest: cstring, len: cint, n: char): cint{. cdecl, importc: "SDL_imageFilterShiftLeftByte", dynlib: gfxLibName.} # SDL_imageFilterShiftLeftUint: D = ((uint)S << N) -proc imageFilterShiftLeftUint*(Src1: cstring, Dest: cstring, len: cint, N: char): cint{. +proc imageFilterShiftLeftUint*(src1: cstring, dest: cstring, len: cint, n: char): cint{. cdecl, importc: "SDL_imageFilterShiftLeftUint", dynlib: gfxLibName.} # SDL_imageFilterShiftLeft: D = saturation255(S << N) -proc imageFilterShiftLeft*(Src1: cstring, Dest: cstring, len: cint, N: char): cint{. +proc imageFilterShiftLeft*(src1: cstring, dest: cstring, len: cint, n: char): cint{. cdecl, importc: "SDL_imageFilterShiftLeft", dynlib: gfxLibName.} # SDL_imageFilterBinarizeUsingThreshold: D = S >= T ? 255:0 -proc imageFilterBinarizeUsingThreshold*(Src1: cstring, Dest: cstring, len: cint, - T: char): cint{.cdecl, +proc imageFilterBinarizeUsingThreshold*(src1: cstring, dest: cstring, len: cint, + t: char): cint{.cdecl, importc: "SDL_imageFilterBinarizeUsingThreshold", dynlib: gfxLibName.} # SDL_imageFilterClipToRange: D = (S >= Tmin) & (S <= Tmax) 255:0 -proc imageFilterClipToRange*(Src1: cstring, Dest: cstring, len: cint, Tmin: int8, - Tmax: int8): cint{.cdecl, +proc imageFilterClipToRange*(src1: cstring, dest: cstring, len: cint, tmin: int8, + tmax: int8): cint{.cdecl, importc: "SDL_imageFilterClipToRange", dynlib: gfxLibName.} # SDL_imageFilterNormalizeLinear: D = saturation255((Nmax - Nmin)/(Cmax - Cmin)*(S - Cmin) + Nmin) -proc imageFilterNormalizeLinear*(Src1: cstring, Dest: cstring, len: cint, - Cmin: cint, Cmax: cint, Nmin: cint, Nmax: cint): cint{. +proc imageFilterNormalizeLinear*(src1: cstring, dest: cstring, len: cint, + cmin: cint, cmax: cint, nmin: cint, nmax: cint): cint{. cdecl, importc: "SDL_imageFilterNormalizeLinear", dynlib: gfxLibName.} # !!! NO C-ROUTINE FOR THESE FUNCTIONS YET !!! # SDL_imageFilterConvolveKernel3x3Divide: Dij = saturation0and255( ... ) -proc imageFilterConvolveKernel3x3Divide*(Src: cstring, Dest: cstring, rows: cint, - columns: cint, Kernel: pointer, Divisor: int8): cint{.cdecl, +proc imageFilterConvolveKernel3x3Divide*(src: cstring, dest: cstring, rows: cint, + columns: cint, kernel: pointer, divisor: int8): cint{.cdecl, importc: "SDL_imageFilterConvolveKernel3x3Divide", dynlib: gfxLibName.} # SDL_imageFilterConvolveKernel5x5Divide: Dij = saturation0and255( ... ) -proc imageFilterConvolveKernel5x5Divide*(Src: cstring, Dest: cstring, rows: cint, - columns: cint, Kernel: pointer, Divisor: int8): cint{.cdecl, +proc imageFilterConvolveKernel5x5Divide*(src: cstring, dest: cstring, rows: cint, + columns: cint, kernel: pointer, divisor: int8): cint{.cdecl, importc: "SDL_imageFilterConvolveKernel5x5Divide", dynlib: gfxLibName.} # SDL_imageFilterConvolveKernel7x7Divide: Dij = saturation0and255( ... ) -proc imageFilterConvolveKernel7x7Divide*(Src: cstring, Dest: cstring, rows: cint, - columns: cint, Kernel: pointer, Divisor: int8): cint{.cdecl, +proc imageFilterConvolveKernel7x7Divide*(src: cstring, dest: cstring, rows: cint, + columns: cint, kernel: pointer, divisor: int8): cint{.cdecl, importc: "SDL_imageFilterConvolveKernel7x7Divide", dynlib: gfxLibName.} # SDL_imageFilterConvolveKernel9x9Divide: Dij = saturation0and255( ... ) -proc imageFilterConvolveKernel9x9Divide*(Src: cstring, Dest: cstring, rows: cint, - columns: cint, Kernel: pointer, Divisor: int8): cint{.cdecl, +proc imageFilterConvolveKernel9x9Divide*(src: cstring, dest: cstring, rows: cint, + columns: cint, kernel: pointer, divisor: int8): cint{.cdecl, importc: "SDL_imageFilterConvolveKernel9x9Divide", dynlib: gfxLibName.} # SDL_imageFilterConvolveKernel3x3ShiftRight: Dij = saturation0and255( ... ) -proc imageFilterConvolveKernel3x3ShiftRight*(Src: cstring, Dest: cstring, - rows: cint, columns: cint, Kernel: pointer, NRightShift: char): cint{.cdecl, +proc imageFilterConvolveKernel3x3ShiftRight*(src: cstring, dest: cstring, + rows: cint, columns: cint, kernel: pointer, nRightShift: char): cint{.cdecl, importc: "SDL_imageFilterConvolveKernel3x3ShiftRight", dynlib: gfxLibName.} # SDL_imageFilterConvolveKernel5x5ShiftRight: Dij = saturation0and255( ... ) -proc imageFilterConvolveKernel5x5ShiftRight*(Src: cstring, Dest: cstring, - rows: cint, columns: cint, Kernel: pointer, NRightShift: char): cint{.cdecl, +proc imageFilterConvolveKernel5x5ShiftRight*(src: cstring, dest: cstring, + rows: cint, columns: cint, kernel: pointer, nRightShift: char): cint{.cdecl, importc: "SDL_imageFilterConvolveKernel5x5ShiftRight", dynlib: gfxLibName.} # SDL_imageFilterConvolveKernel7x7ShiftRight: Dij = saturation0and255( ... ) -proc imageFilterConvolveKernel7x7ShiftRight*(Src: cstring, Dest: cstring, - rows: cint, columns: cint, Kernel: pointer, NRightShift: char): cint{.cdecl, +proc imageFilterConvolveKernel7x7ShiftRight*(src: cstring, dest: cstring, + rows: cint, columns: cint, kernel: pointer, nRightShift: char): cint{.cdecl, importc: "SDL_imageFilterConvolveKernel7x7ShiftRight", dynlib: gfxLibName.} # SDL_imageFilterConvolveKernel9x9ShiftRight: Dij = saturation0and255( ... ) -proc imageFilterConvolveKernel9x9ShiftRight*(Src: cstring, Dest: cstring, - rows: cint, columns: cint, Kernel: pointer, NRightShift: char): cint{.cdecl, +proc imageFilterConvolveKernel9x9ShiftRight*(src: cstring, dest: cstring, + rows: cint, columns: cint, kernel: pointer, nRightShift: char): cint{.cdecl, importc: "SDL_imageFilterConvolveKernel9x9ShiftRight", dynlib: gfxLibName.} # SDL_imageFilterSobelX: Dij = saturation255( ... ) -proc imageFilterSobelX*(Src: cstring, Dest: cstring, rows: cint, columns: cint): cint{. +proc imageFilterSobelX*(src: cstring, dest: cstring, rows: cint, columns: cint): cint{. cdecl, importc: "SDL_imageFilterSobelX", dynlib: gfxLibName.} # SDL_imageFilterSobelXShiftRight: Dij = saturation255( ... ) -proc imageFilterSobelXShiftRight*(Src: cstring, Dest: cstring, rows: cint, - columns: cint, NRightShift: char): cint{.cdecl, +proc imageFilterSobelXShiftRight*(src: cstring, dest: cstring, rows: cint, + columns: cint, nRightShift: char): cint{.cdecl, importc: "SDL_imageFilterSobelXShiftRight", dynlib: gfxLibName.} # Align/restore stack to 32 byte boundary -- Functionality untested! -- proc imageFilterAlignStack*(){.cdecl, importc: "SDL_imageFilterAlignStack", diff --git a/lib/wrappers/sdl/sdl_image.nim b/lib/wrappers/sdl/sdl_image.nim index 2bd731506..9c56e6a46 100644 --- a/lib/wrappers/sdl/sdl_image.nim +++ b/lib/wrappers/sdl/sdl_image.nim @@ -148,13 +148,13 @@ const # This macro can be used to fill a version structure with the compile-time # version of the SDL_image library. -proc IMAGE_VERSION*(X: var TVersion) +proc imageVersion*(x: var Tversion) # This function gets the version of the dynamically linked SDL_image library. # it should NOT be used to fill a version structure, instead you should # use the SDL_IMAGE_VERSION() macro. # -proc IMG_Linked_Version*(): Pversion{.importc: "IMG_Linked_Version", - dynlib: ImageLibName.} +proc imgLinkedVersion*(): Pversion{.importc: "IMG_Linked_Version", + dynlib: ImageLibName.} # Load an image from an SDL data source. # The 'type' may be one of: "BMP", "GIF", "PNG", etc. # @@ -170,74 +170,74 @@ const IMG_INIT_TIF* = 0x00000004 IMG_INIT_WEBP* = 0x00000008 -proc IMG_Init*(flags: cint): int {.cdecl, importc: "IMG_Init", +proc imgInit*(flags: cint): int {.cdecl, importc: "IMG_Init", dynlib: ImageLibName.} -proc IMG_Quit*() {.cdecl, importc: "IMG_Quit", +proc imgQuit*() {.cdecl, importc: "IMG_Quit", dynlib: ImageLibName.} -proc IMG_LoadTyped_RW*(src: PRWops, freesrc: cint, theType: cstring): PSurface{. +proc imgLoadTypedRW*(src: PRWops, freesrc: cint, theType: cstring): PSurface{. cdecl, importc: "IMG_LoadTyped_RW", dynlib: ImageLibName.} # Convenience functions -proc IMG_Load*(theFile: cstring): PSurface{.cdecl, importc: "IMG_Load", +proc imgLoad*(theFile: cstring): PSurface{.cdecl, importc: "IMG_Load", dynlib: ImageLibName.} -proc IMG_Load_RW*(src: PRWops, freesrc: cint): PSurface{.cdecl, +proc imgLoadRW*(src: PRWops, freesrc: cint): PSurface{.cdecl, importc: "IMG_Load_RW", dynlib: ImageLibName.} # Invert the alpha of a surface for use with OpenGL # This function is now a no-op, and only provided for backwards compatibility. -proc IMG_InvertAlpha*(theOn: cint): cint{.cdecl, importc: "IMG_InvertAlpha", +proc imgInvertAlpha*(theOn: cint): cint{.cdecl, importc: "IMG_InvertAlpha", dynlib: ImageLibName.} # Functions to detect a file type, given a seekable source -proc IMG_isBMP*(src: PRWops): cint{.cdecl, importc: "IMG_isBMP", +proc imgIsBMP*(src: PRWops): cint{.cdecl, importc: "IMG_isBMP", dynlib: ImageLibName.} -proc IMG_isGIF*(src: PRWops): cint{.cdecl, importc: "IMG_isGIF", +proc imgIsGIF*(src: PRWops): cint{.cdecl, importc: "IMG_isGIF", dynlib: ImageLibName.} -proc IMG_isJPG*(src: PRWops): cint{.cdecl, importc: "IMG_isJPG", +proc imgIsJPG*(src: PRWops): cint{.cdecl, importc: "IMG_isJPG", dynlib: ImageLibName.} -proc IMG_isLBM*(src: PRWops): cint{.cdecl, importc: "IMG_isLBM", +proc imgIsLBM*(src: PRWops): cint{.cdecl, importc: "IMG_isLBM", dynlib: ImageLibName.} -proc IMG_isPCX*(src: PRWops): cint{.cdecl, importc: "IMG_isPCX", +proc imgIsPCX*(src: PRWops): cint{.cdecl, importc: "IMG_isPCX", dynlib: ImageLibName.} -proc IMG_isPNG*(src: PRWops): cint{.cdecl, importc: "IMG_isPNG", +proc imgIsPNG*(src: PRWops): cint{.cdecl, importc: "IMG_isPNG", dynlib: ImageLibName.} -proc IMG_isPNM*(src: PRWops): cint{.cdecl, importc: "IMG_isPNM", +proc imgIsPNM*(src: PRWops): cint{.cdecl, importc: "IMG_isPNM", dynlib: ImageLibName.} -proc IMG_isTIF*(src: PRWops): cint{.cdecl, importc: "IMG_isTIF", +proc imgIsTIF*(src: PRWops): cint{.cdecl, importc: "IMG_isTIF", dynlib: ImageLibName.} -proc IMG_isXCF*(src: PRWops): cint{.cdecl, importc: "IMG_isXCF", +proc imgIsXCF*(src: PRWops): cint{.cdecl, importc: "IMG_isXCF", dynlib: ImageLibName.} -proc IMG_isXPM*(src: PRWops): cint{.cdecl, importc: "IMG_isXPM", +proc imgIsXPM*(src: PRWops): cint{.cdecl, importc: "IMG_isXPM", dynlib: ImageLibName.} -proc IMG_isXV*(src: PRWops): cint{.cdecl, importc: "IMG_isXV", +proc imgIsXV*(src: PRWops): cint{.cdecl, importc: "IMG_isXV", dynlib: ImageLibName.} # Individual loading functions -proc IMG_LoadBMP_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadBMP_RW", +proc imgLoadBMP_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadBMP_RW", dynlib: ImageLibName.} -proc IMG_LoadGIF_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadGIF_RW", +proc imgLoadGIF_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadGIF_RW", dynlib: ImageLibName.} -proc IMG_LoadJPG_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadJPG_RW", +proc imgLoadJPG_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadJPG_RW", dynlib: ImageLibName.} -proc IMG_LoadLBM_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadLBM_RW", +proc imgLoadLBM_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadLBM_RW", dynlib: ImageLibName.} -proc IMG_LoadPCX_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadPCX_RW", +proc imgLoadPCX_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadPCX_RW", dynlib: ImageLibName.} -proc IMG_LoadPNM_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadPNM_RW", +proc imgLoadPNM_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadPNM_RW", dynlib: ImageLibName.} -proc IMG_LoadPNG_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadPNG_RW", +proc imgLoadPNG_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadPNG_RW", dynlib: ImageLibName.} -proc IMG_LoadTGA_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadTGA_RW", +proc imgLoadTGA_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadTGA_RW", dynlib: ImageLibName.} -proc IMG_LoadTIF_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadTIF_RW", +proc imgLoadTIF_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadTIF_RW", dynlib: ImageLibName.} -proc IMG_LoadXCF_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadXCF_RW", +proc imgLoadXCF_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadXCF_RW", dynlib: ImageLibName.} -proc IMG_LoadXPM_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadXPM_RW", +proc imgLoadXPM_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadXPM_RW", dynlib: ImageLibName.} -proc IMG_LoadXV_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadXV_RW", +proc imgLoadXV_RW*(src: PRWops): PSurface{.cdecl, importc: "IMG_LoadXV_RW", dynlib: ImageLibName.} -proc IMG_ReadXPMFromArray*(xpm: cstringArray): PSurface{.cdecl, +proc imgReadXPMFromArray*(xpm: cstringArray): PSurface{.cdecl, importc: "IMG_ReadXPMFromArray", dynlib: ImageLibName.} -proc IMAGE_VERSION(X: var TVersion) = - X.major = IMAGE_MAJOR_VERSION - X.minor = IMAGE_MINOR_VERSION - X.patch = IMAGE_PATCHLEVEL +proc imageVersion(x: var Tversion) = + x.major = IMAGE_MAJOR_VERSION + x.minor = IMAGE_MINOR_VERSION + x.patch = IMAGE_PATCHLEVEL diff --git a/lib/wrappers/sdl/sdl_mixer.nim b/lib/wrappers/sdl/sdl_mixer.nim index 9199a9271..33a71508a 100644 --- a/lib/wrappers/sdl/sdl_mixer.nim +++ b/lib/wrappers/sdl/sdl_mixer.nim @@ -196,7 +196,7 @@ type #music_cmd.h types PWAVStream* = ptr TWAVStream TWAVStream*{.final.} = object #playmidi.h types - wavefp*: Pointer + wavefp*: pointer start*: int32 stop*: int32 cvt*: TAudioCVT @@ -223,8 +223,8 @@ type #music_cmd.h types volume*: int32 #vf: OggVorbis_File; section*: int32 cvt*: TAudioCVT - len_available*: int32 - snd_available*: pointer + lenAvailable*: int32 + sndAvailable*: pointer TErrorEnum* = enum MMERR_OPENING_FILE, MMERR_OUT_OF_MEMORY, MMERR_DYNAMIC_LINKING, @@ -255,7 +255,7 @@ type #music_cmd.h types TChunk*{.final.} = object allocated*: cint abuf*: pointer - alen*: Uint32 + alen*: uint32 volume*: byte # Per-sample volume, 0-128 TFading* = enum @@ -272,18 +272,18 @@ type #music_cmd.h types # fade_steps : integer; # error : integer; - TMixFunction* = proc (udata, stream: pointer, length: cint): Pointer{. + TMixFunction* = proc (udata, stream: pointer, length: cint): pointer{. cdecl.} # This macro can be used to fill a version structure with the compile-time # version of the SDL_mixer library. -proc VERSION*(X: var sdl.TVersion) +proc version*(x: var sdl.Tversion) # This function gets the version of the dynamically linked SDL_mixer library. # It should NOT be used to fill a version structure, instead you should use the # SDL_MIXER_VERSION() macro. -proc Linked_Version*(): sdl.Pversion{.cdecl, importc: "Mix_Linked_Version", +proc linkedVersion*(): sdl.Pversion{.cdecl, importc: "Mix_Linked_Version", dynlib: MixerLibName.} # Open the mixer with a certain audio format -proc OpenAudio*(frequency: cint, format: Uint16, channels: cint, +proc openAudio*(frequency: cint, format: uint16, channels: cint, chunksize: cint): cint{.cdecl, importc: "Mix_OpenAudio", dynlib: MixerLibName.} # Dynamically change the number of channels managed by the mixer. @@ -291,194 +291,194 @@ proc OpenAudio*(frequency: cint, format: Uint16, channels: cint, # stopped. # This function returns the new number of allocated channels. # -proc AllocateChannels*(numchannels: cint): cint{.cdecl, +proc allocateChannels*(numchannels: cint): cint{.cdecl, importc: "Mix_AllocateChannels", dynlib: MixerLibName.} # Find out what the actual audio device parameters are. # This function returns 1 if the audio has been opened, 0 otherwise. # -proc QuerySpec*(frequency: var cint, format: var Uint16, channels: var cint): cint{. +proc querySpec*(frequency: var cint, format: var uint16, channels: var cint): cint{. cdecl, importc: "Mix_QuerySpec", dynlib: MixerLibName.} # Load a wave file or a music (.mod .s3m .it .xm) file -proc LoadWAV_RW*(src: PRWops, freesrc: cint): PChunk{.cdecl, +proc loadWAV_RW*(src: PRWops, freesrc: cint): PChunk{.cdecl, importc: "Mix_LoadWAV_RW", dynlib: MixerLibName.} -proc LoadWAV*(filename: cstring): PChunk -proc LoadMUS*(filename: cstring): PMusic{.cdecl, importc: "Mix_LoadMUS", +proc loadWAV*(filename: cstring): PChunk +proc loadMUS*(filename: cstring): PMusic{.cdecl, importc: "Mix_LoadMUS", dynlib: MixerLibName.} # Load a wave file of the mixer format from a memory buffer -proc QuickLoad_WAV*(mem: pointer): PChunk{.cdecl, +proc quickLoadWAV*(mem: pointer): PChunk{.cdecl, importc: "Mix_QuickLoad_WAV", dynlib: MixerLibName.} # Free an audio chunk previously loaded -proc FreeChunk*(chunk: PChunk){.cdecl, importc: "Mix_FreeChunk", +proc freeChunk*(chunk: PChunk){.cdecl, importc: "Mix_FreeChunk", dynlib: MixerLibName.} -proc FreeMusic*(music: PMusic){.cdecl, importc: "Mix_FreeMusic", +proc freeMusic*(music: PMusic){.cdecl, importc: "Mix_FreeMusic", dynlib: MixerLibName.} # Find out the music format of a mixer music, or the currently playing # music, if 'music' is NULL. -proc GetMusicType*(music: PMusic): TMusicType{.cdecl, +proc getMusicType*(music: PMusic): TMusicType{.cdecl, importc: "Mix_GetMusicType", dynlib: MixerLibName.} # Set a function that is called after all mixing is performed. # This can be used to provide real-time visual display of the audio stream # or add a custom mixer filter for the stream data. # -proc SetPostMix*(mix_func: TMixFunction, arg: Pointer){.cdecl, +proc setPostMix*(mixFunc: TMixFunction, arg: pointer){.cdecl, importc: "Mix_SetPostMix", dynlib: MixerLibName.} # Add your own music player or additional mixer function. # If 'mix_func' is NULL, the default music player is re-enabled. # -proc HookMusic*(mix_func: TMixFunction, arg: Pointer){.cdecl, +proc hookMusic*(mixFunc: TMixFunction, arg: pointer){.cdecl, importc: "Mix_HookMusic", dynlib: MixerLibName.} # Add your own callback when the music has finished playing. # -proc HookMusicFinished*(music_finished: Pointer){.cdecl, +proc hookMusicFinished*(musicFinished: pointer){.cdecl, importc: "Mix_HookMusicFinished", dynlib: MixerLibName.} # Get a pointer to the user data for the current music hook -proc GetMusicHookData*(): Pointer{.cdecl, importc: "Mix_GetMusicHookData", +proc getMusicHookData*(): pointer{.cdecl, importc: "Mix_GetMusicHookData", dynlib: MixerLibName.} #* Add your own callback when a channel has finished playing. NULL # * to disable callback.* type - TChannel_finished* = proc (channel: cint){.cdecl.} + TChannelFinished* = proc (channel: cint){.cdecl.} -proc ChannelFinished*(channel_finished: TChannel_finished){.cdecl, +proc channelFinished*(channelFinished: TChannelFinished){.cdecl, importc: "Mix_ChannelFinished", dynlib: MixerLibName.} const CHANNEL_POST* = - 2 type - TEffectFunc* = proc (chan: cint, stream: Pointer, length: cint, - udata: Pointer): Pointer{.cdecl.} - TEffectDone* = proc (chan: cint, udata: Pointer): Pointer{.cdecl.} -proc RegisterEffect*(chan: cint, f: TEffectFunc, d: TEffectDone, - arg: Pointer): cint{.cdecl, + TEffectFunc* = proc (chan: cint, stream: pointer, length: cint, + udata: pointer): pointer{.cdecl.} + TEffectDone* = proc (chan: cint, udata: pointer): pointer{.cdecl.} +proc registerEffect*(chan: cint, f: TEffectFunc, d: TEffectDone, + arg: pointer): cint{.cdecl, importc: "Mix_RegisterEffect", dynlib: MixerLibName.} -proc UnregisterEffect*(channel: cint, f: TEffectFunc): cint{.cdecl, +proc unregisterEffect*(channel: cint, f: TEffectFunc): cint{.cdecl, importc: "Mix_UnregisterEffect", dynlib: MixerLibName.} -proc UnregisterAllEffects*(channel: cint): cint{.cdecl, +proc unregisterAllEffects*(channel: cint): cint{.cdecl, importc: "Mix_UnregisterAllEffects", dynlib: MixerLibName.} const EFFECTSMAXSPEED* = "MIX_EFFECTSMAXSPEED" -proc SetPanning*(channel: cint, left: byte, right: byte): cint{.cdecl, +proc setPanning*(channel: cint, left: byte, right: byte): cint{.cdecl, importc: "Mix_SetPanning", dynlib: MixerLibName.} -proc SetPosition*(channel: cint, angle: int16, distance: byte): cint{.cdecl, +proc setPosition*(channel: cint, angle: int16, distance: byte): cint{.cdecl, importc: "Mix_SetPosition", dynlib: MixerLibName.} -proc SetDistance*(channel: cint, distance: byte): cint{.cdecl, +proc setDistance*(channel: cint, distance: byte): cint{.cdecl, importc: "Mix_SetDistance", dynlib: MixerLibName.} -proc SetReverseStereo*(channel: cint, flip: cint): cint{.cdecl, +proc setReverseStereo*(channel: cint, flip: cint): cint{.cdecl, importc: "Mix_SetReverseStereo", dynlib: MixerLibName.} -proc ReserveChannels*(num: cint): cint{.cdecl, importc: "Mix_ReserveChannels", +proc reserveChannels*(num: cint): cint{.cdecl, importc: "Mix_ReserveChannels", dynlib: MixerLibName.} -proc GroupChannel*(which: cint, tag: cint): cint{.cdecl, +proc groupChannel*(which: cint, tag: cint): cint{.cdecl, importc: "Mix_GroupChannel", dynlib: MixerLibName.} -proc GroupChannels*(`from`: cint, `to`: cint, tag: cint): cint{.cdecl, +proc groupChannels*(`from`: cint, `to`: cint, tag: cint): cint{.cdecl, importc: "Mix_GroupChannels", dynlib: MixerLibName.} -proc GroupAvailable*(tag: cint): cint{.cdecl, importc: "Mix_GroupAvailable", +proc groupAvailable*(tag: cint): cint{.cdecl, importc: "Mix_GroupAvailable", dynlib: MixerLibName.} -proc GroupCount*(tag: cint): cint{.cdecl, importc: "Mix_GroupCount", +proc groupCount*(tag: cint): cint{.cdecl, importc: "Mix_GroupCount", dynlib: MixerLibName.} -proc GroupOldest*(tag: cint): cint{.cdecl, importc: "Mix_GroupOldest", +proc groupOldest*(tag: cint): cint{.cdecl, importc: "Mix_GroupOldest", dynlib: MixerLibName.} -proc GroupNewer*(tag: cint): cint{.cdecl, importc: "Mix_GroupNewer", +proc groupNewer*(tag: cint): cint{.cdecl, importc: "Mix_GroupNewer", dynlib: MixerLibName.} -proc PlayChannelTimed*(channel: cint, chunk: PChunk, loops: cint, +proc playChannelTimed*(channel: cint, chunk: PChunk, loops: cint, ticks: cint): cint{.cdecl, importc: "Mix_PlayChannelTimed", dynlib: MixerLibName.} -proc PlayChannel*(channel: cint, chunk: PChunk, loops: cint): cint -proc PlayMusic*(music: PMusic, loops: cint): cint{.cdecl, +proc playChannel*(channel: cint, chunk: PChunk, loops: cint): cint +proc playMusic*(music: PMusic, loops: cint): cint{.cdecl, importc: "Mix_PlayMusic", dynlib: MixerLibName.} -proc FadeInMusic*(music: PMusic, loops: cint, ms: cint): cint{.cdecl, +proc fadeInMusic*(music: PMusic, loops: cint, ms: cint): cint{.cdecl, importc: "Mix_FadeInMusic", dynlib: MixerLibName.} -proc FadeInChannelTimed*(channel: cint, chunk: PChunk, loops: cint, +proc fadeInChannelTimed*(channel: cint, chunk: PChunk, loops: cint, ms: cint, ticks: cint): cint{.cdecl, importc: "Mix_FadeInChannelTimed", dynlib: MixerLibName.} -proc FadeInChannel*(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint +proc fadeInChannel*(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint -proc Volume*(channel: cint, volume: cint): cint{.cdecl, importc: "Mix_Volume", +proc volume*(channel: cint, volume: cint): cint{.cdecl, importc: "Mix_Volume", dynlib: MixerLibName.} -proc VolumeChunk*(chunk: PChunk, volume: cint): cint{.cdecl, +proc volumeChunk*(chunk: PChunk, volume: cint): cint{.cdecl, importc: "Mix_VolumeChunk", dynlib: MixerLibName.} -proc VolumeMusic*(volume: cint): cint{.cdecl, importc: "Mix_VolumeMusic", +proc volumeMusic*(volume: cint): cint{.cdecl, importc: "Mix_VolumeMusic", dynlib: MixerLibName.} -proc HaltChannel*(channel: cint): cint{.cdecl, importc: "Mix_HaltChannel", +proc haltChannel*(channel: cint): cint{.cdecl, importc: "Mix_HaltChannel", dynlib: MixerLibName.} -proc HaltGroup*(tag: cint): cint{.cdecl, importc: "Mix_HaltGroup", +proc haltGroup*(tag: cint): cint{.cdecl, importc: "Mix_HaltGroup", dynlib: MixerLibName.} -proc HaltMusic*(): cint{.cdecl, importc: "Mix_HaltMusic", +proc haltMusic*(): cint{.cdecl, importc: "Mix_HaltMusic", dynlib: MixerLibName.} # Change the expiration delay for a particular channel. # The sample will stop playing after the 'ticks' milliseconds have elapsed, # or remove the expiration if 'ticks' is -1 # -proc ExpireChannel*(channel: cint, ticks: cint): cint{.cdecl, +proc expireChannel*(channel: cint, ticks: cint): cint{.cdecl, importc: "Mix_ExpireChannel", dynlib: MixerLibName.} # Halt a channel, fading it out progressively till it's silent # The ms parameter indicates the number of milliseconds the fading # will take. # -proc FadeOutChannel*(which: cint, ms: cint): cint{.cdecl, +proc fadeOutChannel*(which: cint, ms: cint): cint{.cdecl, importc: "Mix_FadeOutChannel", dynlib: MixerLibName.} -proc FadeOutGroup*(tag: cint, ms: cint): cint{.cdecl, +proc fadeOutGroup*(tag: cint, ms: cint): cint{.cdecl, importc: "Mix_FadeOutGroup", dynlib: MixerLibName.} -proc FadeOutMusic*(ms: cint): cint{.cdecl, importc: "Mix_FadeOutMusic", +proc fadeOutMusic*(ms: cint): cint{.cdecl, importc: "Mix_FadeOutMusic", dynlib: MixerLibName.} # Query the fading status of a channel -proc FadingMusic*(): TFading{.cdecl, importc: "Mix_FadingMusic", +proc fadingMusic*(): TFading{.cdecl, importc: "Mix_FadingMusic", dynlib: MixerLibName.} -proc FadingChannel*(which: cint): TFading{.cdecl, +proc fadingChannel*(which: cint): TFading{.cdecl, importc: "Mix_FadingChannel", dynlib: MixerLibName.} -proc Pause*(channel: cint){.cdecl, importc: "Mix_Pause", dynlib: MixerLibName.} -proc Resume*(channel: cint){.cdecl, importc: "Mix_Resume", +proc pause*(channel: cint){.cdecl, importc: "Mix_Pause", dynlib: MixerLibName.} +proc resume*(channel: cint){.cdecl, importc: "Mix_Resume", dynlib: MixerLibName.} -proc Paused*(channel: cint): cint{.cdecl, importc: "Mix_Paused", +proc paused*(channel: cint): cint{.cdecl, importc: "Mix_Paused", dynlib: MixerLibName.} -proc PauseMusic*(){.cdecl, importc: "Mix_PauseMusic", dynlib: MixerLibName.} -proc ResumeMusic*(){.cdecl, importc: "Mix_ResumeMusic", dynlib: MixerLibName.} -proc RewindMusic*(){.cdecl, importc: "Mix_RewindMusic", dynlib: MixerLibName.} -proc PausedMusic*(): cint{.cdecl, importc: "Mix_PausedMusic", +proc pauseMusic*(){.cdecl, importc: "Mix_PauseMusic", dynlib: MixerLibName.} +proc resumeMusic*(){.cdecl, importc: "Mix_ResumeMusic", dynlib: MixerLibName.} +proc rewindMusic*(){.cdecl, importc: "Mix_RewindMusic", dynlib: MixerLibName.} +proc pausedMusic*(): cint{.cdecl, importc: "Mix_PausedMusic", dynlib: MixerLibName.} -proc SetMusicPosition*(position: float64): cint{.cdecl, +proc setMusicPosition*(position: float64): cint{.cdecl, importc: "Mix_SetMusicPosition", dynlib: MixerLibName.} -proc Playing*(channel: cint): cint{.cdecl, importc: "Mix_Playing", +proc playing*(channel: cint): cint{.cdecl, importc: "Mix_Playing", dynlib: MixerLibName.} -proc PlayingMusic*(): cint{.cdecl, importc: "Mix_PlayingMusic", +proc playingMusic*(): cint{.cdecl, importc: "Mix_PlayingMusic", dynlib: MixerLibName.} -proc SetMusicCMD*(command: cstring): cint{.cdecl, importc: "Mix_SetMusicCMD", +proc setMusicCMD*(command: cstring): cint{.cdecl, importc: "Mix_SetMusicCMD", dynlib: MixerLibName.} -proc SetSynchroValue*(value: cint): cint{.cdecl, +proc setSynchroValue*(value: cint): cint{.cdecl, importc: "Mix_SetSynchroValue", dynlib: MixerLibName.} -proc GetSynchroValue*(): cint{.cdecl, importc: "Mix_GetSynchroValue", +proc getSynchroValue*(): cint{.cdecl, importc: "Mix_GetSynchroValue", dynlib: MixerLibName.} -proc GetChunk*(channel: cint): PChunk{.cdecl, importc: "Mix_GetChunk", +proc getChunk*(channel: cint): PChunk{.cdecl, importc: "Mix_GetChunk", dynlib: MixerLibName.} -proc CloseAudio*(){.cdecl, importc: "Mix_CloseAudio", dynlib: MixerLibName.} +proc closeAudio*(){.cdecl, importc: "Mix_CloseAudio", dynlib: MixerLibName.} -proc VERSION(X: var sdl.Tversion) = - X.major = MAJOR_VERSION - X.minor = MINOR_VERSION - X.patch = PATCHLEVEL +proc version(x: var sdl.Tversion) = + x.major = MAJOR_VERSION + x.minor = MINOR_VERSION + x.patch = PATCHLEVEL -proc LoadWAV(filename: cstring): PChunk = - result = LoadWAV_RW(RWFromFile(filename, "rb"), 1) +proc loadWAV(filename: cstring): PChunk = + result = loadWAV_RW(rWFromFile(filename, "rb"), 1) -proc PlayChannel(channel: cint, chunk: PChunk, loops: cint): cint = - result = PlayChannelTimed(channel, chunk, loops, - 1) +proc playChannel(channel: cint, chunk: PChunk, loops: cint): cint = + result = playChannelTimed(channel, chunk, loops, - 1) -proc FadeInChannel(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint = - result = FadeInChannelTimed(channel, chunk, loops, ms, - 1) +proc fadeInChannel(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint = + result = fadeInChannelTimed(channel, chunk, loops, ms, - 1) diff --git a/lib/wrappers/sdl/sdl_mixer_nosmpeg.nim b/lib/wrappers/sdl/sdl_mixer_nosmpeg.nim index 11f00e0a7..7a8c41af1 100644 --- a/lib/wrappers/sdl/sdl_mixer_nosmpeg.nim +++ b/lib/wrappers/sdl/sdl_mixer_nosmpeg.nim @@ -48,7 +48,7 @@ type #music_cmd.h types PWAVStream* = ptr TWAVStream TWAVStream*{.final.} = object #playmidi.h types - wavefp*: Pointer + wavefp*: pointer start*: int32 stop*: int32 cvt*: TAudioCVT @@ -75,8 +75,8 @@ type #music_cmd.h types volume*: cint #vf: OggVorbis_File; section*: cint cvt*: TAudioCVT - len_available*: cint - snd_available*: pointer + lenAvailable*: cint + sndAvailable*: pointer TErrorEnum* = enum MMERR_OPENING_FILE, MMERR_OUT_OF_MEMORY, MMERR_DYNAMIC_LINKING, @@ -107,7 +107,7 @@ type #music_cmd.h types TChunk*{.final.} = object allocated*: cint abuf*: pointer - alen*: Uint32 + alen*: uint32 volume*: byte # Per-sample volume, 0-128 TFading* = enum @@ -118,18 +118,18 @@ type #music_cmd.h types TMusic*{.final.} = object typ*: TMusicType - TMixFunction* = proc (udata, stream: pointer, length: cint): Pointer{. + TMixFunction* = proc (udata, stream: pointer, length: cint): pointer{. cdecl.} # This macro can be used to fill a version structure with the compile-time # version of the SDL_mixer library. -proc VERSION*(X: var sdl.TVersion) +proc version*(x: var sdl.Tversion) # This function gets the version of the dynamically linked SDL_mixer library. # It should NOT be used to fill a version structure, instead you should use the # SDL_MIXER_VERSION() macro. -proc Linked_Version*(): sdl.Pversion{.cdecl, importc: "Mix_Linked_Version", +proc linkedVersion*(): sdl.Pversion{.cdecl, importc: "Mix_Linked_Version", dynlib: MixerLibName.} # Open the mixer with a certain audio format -proc OpenAudio*(frequency: cint, format: Uint16, channels: cint, +proc openAudio*(frequency: cint, format: uint16, channels: cint, chunksize: cint): cint{.cdecl, importc: "Mix_OpenAudio", dynlib: MixerLibName.} # Dynamically change the number of channels managed by the mixer. @@ -137,170 +137,170 @@ proc OpenAudio*(frequency: cint, format: Uint16, channels: cint, # stopped. # This function returns the new number of allocated channels. # -proc AllocateChannels*(numchannels: cint): cint{.cdecl, +proc allocateChannels*(numchannels: cint): cint{.cdecl, importc: "Mix_AllocateChannels", dynlib: MixerLibName.} # Find out what the actual audio device parameters are. # This function returns 1 if the audio has been opened, 0 otherwise. # -proc QuerySpec*(frequency: var cint, format: var Uint16, channels: var cint): cint{. +proc querySpec*(frequency: var cint, format: var uint16, channels: var cint): cint{. cdecl, importc: "Mix_QuerySpec", dynlib: MixerLibName.} # Load a wave file or a music (.mod .s3m .it .xm) file proc LoadWAV_RW*(src: PRWops, freesrc: cint): PChunk{.cdecl, importc: "Mix_LoadWAV_RW", dynlib: MixerLibName.} -proc LoadWAV*(filename: cstring): PChunk -proc LoadMUS*(filename: cstring): PMusic{.cdecl, importc: "Mix_LoadMUS", +proc loadWAV*(filename: cstring): PChunk +proc loadMUS*(filename: cstring): PMusic{.cdecl, importc: "Mix_LoadMUS", dynlib: MixerLibName.} # Load a wave file of the mixer format from a memory buffer -proc QuickLoad_WAV*(mem: pointer): PChunk{.cdecl, +proc quickLoadWAV*(mem: pointer): PChunk{.cdecl, importc: "Mix_QuickLoad_WAV", dynlib: MixerLibName.} # Free an audio chunk previously loaded -proc FreeChunk*(chunk: PChunk){.cdecl, importc: "Mix_FreeChunk", +proc freeChunk*(chunk: PChunk){.cdecl, importc: "Mix_FreeChunk", dynlib: MixerLibName.} -proc FreeMusic*(music: PMusic){.cdecl, importc: "Mix_FreeMusic", +proc freeMusic*(music: PMusic){.cdecl, importc: "Mix_FreeMusic", dynlib: MixerLibName.} # Find out the music format of a mixer music, or the currently playing # music, if 'music' is NULL. -proc GetMusicType*(music: PMusic): TMusicType{.cdecl, +proc getMusicType*(music: PMusic): TMusicType{.cdecl, importc: "Mix_GetMusicType", dynlib: MixerLibName.} # Set a function that is called after all mixing is performed. # This can be used to provide real-time visual display of the audio stream # or add a custom mixer filter for the stream data. # -proc SetPostMix*(mixfunc: TMixFunction, arg: Pointer){.cdecl, +proc setPostMix*(mixfunc: TMixFunction, arg: pointer){.cdecl, importc: "Mix_SetPostMix", dynlib: MixerLibName.} # Add your own music player or additional mixer function. # If 'mix_func' is NULL, the default music player is re-enabled. # -proc HookMusic*(mix_func: TMixFunction, arg: Pointer){.cdecl, +proc hookMusic*(mixFunc: TMixFunction, arg: pointer){.cdecl, importc: "Mix_HookMusic", dynlib: MixerLibName.} # Add your own callback when the music has finished playing. # -proc HookMusicFinished*(music_finished: Pointer){.cdecl, +proc hookMusicFinished*(musicFinished: pointer){.cdecl, importc: "Mix_HookMusicFinished", dynlib: MixerLibName.} # Get a pointer to the user data for the current music hook -proc GetMusicHookData*(): Pointer{.cdecl, importc: "Mix_GetMusicHookData", +proc getMusicHookData*(): pointer{.cdecl, importc: "Mix_GetMusicHookData", dynlib: MixerLibName.} #* Add your own callback when a channel has finished playing. NULL # * to disable callback.* type - TChannel_finished* = proc (channel: cint){.cdecl.} + TChannelFinished* = proc (channel: cint){.cdecl.} -proc ChannelFinished*(channel_finished: TChannel_finished){.cdecl, +proc channelFinished*(channelFinished: TChannelFinished){.cdecl, importc: "Mix_ChannelFinished", dynlib: MixerLibName.} const CHANNEL_POST* = - 2 type - TEffectFunc* = proc (chan: cint, stream: Pointer, length: cint, - udata: Pointer): Pointer{.cdecl.} - TEffectDone* = proc (chan: cint, udata: Pointer): Pointer{.cdecl.} + TEffectFunc* = proc (chan: cint, stream: pointer, length: cint, + udata: pointer): pointer{.cdecl.} + TEffectDone* = proc (chan: cint, udata: pointer): pointer{.cdecl.} -proc RegisterEffect*(chan: cint, f: TEffectFunc, d: TEffectDone, - arg: Pointer): cint{.cdecl, +proc registerEffect*(chan: cint, f: TEffectFunc, d: TEffectDone, + arg: pointer): cint{.cdecl, importc: "Mix_RegisterEffect", dynlib: MixerLibName.} -proc UnregisterEffect*(channel: cint, f: TEffectFunc): cint{.cdecl, +proc unregisterEffect*(channel: cint, f: TEffectFunc): cint{.cdecl, importc: "Mix_UnregisterEffect", dynlib: MixerLibName.} -proc UnregisterAllEffects*(channel: cint): cint{.cdecl, +proc unregisterAllEffects*(channel: cint): cint{.cdecl, importc: "Mix_UnregisterAllEffects", dynlib: MixerLibName.} const EFFECTSMAXSPEED* = "MIX_EFFECTSMAXSPEED" -proc SetPanning*(channel: cint, left: byte, right: byte): cint{.cdecl, +proc setPanning*(channel: cint, left: byte, right: byte): cint{.cdecl, importc: "Mix_SetPanning", dynlib: MixerLibName.} -proc SetPosition*(channel: cint, angle: int16, distance: byte): cint{.cdecl, +proc setPosition*(channel: cint, angle: int16, distance: byte): cint{.cdecl, importc: "Mix_SetPosition", dynlib: MixerLibName.} -proc SetDistance*(channel: cint, distance: byte): cint{.cdecl, +proc setDistance*(channel: cint, distance: byte): cint{.cdecl, importc: "Mix_SetDistance", dynlib: MixerLibName.} -proc SetReverseStereo*(channel: cint, flip: cint): cint{.cdecl, +proc setReverseStereo*(channel: cint, flip: cint): cint{.cdecl, importc: "Mix_SetReverseStereo", dynlib: MixerLibName.} -proc ReserveChannels*(num: cint): cint{.cdecl, importc: "Mix_ReserveChannels", +proc reserveChannels*(num: cint): cint{.cdecl, importc: "Mix_ReserveChannels", dynlib: MixerLibName.} -proc GroupChannel*(which: cint, tag: cint): cint{.cdecl, +proc groupChannel*(which: cint, tag: cint): cint{.cdecl, importc: "Mix_GroupChannel", dynlib: MixerLibName.} # Assign several consecutive channels to a group -proc GroupChannels*(`from`: cint, `to`: cint, tag: cint): cint{.cdecl, +proc groupChannels*(`from`: cint, `to`: cint, tag: cint): cint{.cdecl, importc: "Mix_GroupChannels", dynlib: MixerLibName.} # Finds the first available channel in a group of channels -proc GroupAvailable*(tag: cint): cint{.cdecl, importc: "Mix_GroupAvailable", +proc groupAvailable*(tag: cint): cint{.cdecl, importc: "Mix_GroupAvailable", dynlib: MixerLibName.} # Returns the number of channels in a group. This is also a subtle # way to get the total number of channels when 'tag' is -1 # -proc GroupCount*(tag: cint): cint{.cdecl, importc: "Mix_GroupCount", +proc groupCount*(tag: cint): cint{.cdecl, importc: "Mix_GroupCount", dynlib: MixerLibName.} # Finds the "oldest" sample playing in a group of channels -proc GroupOldest*(tag: cint): cint{.cdecl, importc: "Mix_GroupOldest", +proc groupOldest*(tag: cint): cint{.cdecl, importc: "Mix_GroupOldest", dynlib: MixerLibName.} # Finds the "most recent" (i.e. last) sample playing in a group of channels -proc GroupNewer*(tag: cint): cint{.cdecl, importc: "Mix_GroupNewer", +proc groupNewer*(tag: cint): cint{.cdecl, importc: "Mix_GroupNewer", dynlib: MixerLibName.} # The same as above, but the sound is played at most 'ticks' milliseconds -proc PlayChannelTimed*(channel: cint, chunk: PChunk, loops: cint, +proc playChannelTimed*(channel: cint, chunk: PChunk, loops: cint, ticks: cint): cint{.cdecl, importc: "Mix_PlayChannelTimed", dynlib: MixerLibName.} -proc PlayChannel*(channel: cint, chunk: PChunk, loops: cint): cint -proc PlayMusic*(music: PMusic, loops: cint): cint{.cdecl, +proc playChannel*(channel: cint, chunk: PChunk, loops: cint): cint +proc playMusic*(music: PMusic, loops: cint): cint{.cdecl, importc: "Mix_PlayMusic", dynlib: MixerLibName.} # Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions -proc FadeInMusic*(music: PMusic, loops: cint, ms: cint): cint{.cdecl, +proc fadeInMusic*(music: PMusic, loops: cint, ms: cint): cint{.cdecl, importc: "Mix_FadeInMusic", dynlib: MixerLibName.} -proc FadeInChannelTimed*(channel: cint, chunk: PChunk, loops: cint, +proc fadeInChannelTimed*(channel: cint, chunk: PChunk, loops: cint, ms: cint, ticks: cint): cint{.cdecl, importc: "Mix_FadeInChannelTimed", dynlib: MixerLibName.} -proc FadeInChannel*(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint +proc fadeInChannel*(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint # Set the volume in the range of 0-128 of a specific channel or chunk. # If the specified channel is -1, set volume for all channels. # Returns the original volume. # If the specified volume is -1, just return the current volume. # -proc Volume*(channel: cint, volume: cint): cint{.cdecl, importc: "Mix_Volume", +proc volume*(channel: cint, volume: cint): cint{.cdecl, importc: "Mix_Volume", dynlib: MixerLibName.} -proc VolumeChunk*(chunk: PChunk, volume: cint): cint{.cdecl, +proc volumeChunk*(chunk: PChunk, volume: cint): cint{.cdecl, importc: "Mix_VolumeChunk", dynlib: MixerLibName.} -proc VolumeMusic*(volume: cint): cint{.cdecl, importc: "Mix_VolumeMusic", +proc volumeMusic*(volume: cint): cint{.cdecl, importc: "Mix_VolumeMusic", dynlib: MixerLibName.} # Halt playing of a particular channel -proc HaltChannel*(channel: cint): cint{.cdecl, importc: "Mix_HaltChannel", +proc haltChannel*(channel: cint): cint{.cdecl, importc: "Mix_HaltChannel", dynlib: MixerLibName.} -proc HaltGroup*(tag: cint): cint{.cdecl, importc: "Mix_HaltGroup", +proc haltGroup*(tag: cint): cint{.cdecl, importc: "Mix_HaltGroup", dynlib: MixerLibName.} -proc HaltMusic*(): cint{.cdecl, importc: "Mix_HaltMusic", +proc haltMusic*(): cint{.cdecl, importc: "Mix_HaltMusic", dynlib: MixerLibName.} -proc ExpireChannel*(channel: cint, ticks: cint): cint{.cdecl, +proc expireChannel*(channel: cint, ticks: cint): cint{.cdecl, importc: "Mix_ExpireChannel", dynlib: MixerLibName.} -proc FadeOutChannel*(which: cint, ms: cint): cint{.cdecl, +proc fadeOutChannel*(which: cint, ms: cint): cint{.cdecl, importc: "Mix_FadeOutChannel", dynlib: MixerLibName.} -proc FadeOutGroup*(tag: cint, ms: cint): cint{.cdecl, +proc fadeOutGroup*(tag: cint, ms: cint): cint{.cdecl, importc: "Mix_FadeOutGroup", dynlib: MixerLibName.} -proc FadeOutMusic*(ms: cint): cint{.cdecl, importc: "Mix_FadeOutMusic", +proc fadeOutMusic*(ms: cint): cint{.cdecl, importc: "Mix_FadeOutMusic", dynlib: MixerLibName.} # Query the fading status of a channel -proc FadingMusic*(): TFading{.cdecl, importc: "Mix_FadingMusic", +proc fadingMusic*(): TFading{.cdecl, importc: "Mix_FadingMusic", dynlib: MixerLibName.} -proc FadingChannel*(which: cint): TFading{.cdecl, +proc fadingChannel*(which: cint): TFading{.cdecl, importc: "Mix_FadingChannel", dynlib: MixerLibName.} # Pause/Resume a particular channel -proc Pause*(channel: cint){.cdecl, importc: "Mix_Pause", dynlib: MixerLibName.} -proc Resume*(channel: cint){.cdecl, importc: "Mix_Resume", +proc pause*(channel: cint){.cdecl, importc: "Mix_Pause", dynlib: MixerLibName.} +proc resume*(channel: cint){.cdecl, importc: "Mix_Resume", dynlib: MixerLibName.} -proc Paused*(channel: cint): cint{.cdecl, importc: "Mix_Paused", +proc paused*(channel: cint): cint{.cdecl, importc: "Mix_Paused", dynlib: MixerLibName.} # Pause/Resume the music stream -proc PauseMusic*(){.cdecl, importc: "Mix_PauseMusic", dynlib: MixerLibName.} -proc ResumeMusic*(){.cdecl, importc: "Mix_ResumeMusic", dynlib: MixerLibName.} -proc RewindMusic*(){.cdecl, importc: "Mix_RewindMusic", dynlib: MixerLibName.} -proc PausedMusic*(): cint{.cdecl, importc: "Mix_PausedMusic", +proc pauseMusic*(){.cdecl, importc: "Mix_PauseMusic", dynlib: MixerLibName.} +proc resumeMusic*(){.cdecl, importc: "Mix_ResumeMusic", dynlib: MixerLibName.} +proc rewindMusic*(){.cdecl, importc: "Mix_RewindMusic", dynlib: MixerLibName.} +proc pausedMusic*(): cint{.cdecl, importc: "Mix_PausedMusic", dynlib: MixerLibName.} # Set the current position in the music stream. # This returns 0 if successful, or -1 if it failed or isn't implemented. @@ -308,44 +308,44 @@ proc PausedMusic*(): cint{.cdecl, importc: "Mix_PausedMusic", # order number) and for OGG music (set position in seconds), at the # moment. # -proc SetMusicPosition*(position: float64): cint{.cdecl, +proc setMusicPosition*(position: float64): cint{.cdecl, importc: "Mix_SetMusicPosition", dynlib: MixerLibName.} # Check the status of a specific channel. # If the specified channel is -1, check all channels. # -proc Playing*(channel: cint): cint{.cdecl, importc: "Mix_Playing", +proc playing*(channel: cint): cint{.cdecl, importc: "Mix_Playing", dynlib: MixerLibName.} -proc PlayingMusic*(): cint{.cdecl, importc: "Mix_PlayingMusic", +proc playingMusic*(): cint{.cdecl, importc: "Mix_PlayingMusic", dynlib: MixerLibName.} # Stop music and set external music playback command -proc SetMusicCMD*(command: cstring): cint{.cdecl, importc: "Mix_SetMusicCMD", +proc setMusicCMD*(command: cstring): cint{.cdecl, importc: "Mix_SetMusicCMD", dynlib: MixerLibName.} # Synchro value is set by MikMod from modules while playing -proc SetSynchroValue*(value: cint): cint{.cdecl, +proc setSynchroValue*(value: cint): cint{.cdecl, importc: "Mix_SetSynchroValue", dynlib: MixerLibName.} -proc GetSynchroValue*(): cint{.cdecl, importc: "Mix_GetSynchroValue", +proc getSynchroValue*(): cint{.cdecl, importc: "Mix_GetSynchroValue", dynlib: MixerLibName.} # # Get the Mix_Chunk currently associated with a mixer channel # Returns nil if it's an invalid channel, or there's no chunk associated. # -proc GetChunk*(channel: cint): PChunk{.cdecl, importc: "Mix_GetChunk", +proc getChunk*(channel: cint): PChunk{.cdecl, importc: "Mix_GetChunk", dynlib: MixerLibName.} # Close the mixer, halting all playing audio -proc CloseAudio*(){.cdecl, importc: "Mix_CloseAudio", dynlib: MixerLibName.} +proc closeAudio*(){.cdecl, importc: "Mix_CloseAudio", dynlib: MixerLibName.} # We'll use SDL for reporting errors -proc VERSION(X: var Tversion) = - X.major = MAJOR_VERSION - X.minor = MINOR_VERSION - X.patch = PATCHLEVEL +proc version(x: var Tversion) = + x.major = MAJOR_VERSION + x.minor = MINOR_VERSION + x.patch = PATCHLEVEL -proc LoadWAV(filename: cstring): PChunk = - result = LoadWAV_RW(RWFromFile(filename, "rb"), 1) +proc loadWAV(filename: cstring): PChunk = + result = LoadWAV_RW(rWFromFile(filename, "rb"), 1) -proc PlayChannel(channel: cint, chunk: PChunk, loops: cint): cint = - result = PlayChannelTimed(channel, chunk, loops, - 1) +proc playChannel(channel: cint, chunk: PChunk, loops: cint): cint = + result = playChannelTimed(channel, chunk, loops, - 1) -proc FadeInChannel(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint = - result = FadeInChannelTimed(channel, chunk, loops, ms, - 1) +proc fadeInChannel(channel: cint, chunk: PChunk, loops: cint, ms: cint): cint = + result = fadeInChannelTimed(channel, chunk, loops, ms, - 1) diff --git a/lib/wrappers/sdl/sdl_net.nim b/lib/wrappers/sdl/sdl_net.nim index 742a59314..1ffdb5cca 100644 --- a/lib/wrappers/sdl/sdl_net.nim +++ b/lib/wrappers/sdl/sdl_net.nim @@ -145,15 +145,15 @@ type # SDL_net.h types #*********************************************************************** PIPAddress* = ptr TIPAddress TIPAddress*{.final.} = object #* TCP network API - host*: Uint32 # 32-bit IPv4 host address */ - port*: Uint16 # 16-bit protocol port */ + host*: uint32 # 32-bit IPv4 host address */ + port*: uint16 # 16-bit protocol port */ PTCPSocket* = ptr TTCPSocket TTCPSocket*{.final.} = object # UDP network API ready*: int channel*: int - remoteAddress*: TIPaddress - localAddress*: TIPaddress + remoteAddress*: TIPAddress + localAddress*: TIPAddress sflag*: int PUDP_Channel* = ptr TUDP_Channel @@ -196,27 +196,27 @@ type # SDL_net.h types ready*: int -proc VERSION*(X: var Tversion) +proc version*(x: var Tversion) #* Initialize/Cleanup the network API # SDL must be initialized before calls to functions in this library, # because this library uses utility functions from the SDL library. #* -proc Init*(): int{.cdecl, importc: "SDLNet_Init", dynlib: NetLibName.} -proc Quit*(){.cdecl, importc: "SDLNet_Quit", dynlib: NetLibName.} +proc init*(): int{.cdecl, importc: "SDLNet_Init", dynlib: NetLibName.} +proc quit*(){.cdecl, importc: "SDLNet_Quit", dynlib: NetLibName.} #* Resolve a host name and port to an IP address in network form. # If the function succeeds, it will return 0. # If the host couldn't be resolved, the host portion of the returned # address will be INADDR_NONE, and the function will return -1. # If 'host' is NULL, the resolved host will be set to INADDR_ANY. # * -proc ResolveHost*(address: var TIPaddress, host: cstring, port: Uint16): int{. +proc resolveHost*(address: var TIPAddress, host: cstring, port: uint16): int{. cdecl, importc: "SDLNet_ResolveHost", dynlib: NetLibName.} #* Resolve an ip address to a host name in canonical form. # If the ip couldn't be resolved, this function returns NULL, # otherwise a pointer to a static buffer containing the hostname # is returned. Note that this function is not thread-safe. #* -proc ResolveIP*(ip: var TIPaddress): cstring{.cdecl, +proc resolveIP*(ip: var TIPAddress): cstring{.cdecl, importc: "SDLNet_ResolveIP", dynlib: NetLibName.} #*********************************************************************** #* TCP network API * @@ -229,24 +229,24 @@ proc ResolveIP*(ip: var TIPaddress): cstring{.cdecl, # in the correct form). # The newly created socket is returned, or NULL if there was an error. #* -proc TCP_Open*(ip: var TIPaddress): PTCPSocket{.cdecl, +proc tcpOpen*(ip: var TIPAddress): PTCPSocket{.cdecl, importc: "SDLNet_TCP_Open", dynlib: NetLibName.} #* Accept an incoming connection on the given server socket. # The newly created socket is returned, or NULL if there was an error. #* -proc TCP_Accept*(server: PTCPsocket): PTCPSocket{.cdecl, +proc tcpAccept*(server: PTCPSocket): PTCPSocket{.cdecl, importc: "SDLNet_TCP_Accept", dynlib: NetLibName.} #* Get the IP address of the remote system associated with the socket. # If the socket is a server socket, this function returns NULL. #* -proc TCP_GetPeerAddress*(sock: PTCPsocket): PIPAddress{.cdecl, +proc tcpGetPeerAddress*(sock: PTCPSocket): PIPAddress{.cdecl, importc: "SDLNet_TCP_GetPeerAddress", dynlib: NetLibName.} #* Send 'len' bytes of 'data' over the non-server socket 'sock' # This function returns the actual amount of data sent. If the return value # is less than the amount of data sent, then either the remote connection was # closed, or an unknown socket error occurred. #* -proc TCP_Send*(sock: PTCPsocket, data: Pointer, length: int): int{.cdecl, +proc tcpSend*(sock: PTCPSocket, data: pointer, length: int): int{.cdecl, importc: "SDLNet_TCP_Send", dynlib: NetLibName.} #* Receive up to 'maxlen' bytes of data over the non-server socket 'sock', # and store them in the buffer pointed to by 'data'. @@ -254,10 +254,10 @@ proc TCP_Send*(sock: PTCPsocket, data: Pointer, length: int): int{.cdecl, # value is less than or equal to zero, then either the remote connection was # closed, or an unknown socket error occurred. #* -proc TCP_Recv*(sock: PTCPsocket, data: Pointer, maxlen: int): int{.cdecl, +proc tcpRecv*(sock: PTCPSocket, data: pointer, maxlen: int): int{.cdecl, importc: "SDLNet_TCP_Recv", dynlib: NetLibName.} #* Close a TCP network socket * -proc TCP_Close*(sock: PTCPsocket){.cdecl, importc: "SDLNet_TCP_Close", +proc tcpClose*(sock: PTCPSocket){.cdecl, importc: "SDLNet_TCP_Close", dynlib: NetLibName.} #*********************************************************************** #* UDP network API * @@ -265,26 +265,26 @@ proc TCP_Close*(sock: PTCPsocket){.cdecl, importc: "SDLNet_TCP_Close", #* Allocate/resize/free a single UDP packet 'size' bytes long. # The new packet is returned, or NULL if the function ran out of memory. # * -proc AllocPacket*(size: int): PUDPpacket{.cdecl, +proc allocPacket*(size: int): PUDPpacket{.cdecl, importc: "SDLNet_AllocPacket", dynlib: NetLibName.} -proc ResizePacket*(packet: PUDPpacket, newsize: int): int{.cdecl, +proc resizePacket*(packet: PUDPpacket, newsize: int): int{.cdecl, importc: "SDLNet_ResizePacket", dynlib: NetLibName.} -proc FreePacket*(packet: PUDPpacket){.cdecl, importc: "SDLNet_FreePacket", +proc freePacket*(packet: PUDPpacket){.cdecl, importc: "SDLNet_FreePacket", dynlib: NetLibName.} #* Allocate/Free a UDP packet vector (array of packets) of 'howmany' packets, # each 'size' bytes long. # A pointer to the first packet in the array is returned, or NULL if the # function ran out of memory. # * -proc AllocPacketV*(howmany: int, size: int): PUDPpacket{.cdecl, +proc allocPacketV*(howmany: int, size: int): PUDPpacket{.cdecl, importc: "SDLNet_AllocPacketV", dynlib: NetLibName.} -proc FreePacketV*(packetV: PUDPpacket){.cdecl, +proc freePacketV*(packetV: PUDPpacket){.cdecl, importc: "SDLNet_FreePacketV", dynlib: NetLibName.} #* Open a UDP network socket # If 'port' is non-zero, the UDP socket is bound to a local port. # This allows other systems to send to this socket via a known port. #* -proc UDP_Open*(port: Uint16): PUDPsocket{.cdecl, importc: "SDLNet_UDP_Open", +proc udpOpen*(port: uint16): PUDPSocket{.cdecl, importc: "SDLNet_UDP_Open", dynlib: NetLibName.} #* Bind the address 'address' to the requested channel on the UDP socket. # If the channel is -1, then the first unbound channel will be bound with @@ -295,10 +295,10 @@ proc UDP_Open*(port: Uint16): PUDPsocket{.cdecl, importc: "SDLNet_UDP_Open", # address, to which all outbound packets on the channel are sent. # This function returns the channel which was bound, or -1 on error. #* -proc UDP_Bind*(sock: PUDPsocket, channel: int, address: var TIPaddress): int{. +proc udpBind*(sock: PUDPSocket, channel: int, address: var TIPAddress): int{. cdecl, importc: "SDLNet_UDP_Bind", dynlib: NetLibName.} #* Unbind all addresses from the given channel * -proc UDP_Unbind*(sock: PUDPsocket, channel: int){.cdecl, +proc udpUnbind*(sock: PUDPSocket, channel: int){.cdecl, importc: "SDLNet_UDP_Unbind", dynlib: NetLibName.} #* Get the primary IP address of the remote system associated with the # socket and channel. If the channel is -1, then the primary IP port @@ -306,7 +306,7 @@ proc UDP_Unbind*(sock: PUDPsocket, channel: int){.cdecl, # opened with a specific port. # If the channel is not bound and not -1, this function returns NULL. # * -proc UDP_GetPeerAddress*(sock: PUDPsocket, channel: int): PIPAddress{.cdecl, +proc udpGetPeerAddress*(sock: PUDPSocket, channel: int): PIPAddress{.cdecl, importc: "SDLNet_UDP_GetPeerAddress", dynlib: NetLibName.} #* Send a vector of packets to the the channels specified within the packet. # If the channel specified in the packet is -1, the packet will be sent to @@ -315,7 +315,7 @@ proc UDP_GetPeerAddress*(sock: PUDPsocket, channel: int): PIPAddress{.cdecl, # been sent, -1 if the packet send failed. # This function returns the number of packets sent. #* -proc UDP_SendV*(sock: PUDPsocket, packets: PPUDPpacket, npackets: int): int{. +proc udpSendV*(sock: PUDPSocket, packets: PPUDPpacket, npackets: int): int{. cdecl, importc: "SDLNet_UDP_SendV", dynlib: NetLibName.} #* Send a single packet to the specified channel. # If the channel specified in the packet is -1, the packet will be sent to @@ -324,7 +324,7 @@ proc UDP_SendV*(sock: PUDPsocket, packets: PPUDPpacket, npackets: int): int{. # been sent. # This function returns 1 if the packet was sent, or 0 on error. #* -proc UDP_Send*(sock: PUDPsocket, channel: int, packet: PUDPpacket): int{. +proc udpSend*(sock: PUDPSocket, channel: int, packet: PUDPpacket): int{. cdecl, importc: "SDLNet_UDP_Send", dynlib: NetLibName.} #* Receive a vector of pending packets from the UDP socket. # The returned packets contain the source address and the channel they arrived @@ -336,7 +336,7 @@ proc UDP_Send*(sock: PUDPsocket, channel: int, packet: PUDPpacket): int{. # This function returns the number of packets read from the network, or -1 # on error. This function does not block, so can return 0 packets pending. #* -proc UDP_RecvV*(sock: PUDPsocket, packets: PPUDPpacket): int{.cdecl, +proc udpRecvV*(sock: PUDPSocket, packets: PPUDPpacket): int{.cdecl, importc: "SDLNet_UDP_RecvV", dynlib: NetLibName.} #* Receive a single packet from the UDP socket. # The returned packet contains the source address and the channel it arrived @@ -348,10 +348,10 @@ proc UDP_RecvV*(sock: PUDPsocket, packets: PPUDPpacket): int{.cdecl, # This function returns the number of packets read from the network, or -1 # on error. This function does not block, so can return 0 packets pending. #* -proc UDP_Recv*(sock: PUDPsocket, packet: PUDPpacket): int{.cdecl, +proc udpRecv*(sock: PUDPSocket, packet: PUDPpacket): int{.cdecl, importc: "SDLNet_UDP_Recv", dynlib: NetLibName.} #* Close a UDP network socket * -proc UDP_Close*(sock: PUDPsocket){.cdecl, importc: "SDLNet_UDP_Close", +proc udpClose*(sock: PUDPSocket){.cdecl, importc: "SDLNet_UDP_Close", dynlib: NetLibName.} #*********************************************************************** #* Hooks for checking sockets for available data * @@ -360,19 +360,19 @@ proc UDP_Close*(sock: PUDPsocket){.cdecl, importc: "SDLNet_UDP_Close", # This returns a socket set for up to 'maxsockets' sockets, or NULL if # the function ran out of memory. # * -proc AllocSocketSet*(maxsockets: int): PSocketSet{.cdecl, +proc allocSocketSet*(maxsockets: int): PSocketSet{.cdecl, importc: "SDLNet_AllocSocketSet", dynlib: NetLibName.} #* Add a socket to a set of sockets to be checked for available data * -proc AddSocket*(theSet: PSocketSet, sock: PGenericSocket): int{. +proc addSocket*(theSet: PSocketSet, sock: PGenericSocket): int{. cdecl, importc: "SDLNet_AddSocket", dynlib: NetLibName.} -proc TCP_AddSocket*(theSet: PSocketSet, sock: PTCPSocket): int -proc UDP_AddSocket*(theSet: PSocketSet, sock: PUDPSocket): int +proc tcpAddSocket*(theSet: PSocketSet, sock: PTCPSocket): int +proc udpAddSocket*(theSet: PSocketSet, sock: PUDPSocket): int #* Remove a socket from a set of sockets to be checked for available data * -proc DelSocket*(theSet: PSocketSet, sock: PGenericSocket): int{. +proc delSocket*(theSet: PSocketSet, sock: PGenericSocket): int{. cdecl, importc: "SDLNet_DelSocket", dynlib: NetLibName.} -proc TCP_DelSocket*(theSet: PSocketSet, sock: PTCPSocket): int +proc tcpDelSocket*(theSet: PSocketSet, sock: PTCPSocket): int # SDLNet_DelSocket(set, (SDLNet_GenericSocket)sock) -proc UDP_DelSocket*(theSet: PSocketSet, sock: PUDPSocket): int +proc udpDelSocket*(theSet: PSocketSet, sock: PUDPSocket): int #SDLNet_DelSocket(set, (SDLNet_GenericSocket)sock) #* This function checks to see if data is available for reading on the # given set of sockets. If 'timeout' is 0, it performs a quick poll, @@ -381,47 +381,46 @@ proc UDP_DelSocket*(theSet: PSocketSet, sock: PUDPSocket): int # first. This function returns the number of sockets ready for reading, # or -1 if there was an error with the select() system call. #* -proc CheckSockets*(theSet: PSocketSet, timeout: int32): int{.cdecl, +proc checkSockets*(theSet: PSocketSet, timeout: int32): int{.cdecl, importc: "SDLNet_CheckSockets", dynlib: NetLibName.} #* After calling SDLNet_CheckSockets(), you can use this function on a # socket that was in the socket set, to find out if data is available # for reading. #* -proc SocketReady*(sock: PGenericSocket): bool +proc socketReady*(sock: PGenericSocket): bool #* Free a set of sockets allocated by SDL_NetAllocSocketSet() * -proc FreeSocketSet*(theSet: PSocketSet){.cdecl, +proc freeSocketSet*(theSet: PSocketSet){.cdecl, importc: "SDLNet_FreeSocketSet", dynlib: NetLibName.} #*********************************************************************** #* Platform-independent data conversion functions * #*********************************************************************** #* Write a 16/32 bit value to network packet buffer * -proc Write16*(value: Uint16, area: Pointer){.cdecl, +proc write16*(value: uint16, area: pointer){.cdecl, importc: "SDLNet_Write16", dynlib: NetLibName.} -proc Write32*(value: Uint32, area: Pointer){.cdecl, +proc write32*(value: uint32, area: pointer){.cdecl, importc: "SDLNet_Write32", dynlib: NetLibName.} #* Read a 16/32 bit value from network packet buffer * -proc Read16*(area: Pointer): Uint16{.cdecl, importc: "SDLNet_Read16", +proc read16*(area: pointer): uint16{.cdecl, importc: "SDLNet_Read16", dynlib: NetLibName.} -proc Read32*(area: Pointer): Uint32{.cdecl, importc: "SDLNet_Read32", +proc read32*(area: pointer): uint32{.cdecl, importc: "SDLNet_Read32", dynlib: NetLibName.} -proc VERSION(X: var Tversion) = - X.major = MAJOR_VERSION - X.minor = MINOR_VERSION - X.patch = PATCHLEVEL +proc version(x: var Tversion) = + x.major = MAJOR_VERSION + x.minor = MINOR_VERSION + x.patch = PATCHLEVEL -proc TCP_AddSocket(theSet: PSocketSet, sock: PTCPSocket): int = - result = AddSocket(theSet, cast[PGenericSocket](sock)) +proc tcpAddSocket(theSet: PSocketSet, sock: PTCPSocket): int = + result = addSocket(theSet, cast[PGenericSocket](sock)) -proc UDP_AddSocket(theSet: PSocketSet, sock: PUDPSocket): int = - result = AddSocket(theSet, cast[PGenericSocket](sock)) +proc udpAddSocket(theSet: PSocketSet, sock: PUDPSocket): int = + result = addSocket(theSet, cast[PGenericSocket](sock)) -proc TCP_DelSocket(theSet: PSocketSet, sock: PTCPSocket): int = - result = DelSocket(theSet, cast[PGenericSocket](sock)) +proc tcpDelSocket(theSet: PSocketSet, sock: PTCPSocket): int = + result = delSocket(theSet, cast[PGenericSocket](sock)) -proc UDP_DelSocket(theSet: PSocketSet, sock: PUDPSocket): int = - result = DelSocket(theSet, cast[PGenericSocket](sock)) - -proc SocketReady(sock: PGenericSocket): bool = - result = ((sock != nil) and (sock.ready == 1)) +proc udpDelSocket(theSet: PSocketSet, sock: PUDPSocket): int = + result = delSocket(theSet, cast[PGenericSocket](sock)) +proc socketReady(sock: PGenericSocket): bool = + result = sock != nil and sock.ready == 1 diff --git a/lib/wrappers/sdl/sdl_ttf.nim b/lib/wrappers/sdl/sdl_ttf.nim index 45247df4d..e0410c798 100644 --- a/lib/wrappers/sdl/sdl_ttf.nim +++ b/lib/wrappers/sdl/sdl_ttf.nim @@ -177,78 +177,78 @@ const UNICODE_BOM_SWAPPED* = 0x0000FFFE type - PFont* = ptr Tfont - TFont{.final.} = object + PFont* = ptr TFont + TFont = object # This macro can be used to fill a version structure with the compile-time # version of the SDL_ttf library. -proc Linked_Version*(): sdl.Pversion{.cdecl, importc: "TTF_Linked_Version", +proc linkedVersion*(): sdl.Pversion{.cdecl, importc: "TTF_Linked_Version", dynlib: ttfLibName.} # This function tells the library whether UNICODE text is generally # byteswapped. A UNICODE BOM character in a string will override # this setting for the remainder of that string. # -proc ByteSwappedUNICODE*(swapped: cint){.cdecl, +proc byteSwappedUNICODE*(swapped: cint){.cdecl, importc: "TTF_ByteSwappedUNICODE", dynlib: ttfLibName.} #returns 0 on succes, -1 if error occurs -proc Init*(): cint{.cdecl, importc: "TTF_Init", dynlib: ttfLibName.} +proc init*(): cint{.cdecl, importc: "TTF_Init", dynlib: ttfLibName.} # # Open a font file and create a font of the specified point size. # Some .fon fonts will have several sizes embedded in the file, so the # point size becomes the index of choosing which size. If the value # is too high, the last indexed size will be the default. # -proc OpenFont*(filename: cstring, ptsize: cint): PFont{.cdecl, +proc openFont*(filename: cstring, ptsize: cint): PFont{.cdecl, importc: "TTF_OpenFont", dynlib: ttfLibName.} -proc OpenFontIndex*(filename: cstring, ptsize: cint, index: int32): PFont{. +proc openFontIndex*(filename: cstring, ptsize: cint, index: int32): PFont{. cdecl, importc: "TTF_OpenFontIndex", dynlib: ttfLibName.} -proc OpenFontRW*(src: PRWops, freesrc: cint, ptsize: cint): PFont{.cdecl, +proc openFontRW*(src: PRWops, freesrc: cint, ptsize: cint): PFont{.cdecl, importc: "TTF_OpenFontRW", dynlib: ttfLibName.} -proc OpenFontIndexRW*(src: PRWops, freesrc: cint, ptsize: cint, index: int32): PFont{. +proc openFontIndexRW*(src: PRWops, freesrc: cint, ptsize: cint, index: int32): PFont{. cdecl, importc: "TTF_OpenFontIndexRW", dynlib: ttfLibName.} -proc GetFontStyle*(font: PFont): cint{.cdecl, +proc getFontStyle*(font: PFont): cint{.cdecl, importc: "TTF_GetFontStyle", dynlib: ttfLibName.} -proc SetFontStyle*(font: PFont, style: cint){.cdecl, +proc setFontStyle*(font: PFont, style: cint){.cdecl, importc: "TTF_SetFontStyle", dynlib: ttfLibName.} # Get the total height of the font - usually equal to point size -proc FontHeight*(font: PFont): cint{.cdecl, importc: "TTF_FontHeight", +proc fontHeight*(font: PFont): cint{.cdecl, importc: "TTF_FontHeight", dynlib: ttfLibName.} # Get the offset from the baseline to the top of the font # This is a positive value, relative to the baseline. # -proc FontAscent*(font: PFont): cint{.cdecl, importc: "TTF_FontAscent", +proc fontAscent*(font: PFont): cint{.cdecl, importc: "TTF_FontAscent", dynlib: ttfLibName.} # Get the offset from the baseline to the bottom of the font # This is a negative value, relative to the baseline. # -proc FontDescent*(font: PFont): cint{.cdecl, importc: "TTF_FontDescent", +proc fontDescent*(font: PFont): cint{.cdecl, importc: "TTF_FontDescent", dynlib: ttfLibName.} # Get the recommended spacing between lines of text for this font -proc FontLineSkip*(font: PFont): cint{.cdecl, +proc fontLineSkip*(font: PFont): cint{.cdecl, importc: "TTF_FontLineSkip", dynlib: ttfLibName.} # Get the number of faces of the font -proc FontFaces*(font: PFont): int32{.cdecl, importc: "TTF_FontFaces", +proc fontFaces*(font: PFont): int32{.cdecl, importc: "TTF_FontFaces", dynlib: ttfLibName.} # Get the font face attributes, if any -proc FontFaceIsFixedWidth*(font: PFont): cint{.cdecl, +proc fontFaceIsFixedWidth*(font: PFont): cint{.cdecl, importc: "TTF_FontFaceIsFixedWidth", dynlib: ttfLibName.} -proc FontFaceFamilyName*(font: PFont): cstring{.cdecl, +proc fontFaceFamilyName*(font: PFont): cstring{.cdecl, importc: "TTF_FontFaceFamilyName", dynlib: ttfLibName.} -proc FontFaceStyleName*(font: PFont): cstring{.cdecl, +proc fontFaceStyleName*(font: PFont): cstring{.cdecl, importc: "TTF_FontFaceStyleName", dynlib: ttfLibName.} # Get the metrics (dimensions) of a glyph -proc GlyphMetrics*(font: PFont, ch: Uint16, minx: var cint, +proc glyphMetrics*(font: PFont, ch: uint16, minx: var cint, maxx: var cint, miny: var cint, maxy: var cint, advance: var cint): cint{.cdecl, importc: "TTF_GlyphMetrics", dynlib: ttfLibName.} # Get the dimensions of a rendered string of text -proc SizeText*(font: PFont, text: cstring, w: var cint, y: var cint): cint{. +proc sizeText*(font: PFont, text: cstring, w: var cint, y: var cint): cint{. cdecl, importc: "TTF_SizeText", dynlib: ttfLibName.} -proc SizeUTF8*(font: PFont, text: cstring, w: var cint, y: var cint): cint{. +proc sizeUTF8*(font: PFont, text: cstring, w: var cint, y: var cint): cint{. cdecl, importc: "TTF_SizeUTF8", dynlib: ttfLibName.} -proc SizeUNICODE*(font: PFont, text: PUint16, w: var cint, y: var cint): cint{. +proc sizeUNICODE*(font: PFont, text: PUInt16, w: var cint, y: var cint): cint{. cdecl, importc: "TTF_SizeUNICODE", dynlib: ttfLibName.} # Create an 8-bit palettized surface and render the given text at # fast quality with the given font and color. The 0 pixel is the @@ -256,9 +256,9 @@ proc SizeUNICODE*(font: PFont, text: PUint16, w: var cint, y: var cint): cint{. # to the text color. # This function returns the new surface, or NULL if there was an error. # -proc RenderUTF8_Solid*(font: PFont, text: cstring, fg: TColor): PSurface{. +proc renderUTF8Solid*(font: PFont, text: cstring, fg: TColor): PSurface{. cdecl, importc: "TTF_RenderUTF8_Solid", dynlib: ttfLibName.} -proc RenderUNICODE_Solid*(font: PFont, text: PUint16, fg: TColor): PSurface{. +proc renderUNICODE_Solid*(font: PFont, text: PUInt16, fg: TColor): PSurface{. cdecl, importc: "TTF_RenderUNICODE_Solid", dynlib: ttfLibName.} # #Create an 8-bit palettized surface and render the given glyph at @@ -268,20 +268,20 @@ proc RenderUNICODE_Solid*(font: PFont, text: PUint16, fg: TColor): PSurface{. # centering in the X direction, and aligned normally in the Y direction. # This function returns the new surface, or NULL if there was an error. # -proc RenderGlyph_Solid*(font: PFont, ch: Uint16, fg: TColor): PSurface{. +proc renderGlyphSolid*(font: PFont, ch: uint16, fg: TColor): PSurface{. cdecl, importc: "TTF_RenderGlyph_Solid", dynlib: ttfLibName.} # Create an 8-bit palettized surface and render the given text at # high quality with the given font and colors. The 0 pixel is background, # while other pixels have varying degrees of the foreground color. # This function returns the new surface, or NULL if there was an error. # -proc RenderText_Shaded*(font: PFont, text: cstring, fg: TColor, +proc renderTextShaded*(font: PFont, text: cstring, fg: TColor, bg: TColor): PSurface{.cdecl, importc: "TTF_RenderText_Shaded", dynlib: ttfLibName.} -proc RenderUTF8_Shaded*(font: PFont, text: cstring, fg: TColor, +proc renderUTF8Shaded*(font: PFont, text: cstring, fg: TColor, bg: TColor): PSurface{.cdecl, importc: "TTF_RenderUTF8_Shaded", dynlib: ttfLibName.} -proc RenderUNICODE_Shaded*(font: PFont, text: PUint16, fg: TColor, +proc renderUNICODE_Shaded*(font: PFont, text: PUInt16, fg: TColor, bg: TColor): PSurface{.cdecl, importc: "TTF_RenderUNICODE_Shaded", dynlib: ttfLibName.} # Create an 8-bit palettized surface and render the given glyph at @@ -291,17 +291,17 @@ proc RenderUNICODE_Shaded*(font: PFont, text: PUint16, fg: TColor, # direction, and aligned normally in the Y direction. # This function returns the new surface, or NULL if there was an error. # -proc RenderGlyph_Shaded*(font: PFont, ch: Uint16, fg: TColor, bg: TColor): PSurface{. +proc renderGlyphShaded*(font: PFont, ch: uint16, fg: TColor, bg: TColor): PSurface{. cdecl, importc: "TTF_RenderGlyph_Shaded", dynlib: ttfLibName.} # Create a 32-bit ARGB surface and render the given text at high quality, # using alpha blending to dither the font with the given color. # This function returns the new surface, or NULL if there was an error. # -proc RenderText_Blended*(font: PFont, text: cstring, fg: TColor): PSurface{. +proc renderTextBlended*(font: PFont, text: cstring, fg: TColor): PSurface{. cdecl, importc: "TTF_RenderText_Blended", dynlib: ttfLibName.} -proc RenderUTF8_Blended*(font: PFont, text: cstring, fg: TColor): PSurface{. +proc renderUTF8Blended*(font: PFont, text: cstring, fg: TColor): PSurface{. cdecl, importc: "TTF_RenderUTF8_Blended", dynlib: ttfLibName.} -proc RenderUNICODE_Blended*(font: PFont, text: PUint16, fg: TColor): PSurface{. +proc RenderUNICODE_Blended*(font: PFont, text: PUInt16, fg: TColor): PSurface{. cdecl, importc: "TTF_RenderUNICODE_Blended", dynlib: ttfLibName.} # Create a 32-bit ARGB surface and render the given glyph at high quality, # using alpha blending to dither the font with the given color. @@ -309,29 +309,29 @@ proc RenderUNICODE_Blended*(font: PFont, text: PUint16, fg: TColor): PSurface{. # direction, and aligned normally in the Y direction. # This function returns the new surface, or NULL if there was an error. # -proc RenderGlyph_Blended*(font: PFont, ch: Uint16, fg: TColor): PSurface{. +proc renderGlyphBlended*(font: PFont, ch: uint16, fg: TColor): PSurface{. cdecl, importc: "TTF_RenderGlyph_Blended", dynlib: ttfLibName.} # For compatibility with previous versions, here are the old functions - ##define TTF_RenderText(font, text, fg, bg) + # #define TTF_RenderText(font, text, fg, bg) # TTF_RenderText_Shaded(font, text, fg, bg) - ##define TTF_RenderUTF8(font, text, fg, bg) + # #define TTF_RenderUTF8(font, text, fg, bg) # TTF_RenderUTF8_Shaded(font, text, fg, bg) - ##define TTF_RenderUNICODE(font, text, fg, bg) + # #define TTF_RenderUNICODE(font, text, fg, bg) # TTF_RenderUNICODE_Shaded(font, text, fg, bg) - # Close an opened font file -proc CloseFont*(font: PFont){.cdecl, importc: "TTF_CloseFont", + # Close an opened font file +proc closeFont*(font: PFont){.cdecl, importc: "TTF_CloseFont", dynlib: ttfLibName.} - #De-initialize TTF engine -proc Quit*(){.cdecl, importc: "TTF_Quit", dynlib: ttfLibName.} + # De-initialize TTF engine +proc quit*(){.cdecl, importc: "TTF_Quit", dynlib: ttfLibName.} # Check if the TTF engine is initialized -proc WasInit*(): cint{.cdecl, importc: "TTF_WasInit", dynlib: ttfLibName.} +proc wasInit*(): cint{.cdecl, importc: "TTF_WasInit", dynlib: ttfLibName.} -proc VERSION*(X: var sdl.Tversion) = - X.major = MAJOR_VERSION - X.minor = MINOR_VERSION - X.patch = PATCHLEVEL +proc version*(x: var sdl.Tversion) = + x.major = MAJOR_VERSION + x.minor = MINOR_VERSION + x.patch = PATCHLEVEL -proc RenderText_Solid*(font: PFont, text: cstring, fg: TColor): PSurface{. +proc renderTextSolid*(font: PFont, text: cstring, fg: TColor): PSurface{. cdecl, importc: "TTF_RenderText_Solid", dynlib: ttfLibName.} diff --git a/lib/wrappers/sdl/smpeg.nim b/lib/wrappers/sdl/smpeg.nim index 33f317631..318c0b3df 100644 --- a/lib/wrappers/sdl/smpeg.nim +++ b/lib/wrappers/sdl/smpeg.nim @@ -125,7 +125,7 @@ # #****************************************************************************** -import +import sdl when defined(windows): @@ -143,29 +143,29 @@ const type TFilterInfo*{.final.} = object - yuv_mb_square_error*: PUint16 - yuv_pixel_square_error*: PUint16 + yuvMbSquareError*: PUInt16 + yuvPixelSquareError*: PUInt16 PFilterInfo* = ptr TFilterInfo # MPEG filter definition PFilter* = ptr TFilter # Callback functions for the filter TFilterCallback* = proc (dest, source: POverlay, region: PRect, - filter_info: PFilterInfo, data: Pointer): Pointer{. + filterInfo: PFilterInfo, data: pointer): pointer{. cdecl.} - TFilterDestroy* = proc (Filter: PFilter): Pointer{.cdecl.} # The filter definition itself + TFilterDestroy* = proc (filter: PFilter): pointer{.cdecl.} # The filter definition itself TFilter*{.final.} = object # The null filter (default). It simply copies the source rectangle to the video overlay. - flags*: Uint32 - data*: Pointer + flags*: uint32 + data*: pointer callback*: TFilterCallback destroy*: TFilterDestroy -proc filter_null*(): PFilter{.cdecl, importc: "SMPEGfilter_null", +proc filterNull*(): PFilter{.cdecl, importc: "SMPEGfilter_null", dynlib: SmpegLibName.} # The bilinear filter. A basic low-pass filter that will produce a smoother image. -proc filter_bilinear*(): PFilter{.cdecl, +proc filterBilinear*(): PFilter{.cdecl, importc: "SMPEGfilter_bilinear", dynlib: SmpegLibName.} # The deblocking filter. It filters block borders and non-intra coded blocks to reduce blockiness -proc filter_deblocking*(): PFilter{.cdecl, +proc filterDeblocking*(): PFilter{.cdecl, importc: "SMPEGfilter_deblocking", dynlib: SmpegLibName.} #------------------------------------------------------------------------------ # SMPEG.h @@ -175,28 +175,28 @@ const MINOR_VERSION* = 4 PATCHLEVEL* = 2 -type - TVersion*{.final.} = object +type + TVersion* = object major*: byte minor*: byte patch*: byte - Pversion* = ptr Tversion # This is the actual SMPEG object - TSMPEG*{.final.} = object + Pversion* = ptr TVersion # This is the actual SMPEG object + TSMPEG* = object PSMPEG* = ptr TSMPEG # Used to get information about the SMPEG object - TInfo*{.final.} = object - has_audio*: int32 - has_video*: int32 + TInfo* = object + hasAudio*: int32 + hasVideo*: int32 width*: int32 height*: int32 - current_frame*: int32 - current_fps*: float64 - audio_string*: array[0..79, char] - audio_current_frame*: int32 - current_offset*: UInt32 - total_size*: UInt32 - current_time*: float64 - total_time*: float64 + currentFrame*: int32 + currentFps*: float64 + audioString*: array[0..79, char] + audioCurrentFrame*: int32 + currentOffset*: uint32 + totalSize*: uint32 + currentTime*: float64 + totalTime*: float64 PInfo* = ptr TInfo # Possible MPEG status codes @@ -208,7 +208,7 @@ const type Tstatus* = int32 Pstatus* = ptr int32 # Matches the declaration of SDL_UpdateRect() - TDisplayCallback* = proc (dst: PSurface, x, y: int, w, h: int): Pointer{. + TDisplayCallback* = proc (dst: PSurface, x, y: int, w, h: int): pointer{. cdecl.} # Create a new SMPEG object from an MPEG file. # On return, if 'info' is not NULL, it will be filled with information # about the MPEG object. @@ -218,15 +218,15 @@ type # subsystem. If not, you will have to use the playaudio() function below # to extract the decoded data. -proc SMPEG_new*(theFile: cstring, info: PInfo, audio: int): PSMPEG{.cdecl, +proc new*(theFile: cstring, info: PInfo, audio: int): PSMPEG{.cdecl, importc: "SMPEG_new", dynlib: SmpegLibName.} # The same as above for a file descriptor -proc new_descr*(theFile: int, info: PInfo, audio: int): PSMPEG{. +proc newDescr*(theFile: int, info: PInfo, audio: int): PSMPEG{. cdecl, importc: "SMPEG_new_descr", dynlib: SmpegLibName.} # The same as above but for a raw chunk of data. SMPEG makes a copy of the # data, so the application is free to delete after a successful call to this # function. -proc new_data*(data: Pointer, size: int, info: PInfo, audio: int): PSMPEG{. +proc newData*(data: pointer, size: int, info: PInfo, audio: int): PSMPEG{. cdecl, importc: "SMPEG_new_data", dynlib: SmpegLibName.} # Get current information about an SMPEG object proc getinfo*(mpeg: PSMPEG, info: PInfo){.cdecl, @@ -247,13 +247,13 @@ proc status*(mpeg: PSMPEG): Tstatus{.cdecl, importc: "SMPEG_status", dynlib: SmpegLibName.} # status # Set the audio volume of an MPEG stream, in the range 0-100 -proc setvolume*(mpeg: PSMPEG, volume: int){.cdecl, +proc setVolume*(mpeg: PSMPEG, volume: int){.cdecl, importc: "SMPEG_setvolume", dynlib: SmpegLibName.} # Set the destination surface for MPEG video playback # 'surfLock' is a mutex used to synchronize access to 'dst', and can be NULL. # 'callback' is a function called when an area of 'dst' needs to be updated. # If 'callback' is NULL, the default function (SDL_UpdateRect) will be used. -proc setdisplay*(mpeg: PSMPEG, dst: PSurface, surfLock: Pmutex, +proc setDisplay*(mpeg: PSMPEG, dst: PSurface, surfLock: PMutex, callback: TDisplayCallback){.cdecl, importc: "SMPEG_setdisplay", dynlib: SmpegLibName.} # Set or clear looping play on an SMPEG object @@ -264,12 +264,12 @@ proc scaleXY*(mpeg: PSMPEG, width, height: int){.cdecl, importc: "SMPEG_scaleXY", dynlib: SmpegLibName.} proc scale*(mpeg: PSMPEG, scale: int){.cdecl, importc: "SMPEG_scale", dynlib: SmpegLibName.} -proc Double*(mpeg: PSMPEG, doubleit: bool) +proc double*(mpeg: PSMPEG, doubleit: bool) # Move the video display area within the destination surface proc move*(mpeg: PSMPEG, x, y: int){.cdecl, importc: "SMPEG_move", dynlib: SmpegLibName.} # Set the region of the video to be shown -proc setdisplayregion*(mpeg: PSMPEG, x, y, w, h: int){.cdecl, +proc setDisplayRegion*(mpeg: PSMPEG, x, y, w, h: int){.cdecl, importc: "SMPEG_setdisplayregion", dynlib: SmpegLibName.} # Play an SMPEG object proc play*(mpeg: PSMPEG){.cdecl, importc: "SMPEG_play", @@ -312,7 +312,7 @@ proc error*(mpeg: PSMPEG): cstring{.cdecl, importc: "SMPEG_error", proc playAudio*(mpeg: PSMPEG, stream: pointer, length: int): int{.cdecl, importc: "SMPEG_playAudio", dynlib: SmpegLibName.} # Wrapper for playAudio() that can be passed to SDL and SDL_mixer -proc playAudioSDL*(mpeg: Pointer, stream: pointer, length: int){.cdecl, +proc playAudioSDL*(mpeg: pointer, stream: pointer, length: int){.cdecl, importc: "SMPEG_playAudioSDL", dynlib: SmpegLibName.} # Get the best SDL audio spec for the audio stream proc wantedSpec*(mpeg: PSMPEG, wanted: PAudioSpec): int{.cdecl, @@ -322,14 +322,11 @@ proc actualSpec*(mpeg: PSMPEG, spec: PAudioSpec){.cdecl, importc: "SMPEG_actualSpec", dynlib: SmpegLibName.} # This macro can be used to fill a version structure with the compile-time # version of the SDL library. -proc GETVERSION*(X: var Tversion) -# implementation +proc getversion*(x: var TVersion) = + x.major = MAJOR_VERSION + x.minor = MINOR_VERSION + x.patch = PATCHLEVEL proc double(mpeg: PSMPEG, doubleit: bool) = if doubleit: scale(mpeg, 2) else: scale(mpeg, 1) - -proc GETVERSION(X: var Tversion) = - X.major = MAJOR_VERSION - X.minor = MINOR_VERSION - X.patch = PATCHLEVEL diff --git a/lib/wrappers/sphinx.nim b/lib/wrappers/sphinx.nim index b4e127c65..e4a282968 100644 --- a/lib/wrappers/sphinx.nim +++ b/lib/wrappers/sphinx.nim @@ -12,7 +12,7 @@ # did not, you can find it at http://www.gnu.org/ # -## Nimrod wrapper for ``sphinx``. +## Nim wrapper for ``sphinx``. {.deadCodeElim: on.} when defined(windows): diff --git a/lib/wrappers/sqlite3.nim b/lib/wrappers/sqlite3.nim index 7b7f0874e..e3a3fa0b8 100644 --- a/lib/wrappers/sqlite3.nim +++ b/lib/wrappers/sqlite3.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -88,8 +88,8 @@ const SQLITE_REINDEX* = 27 SQLITE_DENY* = 1 SQLITE_IGNORE* = 2 # Original from sqlite3.h: - ##define SQLITE_STATIC ((void(*)(void *))0) - ##define SQLITE_TRANSIENT ((void(*)(void *))-1) + #define SQLITE_STATIC ((void(*)(void *))0) + #define SQLITE_TRANSIENT ((void(*)(void *))-1) SQLITE_DETERMINISTIC* = 0x800 const @@ -178,15 +178,15 @@ proc errcode*(db: PSqlite3): int32{.cdecl, dynlib: Lib, importc: "sqlite3_errcod proc errmsg*(para1: PSqlite3): cstring{.cdecl, dynlib: Lib, importc: "sqlite3_errmsg".} proc errmsg16*(para1: PSqlite3): pointer{.cdecl, dynlib: Lib, importc: "sqlite3_errmsg16".} -proc prepare*(db: PSqlite3, zSql: cstring, nBytes: int32, ppStmt: var PStmt, +proc prepare*(db: PSqlite3, zSql: cstring, nBytes: int32, ppStmt: var Pstmt, pzTail: ptr cstring): int32{.cdecl, dynlib: Lib, importc: "sqlite3_prepare".} -proc prepare_v2*(db: PSqlite3, zSql: cstring, nByte: cint, ppStmt: var PStmt, +proc prepare_v2*(db: PSqlite3, zSql: cstring, nByte: cint, ppStmt: var Pstmt, pzTail: ptr cstring): cint {. importc: "sqlite3_prepare_v2", cdecl, dynlib: Lib.} -proc prepare16*(db: PSqlite3, zSql: pointer, nBytes: int32, ppStmt: var PStmt, +proc prepare16*(db: PSqlite3, zSql: pointer, nBytes: int32, ppStmt: var Pstmt, pzTail: var pointer): int32{.cdecl, dynlib: Lib, importc: "sqlite3_prepare16".} proc bind_blob*(para1: Pstmt, para2: int32, para3: pointer, n: int32, diff --git a/lib/wrappers/tinyc.nim b/lib/wrappers/tinyc.nim index f685c714d..ac6cb70f1 100644 --- a/lib/wrappers/tinyc.nim +++ b/lib/wrappers/tinyc.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2010 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/lib/wrappers/zip/libzip.nim b/lib/wrappers/zip/libzip.nim index 0b8d2b3ec..86670b450 100644 --- a/lib/wrappers/zip/libzip.nim +++ b/lib/wrappers/zip/libzip.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2013 Andreas Rumpf # # See the file "copying.txt", included in this @@ -64,15 +64,15 @@ type TZipSourceCallback* = proc (state: pointer, data: pointer, length: int, cmd: TZipSourceCmd): int {.cdecl.} PZipStat* = ptr TZipStat - TZipStat* = object ## the 'zip_stat' struct + TZipStat* = object ## the 'zip_stat' struct name*: cstring ## name of the file index*: int32 ## index within archive crc*: int32 ## crc of file data - mtime*: TTime ## modification time + mtime*: Time ## modification time size*: int ## size of file (uncompressed) - compSize*: int ## size of file (compressed) - compMethod*: int16 ## compression method used - encryptionMethod*: int16 ## encryption method used + compSize*: int ## size of file (compressed) + compMethod*: int16 ## compression method used + encryptionMethod*: int16 ## encryption method used TZip = object TZipSource = object @@ -225,7 +225,7 @@ proc zip_source_buffer*(para1: PZip, para2: pointer, para3: int, para4: int32): cdecl, mydll, importc: "zip_source_buffer".} proc zip_source_file*(para1: PZip, para2: cstring, para3: int, para4: int): PZipSource {. cdecl, mydll, importc: "zip_source_file".} -proc zip_source_filep*(para1: PZip, para2: TFile, para3: int, para4: int): PZipSource {. +proc zip_source_filep*(para1: PZip, para2: File, para3: int, para4: int): PZipSource {. cdecl, mydll, importc: "zip_source_filep".} proc zip_source_free*(para1: PZipSource) {.cdecl, mydll, importc: "zip_source_free".} diff --git a/lib/wrappers/zip/zlib.nim b/lib/wrappers/zip/zlib.nim index cb61783d2..e3530d566 100644 --- a/lib/wrappers/zip/zlib.nim +++ b/lib/wrappers/zip/zlib.nim @@ -14,32 +14,32 @@ type Ulong* = int Ulongf* = int Pulongf* = ptr Ulongf - z_off_t* = int32 - pbyte* = cstring - pbytef* = cstring - TAllocfunc* = proc (p: pointer, items: uInt, size: uInt): pointer{.cdecl.} + ZOffT* = int32 + Pbyte* = cstring + Pbytef* = cstring + TAllocfunc* = proc (p: pointer, items: Uint, size: Uint): pointer{.cdecl.} TFreeFunc* = proc (p: pointer, address: pointer){.cdecl.} TInternalState*{.final, pure.} = object - PInternalState* = ptr TInternalstate + PInternalState* = ptr TInternalState TZStream*{.final, pure.} = object - next_in*: pbytef - avail_in*: uInt - total_in*: uLong - next_out*: pbytef - avail_out*: uInt - total_out*: uLong - msg*: pbytef + nextIn*: Pbytef + availIn*: Uint + totalIn*: Ulong + nextOut*: Pbytef + availOut*: Uint + totalOut*: Ulong + msg*: Pbytef state*: PInternalState - zalloc*: TAllocFunc + zalloc*: TAllocfunc zfree*: TFreeFunc opaque*: pointer - data_type*: int32 - adler*: uLong - reserved*: uLong + dataType*: int32 + adler*: Ulong + reserved*: Ulong TZStreamRec* = TZStream PZstream* = ptr TZStream - gzFile* = pointer + GzFile* = pointer const Z_NO_FLUSH* = 0 @@ -78,79 +78,79 @@ proc inflate*(strm: var TZStream, flush: int32): int32{.cdecl, dynlib: libz, importc: "inflate".} proc inflateEnd*(strm: var TZStream): int32{.cdecl, dynlib: libz, importc: "inflateEnd".} -proc deflateSetDictionary*(strm: var TZStream, dictionary: pbytef, - dictLength: uInt): int32{.cdecl, dynlib: libz, +proc deflateSetDictionary*(strm: var TZStream, dictionary: Pbytef, + dictLength: Uint): int32{.cdecl, dynlib: libz, importc: "deflateSetDictionary".} -proc deflateCopy*(dest, source: var TZstream): int32{.cdecl, dynlib: libz, +proc deflateCopy*(dest, source: var TZStream): int32{.cdecl, dynlib: libz, importc: "deflateCopy".} proc deflateReset*(strm: var TZStream): int32{.cdecl, dynlib: libz, importc: "deflateReset".} proc deflateParams*(strm: var TZStream, level: int32, strategy: int32): int32{. cdecl, dynlib: libz, importc: "deflateParams".} -proc inflateSetDictionary*(strm: var TZStream, dictionary: pbytef, - dictLength: uInt): int32{.cdecl, dynlib: libz, +proc inflateSetDictionary*(strm: var TZStream, dictionary: Pbytef, + dictLength: Uint): int32{.cdecl, dynlib: libz, importc: "inflateSetDictionary".} proc inflateSync*(strm: var TZStream): int32{.cdecl, dynlib: libz, importc: "inflateSync".} proc inflateReset*(strm: var TZStream): int32{.cdecl, dynlib: libz, importc: "inflateReset".} -proc compress*(dest: pbytef, destLen: puLongf, source: pbytef, sourceLen: uLong): cint{. +proc compress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, sourceLen: Ulong): cint{. cdecl, dynlib: libz, importc: "compress".} -proc compress2*(dest: pbytef, destLen: puLongf, source: pbytef, - sourceLen: uLong, level: cint): cint{.cdecl, dynlib: libz, +proc compress2*(dest: Pbytef, destLen: Pulongf, source: Pbytef, + sourceLen: Ulong, level: cint): cint{.cdecl, dynlib: libz, importc: "compress2".} -proc uncompress*(dest: pbytef, destLen: puLongf, source: pbytef, - sourceLen: uLong): cint{.cdecl, dynlib: libz, +proc uncompress*(dest: Pbytef, destLen: Pulongf, source: Pbytef, + sourceLen: Ulong): cint{.cdecl, dynlib: libz, importc: "uncompress".} -proc compressBound*(sourceLen: uLong): uLong {.cdecl, dynlib: libz, importc.} -proc gzopen*(path: cstring, mode: cstring): gzFile{.cdecl, dynlib: libz, +proc compressBound*(sourceLen: Ulong): Ulong {.cdecl, dynlib: libz, importc.} +proc gzopen*(path: cstring, mode: cstring): GzFile{.cdecl, dynlib: libz, importc: "gzopen".} -proc gzdopen*(fd: int32, mode: cstring): gzFile{.cdecl, dynlib: libz, +proc gzdopen*(fd: int32, mode: cstring): GzFile{.cdecl, dynlib: libz, importc: "gzdopen".} -proc gzsetparams*(thefile: gzFile, level: int32, strategy: int32): int32{.cdecl, +proc gzsetparams*(thefile: GzFile, level: int32, strategy: int32): int32{.cdecl, dynlib: libz, importc: "gzsetparams".} -proc gzread*(thefile: gzFile, buf: pointer, length: int): int32{.cdecl, +proc gzread*(thefile: GzFile, buf: pointer, length: int): int32{.cdecl, dynlib: libz, importc: "gzread".} -proc gzwrite*(thefile: gzFile, buf: pointer, length: int): int32{.cdecl, +proc gzwrite*(thefile: GzFile, buf: pointer, length: int): int32{.cdecl, dynlib: libz, importc: "gzwrite".} -proc gzprintf*(thefile: gzFile, format: pbytef): int32{.varargs, cdecl, +proc gzprintf*(thefile: GzFile, format: Pbytef): int32{.varargs, cdecl, dynlib: libz, importc: "gzprintf".} -proc gzputs*(thefile: gzFile, s: pbytef): int32{.cdecl, dynlib: libz, +proc gzputs*(thefile: GzFile, s: Pbytef): int32{.cdecl, dynlib: libz, importc: "gzputs".} -proc gzgets*(thefile: gzFile, buf: pbytef, length: int32): pbytef{.cdecl, +proc gzgets*(thefile: GzFile, buf: Pbytef, length: int32): Pbytef{.cdecl, dynlib: libz, importc: "gzgets".} -proc gzputc*(thefile: gzFile, c: char): char{.cdecl, dynlib: libz, +proc gzputc*(thefile: GzFile, c: char): char{.cdecl, dynlib: libz, importc: "gzputc".} -proc gzgetc*(thefile: gzFile): char{.cdecl, dynlib: libz, importc: "gzgetc".} -proc gzflush*(thefile: gzFile, flush: int32): int32{.cdecl, dynlib: libz, +proc gzgetc*(thefile: GzFile): char{.cdecl, dynlib: libz, importc: "gzgetc".} +proc gzflush*(thefile: GzFile, flush: int32): int32{.cdecl, dynlib: libz, importc: "gzflush".} -proc gzseek*(thefile: gzFile, offset: z_off_t, whence: int32): z_off_t{.cdecl, +proc gzseek*(thefile: GzFile, offset: ZOffT, whence: int32): ZOffT{.cdecl, dynlib: libz, importc: "gzseek".} -proc gzrewind*(thefile: gzFile): int32{.cdecl, dynlib: libz, importc: "gzrewind".} -proc gztell*(thefile: gzFile): z_off_t{.cdecl, dynlib: libz, importc: "gztell".} -proc gzeof*(thefile: gzFile): int {.cdecl, dynlib: libz, importc: "gzeof".} -proc gzclose*(thefile: gzFile): int32{.cdecl, dynlib: libz, importc: "gzclose".} -proc gzerror*(thefile: gzFile, errnum: var int32): pbytef{.cdecl, dynlib: libz, +proc gzrewind*(thefile: GzFile): int32{.cdecl, dynlib: libz, importc: "gzrewind".} +proc gztell*(thefile: GzFile): ZOffT{.cdecl, dynlib: libz, importc: "gztell".} +proc gzeof*(thefile: GzFile): int {.cdecl, dynlib: libz, importc: "gzeof".} +proc gzclose*(thefile: GzFile): int32{.cdecl, dynlib: libz, importc: "gzclose".} +proc gzerror*(thefile: GzFile, errnum: var int32): Pbytef{.cdecl, dynlib: libz, importc: "gzerror".} -proc adler32*(adler: uLong, buf: pbytef, length: uInt): uLong{.cdecl, +proc adler32*(adler: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, dynlib: libz, importc: "adler32".} ## **Warning**: Adler-32 requires at least a few hundred bytes to get rolling. -proc crc32*(crc: uLong, buf: pbytef, length: uInt): uLong{.cdecl, dynlib: libz, +proc crc32*(crc: Ulong, buf: Pbytef, length: Uint): Ulong{.cdecl, dynlib: libz, importc: "crc32".} proc deflateInitu*(strm: var TZStream, level: int32, version: cstring, - stream_size: int32): int32{.cdecl, dynlib: libz, + streamSize: int32): int32{.cdecl, dynlib: libz, importc: "deflateInit_".} proc inflateInitu*(strm: var TZStream, version: cstring, - stream_size: int32): int32 {. + streamSize: int32): int32 {. cdecl, dynlib: libz, importc: "inflateInit_".} proc deflateInit*(strm: var TZStream, level: int32): int32 proc inflateInit*(strm: var TZStream): int32 proc deflateInit2u*(strm: var TZStream, level: int32, `method`: int32, windowBits: int32, memLevel: int32, strategy: int32, - version: cstring, stream_size: int32): int32 {.cdecl, + version: cstring, streamSize: int32): int32 {.cdecl, dynlib: libz, importc: "deflateInit2_".} proc inflateInit2u*(strm: var TZStream, windowBits: int32, version: cstring, - stream_size: int32): int32{.cdecl, dynlib: libz, + streamSize: int32): int32{.cdecl, dynlib: libz, importc: "inflateInit2_".} proc deflateInit2*(strm: var TZStream, level, `method`, windowBits, memLevel, @@ -159,29 +159,29 @@ proc inflateInit2*(strm: var TZStream, windowBits: int32): int32 proc zError*(err: int32): cstring{.cdecl, dynlib: libz, importc: "zError".} proc inflateSyncPoint*(z: PZstream): int32{.cdecl, dynlib: libz, importc: "inflateSyncPoint".} -proc get_crc_table*(): pointer{.cdecl, dynlib: libz, importc: "get_crc_table".} +proc getCrcTable*(): pointer{.cdecl, dynlib: libz, importc: "get_crc_table".} proc deflateInit(strm: var TZStream, level: int32): int32 = - result = deflateInitu(strm, level, ZLIB_VERSION(), sizeof(TZStream).cint) + result = deflateInitu(strm, level, zlibVersion(), sizeof(TZStream).cint) proc inflateInit(strm: var TZStream): int32 = - result = inflateInitu(strm, ZLIB_VERSION(), sizeof(TZStream).cint) + result = inflateInitu(strm, zlibVersion(), sizeof(TZStream).cint) proc deflateInit2(strm: var TZStream, level, `method`, windowBits, memLevel, strategy: int32): int32 = result = deflateInit2u(strm, level, `method`, windowBits, memLevel, - strategy, ZLIB_VERSION(), sizeof(TZStream).cint) + strategy, zlibVersion(), sizeof(TZStream).cint) proc inflateInit2(strm: var TZStream, windowBits: int32): int32 = - result = inflateInit2u(strm, windowBits, ZLIB_VERSION(), + result = inflateInit2u(strm, windowBits, zlibVersion(), sizeof(TZStream).cint) -proc zlibAllocMem*(AppData: Pointer, Items, Size: int): Pointer {.cdecl.} = - result = Alloc(Items * Size) +proc zlibAllocMem*(appData: pointer, items, size: int): pointer {.cdecl.} = + result = alloc(items * size) -proc zlibFreeMem*(AppData, `Block`: Pointer) {.cdecl.} = - dealloc(`Block`) +proc zlibFreeMem*(appData, `block`: pointer) {.cdecl.} = + dealloc(`block`) proc uncompress*(sourceBuf: cstring, sourceLen: int): string = ## Given a deflated cstring returns its inflated version. @@ -202,7 +202,7 @@ proc uncompress*(sourceBuf: cstring, sourceLen: int): string = var z: TZStream # Initialize input. - z.next_in = sourceBuf + z.nextIn = sourceBuf # Input left to decompress. var left = zlib.Uint(sourceLen) @@ -220,12 +220,12 @@ proc uncompress*(sourceBuf: cstring, sourceLen: int): string = var decompressed = newStringOfCap(space) # Initialize output. - z.next_out = addr(decompressed[0]) + z.nextOut = addr(decompressed[0]) # Output generated so far. var have = 0 # Set up for gzip decoding. - z.avail_in = 0; + z.availIn = 0; var status = inflateInit2(z, (15+16)) if status != Z_OK: # Out of memory. @@ -241,10 +241,10 @@ proc uncompress*(sourceBuf: cstring, sourceLen: int): string = discard inflateReset(z) # Provide input for inflate. - if z.avail_in == 0: + if z.availIn == 0: # This only makes sense in the C version using unsigned values. - z.avail_in = left - left -= z.avail_in + z.availIn = left + left -= z.availIn # Decompress the available input. while true: @@ -260,15 +260,15 @@ proc uncompress*(sourceBuf: cstring, sourceLen: int): string = # Increase space. decompressed.setLen(space) # Update output pointer (might have moved). - z.next_out = addr(decompressed[have]) + z.nextOut = addr(decompressed[have]) # Provide output space for inflate. - z.avail_out = zlib.Uint(space - have) - have += z.avail_out; + z.availOut = zlib.Uint(space - have) + have += z.availOut; # Inflate and update the decompressed size. status = inflate(z, Z_SYNC_FLUSH); - have -= z.avail_out; + have -= z.availOut; # Bail out if any errors. if status != Z_OK and status != Z_BUF_ERROR and status != Z_STREAM_END: @@ -279,10 +279,10 @@ proc uncompress*(sourceBuf: cstring, sourceLen: int): string = # Repeat until all output is generated from provided input (note # that even if z.avail_in is zero, there may still be pending # output -- we're not done until the output buffer isn't filled) - if z.avail_out != 0: + if z.availOut != 0: break # Continue until all input consumed. - if left == 0 and z.avail_in == 0: + if left == 0 and z.availIn == 0: break # Verify that the input is a valid gzip stream. diff --git a/lib/wrappers/zip/zzip.nim b/lib/wrappers/zip/zzip.nim index a656322ee..73fd53c34 100644 --- a/lib/wrappers/zip/zzip.nim +++ b/lib/wrappers/zip/zzip.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2008 Andreas Rumpf # # See the file "copying.txt", included in this diff --git a/readme.md b/readme.md index e8c081d4e..7c6fc8e45 100644 --- a/readme.md +++ b/readme.md @@ -1,15 +1,15 @@ -# Nimrod Compiler -This repo contains the Nimrod compiler, Nimrod's stdlib, tools and +# Nim Compiler +This repo contains the Nim compiler, Nim's stdlib, tools and documentation. ## Compiling -Compiling the Nimrod compiler is quite straightforward. Because -the Nimrod compiler itself is written in the Nimrod programming language +Compiling the Nim compiler is quite straightforward. Because +the Nim compiler itself is written in the Nim programming language the C source of an older version of the compiler are needed to bootstrap the -latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources). +latest version. The C sources are available in a separate repo [here](http://github.com/nim-code/csources). Pre-compiled snapshots of the compiler are also available on -[Nimbuild](http://build.nimrod-lang.org/). Your platform however may not +[Nimbuild](http://build.nim-lang.org/). Your platform however may not currently be built for. The compiler currently supports the following platform and architecture @@ -35,11 +35,11 @@ $ cd Nimrod $ git clone --depth 1 git://github.com/nimrod-code/csources $ cd csources && sh build.sh $ cd .. -$ bin/nimrod c koch +$ bin/nim c koch $ ./koch boot -d:release ``` -``koch install [dir]`` may then be used to install Nimrod, or you can simply +``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 [doc/koch.txt](doc/koch.txt). @@ -48,16 +48,16 @@ The above steps can be performed on Windows in a similar fashion, the instead of ``build.sh``. ## Getting help -A [forum](http://forum.nimrod-lang.org/) is available if you have any +A [forum](http://forum.nim-lang.org/) is available if you have any questions, and you can also get help in the IRC channel on -[Freenode](irc://irc.freenode.net/nimrod) in #nimrod. If you ask questions on -[StackOverflow use the nimrod -tag](http://stackoverflow.com/questions/tagged/nimrod). +[Freenode](irc://irc.freenode.net/nim) in #nim. If you ask questions on +[StackOverflow use the nim +tag](http://stackoverflow.com/questions/tagged/nim). ## License The compiler and the standard library are licensed under the MIT license, except for some modules where the documentation suggests otherwise. This means -that you can use any license for your own programs developed with Nimrod, +that you can use any license for your own programs developed with Nim, allowing you to create commercial applications. Read copying.txt for more details. diff --git a/readme.txt b/readme.txt index 3f6aef05c..7c6fc8e45 100644 --- a/readme.txt +++ b/readme.txt @@ -1,15 +1,15 @@ -# Nimrod Compiler -This repo contains the Nimrod compiler, Nimrod's stdlib, tools and +# Nim Compiler +This repo contains the Nim compiler, Nim's stdlib, tools and documentation. ## Compiling -Compiling the Nimrod compiler is quite straightforward. Because -the Nimrod compiler itself is written in the Nimrod programming language +Compiling the Nim compiler is quite straightforward. Because +the Nim compiler itself is written in the Nim programming language the C source of an older version of the compiler are needed to bootstrap the -latest version. The C sources are available in a separate repo [here](http://github.com/nimrod-code/csources). +latest version. The C sources are available in a separate repo [here](http://github.com/nim-code/csources). Pre-compiled snapshots of the compiler are also available on -[Nimbuild](http://build.nimrod-lang.org/). Your platform however may not +[Nimbuild](http://build.nim-lang.org/). Your platform however may not currently be built for. The compiler currently supports the following platform and architecture @@ -33,13 +33,13 @@ If you are on a fairly modern *nix system, the following steps should work: $ git clone git://github.com/Araq/Nimrod.git $ cd Nimrod $ git clone --depth 1 git://github.com/nimrod-code/csources -$ cd csources && ./build.sh +$ cd csources && sh build.sh $ cd .. -$ bin/nimrod c koch +$ bin/nim c koch $ ./koch boot -d:release ``` -``koch install [dir]`` may then be used to install Nimrod, or you can simply +``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 [doc/koch.txt](doc/koch.txt). @@ -48,16 +48,16 @@ The above steps can be performed on Windows in a similar fashion, the instead of ``build.sh``. ## Getting help -A [forum](http://forum.nimrod-lang.org/) is available if you have any +A [forum](http://forum.nim-lang.org/) is available if you have any questions, and you can also get help in the IRC channel on -[Freenode](irc://irc.freenode.net/nimrod) in #nimrod. If you ask questions on -[StackOverflow use the nimrod -tag](http://stackoverflow.com/questions/tagged/nimrod). +[Freenode](irc://irc.freenode.net/nim) in #nim. If you ask questions on +[StackOverflow use the nim +tag](http://stackoverflow.com/questions/tagged/nim). ## License The compiler and the standard library are licensed under the MIT license, except for some modules where the documentation suggests otherwise. This means -that you can use any license for your own programs developed with Nimrod, +that you can use any license for your own programs developed with Nim, allowing you to create commercial applications. Read copying.txt for more details. diff --git a/tests/actiontable/tactiontable2.nim b/tests/actiontable/tactiontable2.nim index bfeb1c169..99bb3dca0 100644 --- a/tests/actiontable/tactiontable2.nim +++ b/tests/actiontable/tactiontable2.nim @@ -1,6 +1,6 @@ discard """ line: 21 - errormsg: "invalid type: 'TTable[string, proc (string){.gcsafe.}]'" + errormsg: "invalid type: 'Table[string, proc (string){.gcsafe.}]'" """ import tables diff --git a/tests/assert/tassert.nim b/tests/assert/tassert.nim index 0ea8d2034..b3df30bd1 100644 --- a/tests/assert/tassert.nim +++ b/tests/assert/tassert.nim @@ -5,7 +5,7 @@ discard """ """ # test assert and exception handling -proc callB() = assert(False) +proc callB() = assert(false) proc callA() = callB() proc callC() = callA() diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim index 2d65db4bd..5165b0f06 100644 --- a/tests/async/tasyncawait.nim +++ b/tests/async/tasyncawait.nim @@ -21,15 +21,8 @@ proc launchSwarm(port: TPort) {.async.} = var sock = newAsyncRawSocket() await connect(sock, "localhost", port) - when true: - await sendMessages(sock) - closeSocket(sock) - else: - # Issue #932: https://github.com/Araq/Nimrod/issues/932 - var msgFut = sendMessages(sock) - msgFut.callback = - proc () = - closeSocket(sock) + await sendMessages(sock) + closeSocket(sock) proc readMessages(client: TAsyncFD) {.async.} = while true: @@ -47,18 +40,18 @@ proc readMessages(client: TAsyncFD) {.async.} = proc createServer(port: TPort) {.async.} = var server = newAsyncRawSocket() block: - var name: TSockaddr_in + var name: Sockaddr_in when defined(windows): name.sin_family = toInt(AF_INET).int16 else: name.sin_family = toInt(AF_INET) name.sin_port = htons(int16(port)) name.sin_addr.s_addr = htonl(INADDR_ANY) - if bindAddr(server.TSocketHandle, cast[ptr TSockAddr](addr(name)), - sizeof(name).TSocklen) < 0'i32: - osError(osLastError()) + if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)), + sizeof(name).Socklen) < 0'i32: + raiseOSError(osLastError()) - discard server.TSocketHandle.listen() + discard server.SocketHandle.listen() while true: var client = await accept(server) asyncCheck readMessages(client) diff --git a/tests/async/tasyncdiscard.nim b/tests/async/tasyncdiscard.nim index 966851acc..71aba29e2 100644 --- a/tests/async/tasyncdiscard.nim +++ b/tests/async/tasyncdiscard.nim @@ -13,7 +13,7 @@ discard """ import asyncio, asyncdispatch, asyncnet proc main {.async.} = - proc f: PFuture[int] {.async.} = + proc f: Future[int] {.async.} = discard echo 1 discard @@ -24,7 +24,7 @@ proc main {.async.} = echo x echo 3 - proc g: PFuture[int] {.async.} = + proc g: Future[int] {.async.} = discard echo 4 discard diff --git a/tests/async/tasyncexceptions.nim b/tests/async/tasyncexceptions.nim index ca73c6a3d..30ef41756 100644 --- a/tests/async/tasyncexceptions.nim +++ b/tests/async/tasyncexceptions.nim @@ -1,15 +1,15 @@ discard """ file: "tasyncexceptions.nim" exitcode: 1 - outputsub: "Error: unhandled exception: foobar [E_Base]" + outputsub: "Error: unhandled exception: foobar [Exception]" """ import asyncdispatch -proc accept(): PFuture[int] {.async.} = +proc accept(): Future[int] {.async.} = await sleepAsync(100) result = 4 -proc recvLine(fd: int): PFuture[string] {.async.} = +proc recvLine(fd: int): Future[string] {.async.} = await sleepAsync(100) return "get" diff --git a/tests/async/tasyncfile.nim b/tests/async/tasyncfile.nim new file mode 100644 index 000000000..c3cf33512 --- /dev/null +++ b/tests/async/tasyncfile.nim @@ -0,0 +1,36 @@ +discard """ + file: "tasyncfile.nim" + exitcode: 0 +""" +import asyncfile, asyncdispatch, os + +proc main() {.async.} = + let fn = getTempDir() / "foobar.txt" + removeFile(fn) + + # Simple write/read test. + block: + var file = openAsync(fn, fmReadWrite) + await file.write("test") + file.setFilePos(0) + await file.write("foo") + file.setFilePos(0) + let data = await file.readAll() + doAssert data == "foot" + file.close() + + # Append test + block: + var file = openAsync(fn, fmAppend) + await file.write("\ntest2") + let errorTest = file.readAll() + await errorTest + doAssert errorTest.failed + file.close() + file = openAsync(fn, fmRead) + let data = await file.readAll() + + doAssert data == "foot\ntest2" + file.close() + +waitFor main() diff --git a/tests/async/tasynciossl.nim b/tests/async/tasynciossl.nim index 6b38fcf7b..b0222e4ff 100644 --- a/tests/async/tasynciossl.nim +++ b/tests/async/tasynciossl.nim @@ -1,6 +1,6 @@ discard """ file: "tasynciossl.nim" - cmd: "nimrod $target --hints:on --define:ssl $options $file" + cmd: "nim $target --hints:on --define:ssl $options $file" output: "20000" """ import sockets, asyncio, strutils, times diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim new file mode 100644 index 000000000..66ea40d49 --- /dev/null +++ b/tests/async/tasynctry.nim @@ -0,0 +1,51 @@ +discard """ + file: "tasynctry.nim" + exitcode: 0 + output: ''' +Generic except: Test +Specific except +Multiple idents in except +Multiple except branches +Multiple except branches 2 +''' +""" +import asyncdispatch + +# Here we are testing the ability to catch exceptions. + +proc foobar() {.async.} = + if 5 == 5: + raise newException(EInvalidIndex, "Test") + +proc catch() {.async.} = + # TODO: Create a test for when exceptions are not caught. + try: + await foobar() + except: + echo("Generic except: ", getCurrentExceptionMsg()) + + try: + await foobar() + except EInvalidIndex: + echo("Specific except") + + try: + await foobar() + except OSError, EInvalidField, EInvalidIndex: + echo("Multiple idents in except") + + try: + await foobar() + except OSError, EInvalidField: + assert false + except EInvalidIndex: + echo("Multiple except branches") + + try: + await foobar() + except EInvalidIndex: + echo("Multiple except branches 2") + except OSError, EInvalidField: + assert false + +asyncCheck catch() diff --git a/tests/async/tnestedpfuturetypeparam.nim b/tests/async/tnestedpfuturetypeparam.nim index 1db442170..bf346ff8e 100644 --- a/tests/async/tnestedpfuturetypeparam.nim +++ b/tests/async/tnestedpfuturetypeparam.nim @@ -1,8 +1,8 @@ import asyncdispatch, asyncnet proc main {.async.} = - proc f: PFuture[seq[int]] {.async.} = - await newAsyncSocket().connect("www.google.com", TPort(80)) + proc f: Future[seq[int]] {.async.} = + await newAsyncSocket().connect("www.google.com", Port(80)) let x = await f() asyncCheck main() diff --git a/tests/benchmark.nim b/tests/benchmark.nim index 8dd9cc2e2..0613d1bf9 100644 --- a/tests/benchmark.nim +++ b/tests/benchmark.nim @@ -1,6 +1,6 @@ # # -# Nimrod Benchmark tool +# Nim Benchmark tool # (c) Copyright 2012 Dominik Picheta # # See the file "copying.txt", included in this @@ -15,7 +15,7 @@ type proc compileBench(file: string) = ## Compiles ``file``. - doAssert(execCmdEx("nimrod c -d:release " & file).exitCode == QuitSuccess) + doAssert(execCmdEx("nim c -d:release " & file).exitCode == QuitSuccess) proc runBench(file: string): TBenchResult = ## Runs ``file`` and returns info on how long it took to run. diff --git a/tests/bind/tnicerrorforsymchoice.nim b/tests/bind/tnicerrorforsymchoice.nim index 4e7a271b3..e1ff090dd 100644 --- a/tests/bind/tnicerrorforsymchoice.nim +++ b/tests/bind/tnicerrorforsymchoice.nim @@ -1,17 +1,17 @@ discard """ line: 18 - errormsg: "type mismatch: got (proc (TScgi) | proc (PAsyncSocket, PStringTable, string){.gcsafe.})" + errormsg: "type mismatch: got (proc (TScgi) | proc (AsyncSocket, StringTableRef, string){.gcsafe.})" """ #bug #442 import scgi, sockets, asyncio, strtabs -proc handleSCGIRequest[TScgi: TScgiState | PAsyncScgiState](s: TScgi) = +proc handleSCGIRequest[TScgi: ScgiState | AsyncScgiState](s: TScgi) = discard -proc handleSCGIRequest(client: PAsyncSocket, headers: PStringTable, +proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef, input: string) = discard -proc test(handle: proc (client: PAsyncSocket, headers: PStringTable, +proc test(handle: proc (client: AsyncSocket, headers: StringTableRef, input: string), b: int) = discard diff --git a/tests/borrow/tborrow.nim b/tests/borrow/tborrow.nim index 8e6aeba74..d4df5f524 100644 --- a/tests/borrow/tborrow.nim +++ b/tests/borrow/tborrow.nim @@ -18,4 +18,4 @@ proc `++`(x, y: DF): DF {.borrow.} proc `$`(x: DI): string {.borrow.} proc `$`(x: DF): string {.borrow.} -echo 4544.DI ++ 343.di, " ", (4.5.df ++ 0.5.df).float == 5.0 +echo 4544.DI ++ 343.DI, " ", (4.5.DF ++ 0.5.DF).float == 5.0 diff --git a/tests/casestmt/tcasestm.nim b/tests/casestmt/tcasestm.nim index b033b98ec..a21b6be0d 100644 --- a/tests/casestmt/tcasestm.nim +++ b/tests/casestmt/tcasestm.nim @@ -5,7 +5,7 @@ discard """ # Test the case statement type - tenum = enum eA, eB, eC + Tenum = enum eA, eB, eC var x: string = "yyy" diff --git a/tests/ccgbugs/tccgen1.nim b/tests/ccgbugs/tccgen1.nim index 137dd545d..9234bbd6c 100644 --- a/tests/ccgbugs/tccgen1.nim +++ b/tests/ccgbugs/tccgen1.nim @@ -45,7 +45,7 @@ type PText* = ref Text Text = object of CharacterData - PComment* = ref comment + PComment* = ref Comment Comment = object of CharacterData PCDataSection* = ref CDataSection diff --git a/tests/ccgbugs/tcodegenbug1.nim b/tests/ccgbugs/tcodegenbug1.nim index 7d0fc4ad5..9b9771485 100644 --- a/tests/ccgbugs/tcodegenbug1.nim +++ b/tests/ccgbugs/tcodegenbug1.nim @@ -51,7 +51,7 @@ proc `$`*(status: TStatusEnum): string = return "unknown" proc makeCommitPath*(platform, hash: string): string = - return platform / "nimrod_" & hash.substr(0, 11) # 11 Chars. + return platform / "nim_" & hash.substr(0, 11) # 11 Chars. type TFlag = enum diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim index 764aaa97d..445a99b6d 100644 --- a/tests/closure/tclosure.nim +++ b/tests/closure/tclosure.nim @@ -36,7 +36,7 @@ myData.each do (x: int): type ITest = tuple[ - setter: proc(v: Int), + setter: proc(v: int), getter: proc(): int] proc getInterf(): ITest = diff --git a/tests/closure/tclosurebug2.nim b/tests/closure/tclosurebug2.nim index ec4f0045b..12e4e3509 100644 --- a/tests/closure/tclosurebug2.nim +++ b/tests/closure/tclosurebug2.nim @@ -38,17 +38,17 @@ template rawInsertImpl() {.dirty.} = data[h].val = val data[h].slot = seFilled -template AddImpl() {.dirty.} = - if mustRehash(len(t.data), t.counter): Enlarge(t) - RawInsert(t, t.data, key, val) +template addImpl() {.dirty.} = + if mustRehash(len(t.data), t.counter): enlarge(t) + rawInsert(t, t.data, key, val) inc(t.counter) -template PutImpl() {.dirty.} = - var index = RawGet(t, key) +template putImpl() {.dirty.} = + var index = rawGet(t, key) if index >= 0: t.data[index].val = val else: - AddImpl() + addImpl() proc len*[A, B](t: TOrderedTable[A, B]): int {.inline.} = ## returns the number of keys in `t`. @@ -89,7 +89,7 @@ iterator mvalues*[A, B](t: var TOrderedTable[A, B]): var B = forAllOrderedPairs: yield t.data[h].val -proc RawGet[A, B](t: TOrderedTable[A, B], key: A): int = +proc rawGet[A, B](t: TOrderedTable[A, B], key: A): int = rawGetImpl() proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B = @@ -97,21 +97,21 @@ proc `[]`*[A, B](t: TOrderedTable[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 index = rawGet(t, key) if index >= 0: result = t.data[index].val proc mget*[A, B](t: var TOrderedTable[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 index = rawGet(t, key) if index >= 0: result = t.data[index].val - else: raise newException(EInvalidKey, "key not found: " & $key) + else: raise newException(KeyError, "key not found: " & $key) proc hasKey*[A, B](t: TOrderedTable[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 -proc RawInsert[A, B](t: var TOrderedTable[A, B], +proc rawInsert[A, B](t: var TOrderedTable[A, B], data: var TOrderedKeyValuePairSeq[A, B], key: A, val: B) = rawInsertImpl() @@ -120,7 +120,7 @@ proc RawInsert[A, B](t: var TOrderedTable[A, B], if t.last >= 0: data[t.last].next = h t.last = h -proc Enlarge[A, B](t: var TOrderedTable[A, B]) = +proc enlarge[A, B](t: var TOrderedTable[A, B]) = var n: TOrderedKeyValuePairSeq[A, B] newSeq(n, len(t.data) * growthFactor) var h = t.first @@ -129,7 +129,7 @@ proc Enlarge[A, B](t: var TOrderedTable[A, B]) = 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) + rawInsert(t, n, t.data[h].key, t.data[h].val) h = nxt swap(t.data, n) @@ -139,7 +139,7 @@ proc `[]=`*[A, B](t: var TOrderedTable[A, B], key: A, val: B) = proc add*[A, B](t: var TOrderedTable[A, B], key: A, val: B) = ## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists. - AddImpl() + addImpl() proc initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] = ## creates a new ordered hash table that is empty. `initialSize` needs to be diff --git a/tests/concurrency/tnodeadlocks.nim b/tests/concurrency/tnodeadlocks.nim index d44196039..7a3eedbc2 100644 --- a/tests/concurrency/tnodeadlocks.nim +++ b/tests/concurrency/tnodeadlocks.nim @@ -1,6 +1,6 @@ discard """ outputsub: "101" - cmd: "nimrod $target --hints:on --threads:on $options $file" + cmd: "nim $target --hints:on --threads:on $options $file" """ import os, locks @@ -20,46 +20,46 @@ proc threadFunc(interval: tuple[a, b: int]) {.thread.} = when nodeadlocks: case i mod 6 of 0: - Acquire(L) # lock stdout - Acquire(M) - Acquire(N) + acquire(L) # lock stdout + acquire(M) + acquire(N) of 1: - Acquire(L) - Acquire(N) # lock stdout - Acquire(M) + acquire(L) + acquire(N) # lock stdout + acquire(M) of 2: - Acquire(M) - Acquire(L) - Acquire(N) + acquire(M) + acquire(L) + acquire(N) of 3: - Acquire(M) - Acquire(N) - Acquire(L) + acquire(M) + acquire(N) + acquire(L) of 4: - Acquire(N) - Acquire(M) - Acquire(L) + acquire(N) + acquire(M) + acquire(L) of 5: - Acquire(N) - Acquire(L) - Acquire(M) + acquire(N) + acquire(L) + acquire(M) else: assert false else: - Acquire(L) # lock stdout - Acquire(M) + acquire(L) # lock stdout + acquire(M) echo i os.sleep(10) when nodeadlocks: echo "deadlocks prevented: ", deadlocksPrevented when nodeadlocks: - Release(N) - Release(M) - Release(L) + release(N) + release(M) + release(L) -InitLock(L) -InitLock(M) -InitLock(N) +initLock(L) +initLock(M) +initLock(N) proc main = for i in 0..high(thr): diff --git a/tests/constr/tconstr1.nim b/tests/constr/tconstr1.nim index cb6594213..45e303554 100644 --- a/tests/constr/tconstr1.nim +++ b/tests/constr/tconstr1.nim @@ -10,7 +10,7 @@ type s: string, x, y: int, z: float, - chars: set[Char]] + chars: set[char]] proc testSem = var diff --git a/tests/destructor/tdictdestruct.nim b/tests/destructor/tdictdestruct.nim index b7043f7b7..17ded4853 100644 --- a/tests/destructor/tdictdestruct.nim +++ b/tests/destructor/tdictdestruct.nim @@ -11,7 +11,7 @@ proc fakeNew[T](x: var ref T, destroy: proc (a: ref T) {.nimcall.}) = proc destroyDict[TK, TV](a: PDict[TK, TV]) = return proc newDict[TK, TV](a: TK, b: TV): PDict[TK, TV] = - Fakenew(result, destroyDict[TK, TV]) + fakeNew(result, destroyDict[TK, TV]) # Problem: destroyDict is not instantiated when newDict is instantiated! diff --git a/tests/dll/client.nim b/tests/dll/client.nim index 45fa8f639..d535e8750 100644 --- a/tests/dll/client.nim +++ b/tests/dll/client.nim @@ -1,6 +1,6 @@ discard """ output: "Done" - cmd: "nimrod $target --debuginfo --hints:on --define:useNimRtl $options $file" + cmd: "nim $target --debuginfo --hints:on --define:useNimRtl $options $file" """ type diff --git a/tests/dll/server.nim b/tests/dll/server.nim index b2fac9ecc..df3223444 100644 --- a/tests/dll/server.nim +++ b/tests/dll/server.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nimrod $target --debuginfo --hints:on --define:useNimRtl --app:lib $options $file" + cmd: "nim $target --debuginfo --hints:on --define:useNimRtl --app:lib $options $file" """ type diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim index f73230ff9..e6d38cbc2 100644 --- a/tests/effects/teffects1.nim +++ b/tests/effects/teffects1.nim @@ -1,7 +1,7 @@ discard """ - line: 2136 + line: 2169 file: "system.nim" - errormsg: "can raise an unlisted exception: ref EIO" + errormsg: "can raise an unlisted exception: ref IOError" """ type @@ -9,13 +9,13 @@ type TObjB = object of TObj a, b, c: string - EIO2 = ref object of EIO + IO2Error = ref object of IOError proc forw: int {. .} -proc lier(): int {.raises: [EIO2].} = +proc lier(): int {.raises: [IO2Error].} = writeln stdout, "arg" proc forw: int = - raise newException(EIO, "arg") + raise newException(IOError, "arg") diff --git a/tests/effects/teffects2.nim b/tests/effects/teffects2.nim index 7e6b17c36..89ad16edc 100644 --- a/tests/effects/teffects2.nim +++ b/tests/effects/teffects2.nim @@ -1,6 +1,6 @@ discard """ line: 19 - errormsg: "can raise an unlisted exception: ref EIO" + errormsg: "can raise an unlisted exception: ref IOError" """ type @@ -8,13 +8,13 @@ type TObjB = object of TObj a, b, c: string - EIO2 = ref object of EIO + EIO2 = ref object of IOError proc forw: int {.raises: [].} -proc lier(): int {.raises: [EIO].} = +proc lier(): int {.raises: [IOError].} = writeln stdout, "arg" proc forw: int = - raise newException(EIO, "arg") + raise newException(IOError, "arg") diff --git a/tests/effects/tgcsafe.nim b/tests/effects/tgcsafe.nim index 87388238a..0d5109439 100644 --- a/tests/effects/tgcsafe.nim +++ b/tests/effects/tgcsafe.nim @@ -1,6 +1,7 @@ discard """ - line: 15 + line: 16 errormsg: "'mainUnsafe' is not GC-safe" + cmd: "nim $target --hints:on --threads:on $options $file" """ proc mymap(x: proc ()) = diff --git a/tests/exception/texcpt1.nim b/tests/exception/texcpt1.nim index ec74c9470..50a95eeec 100644 --- a/tests/exception/texcpt1.nim +++ b/tests/exception/texcpt1.nim @@ -2,8 +2,8 @@ discard """ outputsub: "-6" """ type - ESomething = object of E_Base - ESomeOtherErr = object of E_Base + ESomething = object of Exception + ESomeOtherErr = object of Exception proc genErrors(s: string) = if s == "error!": diff --git a/tests/exception/tnestedreturn.nim b/tests/exception/tnestedreturn.nim index b9f7843f6..591638f0e 100644 --- a/tests/exception/tnestedreturn.nim +++ b/tests/exception/tnestedreturn.nim @@ -10,8 +10,8 @@ proc test1() = finally: echo "A" try: - raise newException(EOS, "Problem") - except EOS: + raise newException(OSError, "Problem") + except OSError: return test1() @@ -23,7 +23,7 @@ proc test2() = try: return - except EOS: + except OSError: discard test2() @@ -31,8 +31,8 @@ test2() proc test3() = try: try: - raise newException(EOS, "Problem") - except EOS: + raise newException(OSError, "Problem") + except OSError: return finally: echo "C" diff --git a/tests/exception/tnestedreturn2.nim b/tests/exception/tnestedreturn2.nim index 14a2dab92..4bd2d535d 100644 --- a/tests/exception/tnestedreturn2.nim +++ b/tests/exception/tnestedreturn2.nim @@ -1,14 +1,14 @@ discard """ - file: "tnestedreturn.nim" - outputsub: "Error: unhandled exception: Problem [EOS]" + file: "tnestedreturn2.nim" + outputsub: "Error: unhandled exception: Problem [OSError]" exitcode: "1" """ proc test4() = try: try: - raise newException(EOS, "Problem") - except EOS: + raise newException(OSError, "Problem") + except OSError: return finally: discard @@ -17,4 +17,4 @@ proc test4() = # but could cause segmentation fault if # exceptions are not handled properly. test4() -raise newException(EOS, "Problem") +raise newException(OSError, "Problem") diff --git a/tests/exception/tunhandledexc.nim b/tests/exception/tunhandledexc.nim index f24881aef..aa9d61236 100644 --- a/tests/exception/tunhandledexc.nim +++ b/tests/exception/tunhandledexc.nim @@ -4,8 +4,8 @@ discard """ exitcode: "1" """ type - ESomething = object of E_Base - ESomeOtherErr = object of E_Base + ESomething = object of Exception + ESomeOtherErr = object of Exception proc genErrors(s: string) = if s == "error!": @@ -13,7 +13,7 @@ proc genErrors(s: string) = else: raise newException(EsomeotherErr, "bla") -when True: +when true: try: genErrors("errssor!") except ESomething: diff --git a/tests/exception/twrongexc.nim b/tests/exception/twrongexc.nim index 755f7d979..4e921b8a3 100644 --- a/tests/exception/twrongexc.nim +++ b/tests/exception/twrongexc.nim @@ -1,11 +1,11 @@ discard """ file: "twrongexc.nim" - outputsub: "Error: unhandled exception: [EInvalidValue]" + outputsub: "Error: unhandled exception: [ValueError]" exitcode: "1" """ try: - raise newException(EInvalidValue, "") -except EOverflow: + raise newException(ValueError, "") +except OverflowError: echo("Error caught") diff --git a/tests/float/tfloat1.nim b/tests/float/tfloat1.nim index f290fdb57..ed99260ea 100644 --- a/tests/float/tfloat1.nim +++ b/tests/float/tfloat1.nim @@ -1,6 +1,6 @@ discard """ file: "tfloat1.nim" - outputsub: "Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow]" + outputsub: "Error: unhandled exception: FPU operation caused an overflow [FloatOverflowError]" exitcode: "1" """ # Test new floating point exceptions @@ -10,6 +10,6 @@ discard """ var x = 0.8 var y = 0.0 -echo x / y #OUT Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow] +echo x / y #OUT Error: unhandled exception: FPU operation caused an overflow diff --git a/tests/float/tfloat2.nim b/tests/float/tfloat2.nim index 51883674f..b84120fba 100644 --- a/tests/float/tfloat2.nim +++ b/tests/float/tfloat2.nim @@ -1,6 +1,6 @@ discard """ file: "tfloat2.nim" - outputsub: "Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]" + outputsub: "Error: unhandled exception: FPU operation caused a NaN result [FloatInvalidOpError]" exitcode: "1" """ # Test new floating point exceptions @@ -10,6 +10,6 @@ discard """ var x = 0.0 var y = 0.0 -echo x / y #OUT Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp] +echo x / y #OUT Error: unhandled exception: FPU operation caused a NaN result diff --git a/tests/float/tfloat3.nim b/tests/float/tfloat3.nim index 4382dd3ed..a3f5a2fc7 100644 --- a/tests/float/tfloat3.nim +++ b/tests/float/tfloat3.nim @@ -1,6 +1,6 @@ discard """ file: "tfloat3.nim" - output: "Nimrod 3.4368930843, 0.3299290698 C double: 3.4368930843, 0.3299290698" + output: "Nim 3.4368930843, 0.3299290698 C double: 3.4368930843, 0.3299290698" """ import math, strutils @@ -13,11 +13,11 @@ void printFloats(void) { } """.} -proc c_printf(frmt: CString) {.importc: "printf", header: "<stdio.h>", varargs.} +proc c_printf(frmt: cstring) {.importc: "printf", header: "<stdio.h>", varargs.} proc printFloats {.importc, nodecl.} var x: float = 1.234567890123456789 -c_printf("Nimrod %.10f, %.10f ", exp(x), cos(x)) +c_printf("Nim %.10f, %.10f ", exp(x), cos(x)) printFloats() diff --git a/tests/gc/bintrees.nim b/tests/gc/bintrees.nim index 3f8acee1e..5b65bb437 100644 --- a/tests/gc/bintrees.nim +++ b/tests/gc/bintrees.nim @@ -1,4 +1,4 @@ -# -*- nimrod -*- +# -*- nim -*- import os, strutils diff --git a/tests/gc/closureleak.nim b/tests/gc/closureleak.nim index 669e05227..38ee1250a 100644 --- a/tests/gc/closureleak.nim +++ b/tests/gc/closureleak.nim @@ -29,5 +29,5 @@ for i in 0 .. <10: f.func = proc = echo f.id -gc_fullcollect() +GC_fullcollect() echo alive_foos.len <= 3 diff --git a/tests/generics/tcan_alias_generic.nim b/tests/generics/tcan_alias_generic.nim index e90bdc6d2..780a47841 100644 --- a/tests/generics/tcan_alias_generic.nim +++ b/tests/generics/tcan_alias_generic.nim @@ -1,5 +1,5 @@ ## -## can_alias_generic Nimrod Module +## can_alias_generic Nim Module ## ## Created by Eric Doughty-Papassideris on 2011-02-16. ## Copyright (c) 2011 FWA. All rights reserved. diff --git a/tests/generics/tcan_alias_specialised_generic.nim b/tests/generics/tcan_alias_specialised_generic.nim index 8d4a29abd..a737d3580 100644 --- a/tests/generics/tcan_alias_specialised_generic.nim +++ b/tests/generics/tcan_alias_specialised_generic.nim @@ -3,7 +3,7 @@ discard """ """ ## -## can_alias_specialised_generic Nimrod Module +## can_alias_specialised_generic Nim Module ## ## Created by Eric Doughty-Papassideris on 2011-02-16. ## Copyright (c) 2011 FWA. All rights reserved. diff --git a/tests/generics/tcan_inherit_generic.nim b/tests/generics/tcan_inherit_generic.nim index a6f4d946b..ce2b6452f 100644 --- a/tests/generics/tcan_inherit_generic.nim +++ b/tests/generics/tcan_inherit_generic.nim @@ -1,5 +1,5 @@ ## -## can_inherit_generic Nimrod Module +## can_inherit_generic Nim Module ## ## Created by Eric Doughty-Papassideris on 2011-02-16. ## Copyright (c) 2011 FWA. All rights reserved. diff --git a/tests/generics/tcan_specialise_generic.nim b/tests/generics/tcan_specialise_generic.nim index 64d5f56e3..c510910e8 100644 --- a/tests/generics/tcan_specialise_generic.nim +++ b/tests/generics/tcan_specialise_generic.nim @@ -1,5 +1,5 @@ ## -## can_specialise_generic Nimrod Module +## can_specialise_generic Nim Module ## ## Created by Eric Doughty-Papassideris on 2011-02-16. ## Copyright (c) 2011 FWA. All rights reserved. diff --git a/tests/generics/texplicitgeneric1.nim b/tests/generics/texplicitgeneric1.nim index 6cca71ac0..d54044368 100644 --- a/tests/generics/texplicitgeneric1.nim +++ b/tests/generics/texplicitgeneric1.nim @@ -18,7 +18,7 @@ proc newDict*[TKey, TValue](): PDict[TKey, TValue] = proc add*[TKey, TValue](d: PDict[TKey, TValue], k: TKey, v: TValue) = d.data.add((k, v)) -iterator items*[Tkey, tValue](d: PDict[TKey, TValue]): tuple[k: TKey, +iterator items*[Tkey, TValue](d: PDict[TKey, TValue]): tuple[k: TKey, v: TValue] = for k, v in items(d.data): yield (k, v) diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim index 9292b729f..45450ccca 100644 --- a/tests/generics/tgeneric0.nim +++ b/tests/generics/tgeneric0.nim @@ -1,9 +1,9 @@ import tables type - TX = TTable[string, int] + TX = Table[string, int] -proc foo(models: seq[TTable[string, float]]): seq[float] = +proc foo(models: seq[Table[string, float]]): seq[float] = result = @[] for model in models.items: result.add model["foobar"] @@ -16,4 +16,12 @@ proc foo[T](p: TType[T, range[0..1]]) = proc foo[T](p: TType[T, range[0..2]]) = echo "bar" +#bug #1366 + +proc reversed(x) = + for i in countdown(x.low, x.high): + echo i + +reversed(@[-19, 7, -4, 6]) + diff --git a/tests/generics/tgeneric2.nim b/tests/generics/tgeneric2.nim index 56803017a..21eb4693e 100644 --- a/tests/generics/tgeneric2.nim +++ b/tests/generics/tgeneric2.nim @@ -1,7 +1,7 @@ import tables type - TX = TTable[string, int] + TX = Table[string, int] proc foo(models: seq[TX]): seq[int] = result = @[] @@ -9,7 +9,7 @@ proc foo(models: seq[TX]): seq[int] = result.add model["foobar"] type - obj = object - field: TTable[string, string] + Obj = object + field: Table[string, string] var t: Obj discard initTable[type(t.field), string]() diff --git a/tests/generics/tgeneric3.nim b/tests/generics/tgeneric3.nim index 963d0ccfb..6fb929efb 100644 --- a/tests/generics/tgeneric3.nim +++ b/tests/generics/tgeneric3.nim @@ -7,17 +7,17 @@ type value: D node: PNode[T,D] when not (D is string): - val_set: Bool + val_set: bool TItems[T,D] = seq[ref TItem[T,D]] TNode {.acyclic, pure, final, shallow.} [T,D] = object slots: TItems[T,D] left: PNode[T,D] - count: Int32 + count: int32 RPath[T,D] = tuple[ - Xi: Int, + Xi: int, Nd: PNode[T,D] ] const @@ -29,41 +29,41 @@ const cLenMax = 128 cCenter = cLenMax div 2 -proc len[T,D] (n:PNode[T,D]): Int {.inline.} = - return n.Count +proc len[T,D] (n:PNode[T,D]): int {.inline.} = + return n.count -proc clean[T: TOrdinal|TNumber](o: var T) {.inline.} = discard +proc clean[T: SomeOrdinal|SomeNumber](o: var T) {.inline.} = discard proc clean[T: string|seq](o: var T) {.inline.} = o = nil proc clean[T,D] (o: ref TItem[T,D]) {.inline.} = when (D is string) : - o.Value = nil + o.value = nil else : o.val_set = false -proc isClean[T,D] (it: ref TItem[T,D]): Bool {.inline.} = +proc isClean[T,D] (it: ref TItem[T,D]): bool {.inline.} = when (D is string) : - return it.Value == nil + return it.value == nil else : return not it.val_set -proc isClean[T,D] (n: PNode[T,D], x: Int): Bool {.inline.} = - when (D is string) : - return n.slots[x].Value == nil - else : +proc isClean[T,D](n: PNode[T,D], x: int): bool {.inline.} = + when (D is string): + return n.slots[x].value == nil + else: return not n.slots[x].val_set -proc setItem[T,D] (AKey: T, AValue: D, ANode: PNode[T,D]): ref TItem[T,D] {.inline.} = - new(Result) - Result.Key = AKey - Result.Value = AValue - Result.Node = ANode +proc setItem[T,D](Akey: T, Avalue: D, ANode: PNode[T,D]): ref TItem[T,D] {.inline.} = + new(result) + result.key = Akey + result.value = Avalue + result.node = ANode when not (D is string) : - Result.val_set = true + result.val_set = true -proc cmp[T:Int8|Int16|Int32|Int64|Int] (a,b: T): T {.inline.} = +proc cmp[T:int8|int16|int32|int64|int] (a,b: T): T {.inline.} = return a-b template binSearchImpl *(docmp: expr) {.immediate.} = @@ -76,41 +76,41 @@ template binSearchImpl *(docmp: expr) {.immediate.} = if SW < 0: result = I + 1 else: H = I - 1 - if SW == 0 : bFound = True + if SW == 0 : bFound = true if bFound: inc(result) else: result = - result -proc bSearch[T,D] (haystack: PNode[T,D], needle:T): Int {.inline.} = +proc bSearch[T,D] (haystack: PNode[T,D], needle:T): int {.inline.} = binSearchImpl(haystack.slots[I].key.cmp(needle)) -proc DeleteItem[T,D] (n: PNode[T,D], x: Int): PNode[T,D] {.inline.} = +proc DeleteItem[T,D] (n: PNode[T,D], x: int): PNode[T,D] {.inline.} = var w = n.slots[x] - if w.Node != nil : + if w.node != nil : clean(w) return n - dec(n.Count) - if n.Count > 0 : - for i in countup(x, n.Count -1) : n.slots[i] = n.slots[i + 1] - n.slots[n.Count] = nil - case n.Count + dec(n.count) + if n.count > 0 : + for i in countup(x, n.count -1) : n.slots[i] = n.slots[i + 1] + n.slots[n.count] = nil + case n.count of cLen1 : setLen(n.slots, cLen1) of cLen2 : setLen(n.slots, cLen2) of cLen3 : setLen(n.slots, cLen3) of cLenCenter : setLen(n.slots, cLenCenter) of cLen4 : setLen(n.slots, cLen4) else: discard - Result = n + result = n else : - Result = n.Left + result = n.left n.slots = nil - n.Left = nil + n.left = nil -proc InternalDelete[T,D] (ANode: PNode[T,D], key: T, AValue: var D): PNode[T,D] = +proc internalDelete[T,D] (ANode: PNode[T,D], key: T, Avalue: var D): PNode[T,D] = var Path: array[0..20, RPath[T,D]] var n = ANode - Result = n - clean(AValue) + result = n + clean(Avalue) var h = 0 while n != nil: var x = bSearch(n, key) @@ -119,17 +119,17 @@ proc InternalDelete[T,D] (ANode: PNode[T,D], key: T, AValue: var D): PNode[T,D] Path[h].Xi = - x inc(h) if x == 0 : - n = n.Left + n = n.left else : x = (-x) -1 - if x < n.Count : - n = n.slots[x].Node + if x < n.count : + n = n.slots[x].node else : n = nil else : dec(x) if isClean(n, x) : return - AValue = n.slots[x].Value + Avalue = n.slots[x].value var n2 = DeleteItem(n, x) dec(h) while (n2 != n) and (h >=0) : @@ -139,30 +139,30 @@ proc InternalDelete[T,D] (ANode: PNode[T,D], key: T, AValue: var D): PNode[T,D] if x >= 0 : if (n == nil) and isClean(w.Nd, x) : n = w.Nd - n.slots[x].Node = nil + n.slots[x].node = nil n2 = DeleteItem(n, x) else : - w.Nd.slots[x].Node = n + w.Nd.slots[x].node = n return else : - w.Nd.Left = n + w.Nd.left = n return dec(h) if h < 0: - Result = n2 + result = n2 return -proc InternalFind[T,D] (n: PNode[T,D], key: T): ref TItem[T,D] {.inline.} = +proc internalFind[T,D] (n: PNode[T,D], key: T): ref TItem[T,D] {.inline.} = var wn = n while wn != nil : var x = bSearch(wn, key) if x <= 0 : if x == 0 : - wn = wn.Left + wn = wn.left else : x = (-x) -1 - if x < wn.Count : - wn = wn.slots[x].Node + if x < wn.count : + wn = wn.slots[x].node else : return nil @@ -171,32 +171,32 @@ proc InternalFind[T,D] (n: PNode[T,D], key: T): ref TItem[T,D] {.inline.} = return nil proc traceTree[T,D](root: PNode[T,D]) = - proc traceX(x: Int) = + proc traceX(x: int) = write stdout, "(" write stdout, x write stdout, ") " proc traceEl(el: ref TItem[T,D]) = write stdout, " key: " - write stdout, el.Key + write stdout, el.key write stdout, " value: " - write stdout, el.Value + write stdout, el.value proc traceln(space: string) = writeln stdout, "" write stdout, space - proc doTrace(n: PNode[T,D], level: Int) = + proc doTrace(n: PNode[T,D], level: int) = var space = repeatChar(2 * level) traceln(space) write stdout, "node: " if n == nil: writeln stdout, "is empty" return - write stdout, n.Count + write stdout, n.count write stdout, " elements: " - if n.Left != nil: + if n.left != nil: traceln(space) write stdout, "left: " doTrace(n.left, level +1) @@ -204,188 +204,188 @@ proc traceTree[T,D](root: PNode[T,D]) = if el != nil and not isClean(el): traceln(space) traceX(i) - if i >= n.Count: + if i >= n.count: write stdout, "error " else: traceEl(el) - if el.Node != nil: doTrace(el.Node, level +1) + if el.node != nil: doTrace(el.node, level +1) else : write stdout, " empty " - elif i < n.Count : + elif i < n.count : traceln(space) traceX(i) write stdout, "clean: " when T is string : - if el.Key != nil: write stdout, el.Key - else : write stdout, el.Key - if el.Node != nil: doTrace(el.Node, level +1) + if el.key != nil: write stdout, el.key + else : write stdout, el.key + if el.node != nil: doTrace(el.node, level +1) else : write stdout, " empty " writeln stdout,"" doTrace(root, 0) -proc InsertItem[T,D](APath: RPath[T,D], ANode:PNode[T,D], AKey: T, AValue: D) = +proc InsertItem[T,D](APath: RPath[T,D], ANode:PNode[T,D], Akey: T, Avalue: D) = var x = - APath.Xi - inc(APath.Nd.Count) - case APath.Nd.Count + inc(APath.Nd.count) + case APath.Nd.count of cLen1: setLen(APath.Nd.slots, cLen2) of cLen2: setLen(APath.Nd.slots, cLen3) of cLen3: setLen(APath.Nd.slots, cLenCenter) of cLenCenter: setLen(APath.Nd.slots, cLen4) of cLen4: setLen(APath.Nd.slots, cLenMax) else: discard - for i in countdown(APath.Nd.Count.int - 1, x + 1): shallowCopy(APath.Nd.slots[i], APath.Nd.slots[i - 1]) - APath.Nd.slots[x] = setItem(AKey, AValue, ANode) + for i in countdown(APath.Nd.count.int - 1, x + 1): shallowCopy(APath.Nd.slots[i], APath.Nd.slots[i - 1]) + APath.Nd.slots[x] = setItem(Akey, Avalue, ANode) -proc SplitPage[T,D](n, left: PNode[T,D], xi: Int, AKey:var T, AValue:var D): PNode[T,D] = - var x = -Xi +proc SplitPage[T,D](n, left: PNode[T,D], xi: int, Akey:var T, Avalue:var D): PNode[T,D] = + var x = -xi var it1: TItems[T,D] it1.newSeq(cLenCenter) - new(Result) - Result.slots.newSeq(cLenCenter) - Result.Count = cCenter + new(result) + result.slots.newSeq(cLenCenter) + result.count = cCenter if x == cCenter: for i in 0..cCenter -1: shallowCopy(it1[i], left.slots[i]) - for i in 0..cCenter -1: shallowCopy(Result.slots[i], left.slots[cCenter + i]) - Result.Left = n + for i in 0..cCenter -1: shallowCopy(result.slots[i], left.slots[cCenter + i]) + result.left = n else : if x < cCenter : for i in 0..x-1: shallowCopy(it1[i], left.slots[i]) - it1[x] = setItem(AKey, AValue, n) + it1[x] = setItem(Akey, Avalue, n) for i in x+1 .. cCenter -1: shallowCopy(it1[i], left.slots[i-1]) var w = left.slots[cCenter -1] - AKey = w.Key - AValue = w.Value - Result.Left = w.Node - for i in 0..cCenter -1: shallowCopy(Result.slots[i], left.slots[cCenter + i]) + Akey = w.key + Avalue = w.value + result.left = w.node + for i in 0..cCenter -1: shallowCopy(result.slots[i], left.slots[cCenter + i]) else : for i in 0..cCenter -1: shallowCopy(it1[i], left.slots[i]) x = x - (cCenter + 1) - for i in 0..x-1: shallowCopy(Result.slots[i], left.slots[cCenter + i + 1]) - Result.slots[x] = setItem(AKey, AValue, n) - for i in x+1 .. cCenter -1: shallowCopy(Result.slots[i], left.slots[cCenter + i]) + for i in 0..x-1: shallowCopy(result.slots[i], left.slots[cCenter + i + 1]) + result.slots[x] = setItem(Akey, Avalue, n) + for i in x+1 .. cCenter -1: shallowCopy(result.slots[i], left.slots[cCenter + i]) var w = left.slots[cCenter] - AKey = w.Key - AValue = w.Value - Result.Left = w.Node - left.Count = cCenter + Akey = w.key + Avalue = w.value + result.left = w.node + left.count = cCenter shallowCopy(left.slots, it1) -proc InternalPut[T,D](ANode: ref TNode[T,D], AKey: T, AValue: D, OldValue: var D): ref TNode[T,D] = - var h: Int +proc internalPut[T,D](ANode: ref TNode[T,D], Akey: T, Avalue: D, Oldvalue: var D): ref TNode[T,D] = + var h: int var Path: array[0..30, RPath[T,D]] var left: PNode[T,D] var n = ANode - Result = ANode + result = ANode h = 0 while n != nil: - var x = bSearch[T,D](n, AKey) + var x = bSearch[T,D](n, Akey) if x <= 0 : Path[h].Nd = n Path[h].Xi = x inc(h) if x == 0 : - n = n.Left + n = n.left else : x = (-x) -1 - if x < n.Count : - n = n.slots[x].Node + if x < n.count : + n = n.slots[x].node else : n = nil else : var w = n.slots[x - 1] - OldValue = w.Value - w.Value = AValue + Oldvalue = w.value + w.value = Avalue return dec(h) left = nil - var lKey = AKey - var lValue = AValue + var lkey = Akey + var lvalue = Avalue while h >= 0 : - if Path[h].Nd.Count < cLenMax : - InsertItem(Path[h], n, lKey, lValue) + if Path[h].Nd.count < cLenMax : + InsertItem(Path[h], n, lkey, lvalue) return else : left = Path[h].Nd - n = SplitPage(n, left, Path[h].Xi, lKey, lValue) + n = SplitPage(n, left, Path[h].Xi, lkey, lvalue) dec(h) - new(Result) - Result.slots.newSeq(cLen1) - Result.Count = 1 - Result.Left = left - Result.slots[0] = setItem(lKey, lValue, n) + new(result) + result.slots.newSeq(cLen1) + result.count = 1 + result.left = left + result.slots[0] = setItem(lkey, lvalue, n) proc CleanTree[T,D](n: PNode[T,D]): PNode[T,D] = - if n.Left != nil : - n.Left = CleanTree(n.Left) - for i in 0 .. n.Count - 1 : + if n.left != nil : + n.left = CleanTree(n.left) + for i in 0 .. n.count - 1 : var w = n.slots[i] - if w.Node != nil : - w.Node = CleanTree(w.Node) - clean(w.Value) - clean(w.Key) + if w.node != nil : + w.node = CleanTree(w.node) + clean(w.value) + clean(w.key) n.slots = nil return nil proc VisitAllNodes[T,D](n: PNode[T,D], visit: proc(n: PNode[T,D]): PNode[T,D] {.closure.} ): PNode[T,D] = if n != nil : - if n.Left != nil : - n.Left = VisitAllNodes(n.Left, visit) - for i in 0 .. n.Count - 1 : + if n.left != nil : + n.left = VisitAllNodes(n.left, visit) + for i in 0 .. n.count - 1 : var w = n.slots[i] - if w.Node != nil : - w.Node = VisitAllNodes(w.Node, visit) + if w.node != nil : + w.node = VisitAllNodes(w.node, visit) return visit(n) return nil proc VisitAllNodes[T,D](n: PNode[T,D], visit: proc(n: PNode[T,D]) {.closure.} ) = if n != nil: - if n.Left != nil : - VisitAllNodes(n.Left, visit) - for i in 0 .. n.Count - 1 : + if n.left != nil : + VisitAllNodes(n.left, visit) + for i in 0 .. n.count - 1 : var w = n.slots[i] - if w.Node != nil : - VisitAllNodes(w.Node, visit) + if w.node != nil : + VisitAllNodes(w.node, visit) visit(n) -proc VisitAll[T,D](n: PNode[T,D], visit: proc(AKey: T, AValue: D) {.closure.} ) = +proc VisitAll[T,D](n: PNode[T,D], visit: proc(Akey: T, Avalue: D) {.closure.} ) = if n != nil: - if n.Left != nil : - VisitAll(n.Left, visit) - for i in 0 .. n.Count - 1 : + if n.left != nil : + VisitAll(n.left, visit) + for i in 0 .. n.count - 1 : var w = n.slots[i] if not w.isClean : - visit(w.Key, w.Value) - if w.Node != nil : - VisitAll(w.Node, visit) + visit(w.key, w.value) + if w.node != nil : + VisitAll(w.node, visit) -proc VisitAll[T,D](n: PNode[T,D], visit: proc(AKey: T, AValue: var D):Bool {.closure.} ): PNode[T,D] = +proc VisitAll[T,D](n: PNode[T,D], visit: proc(Akey: T, Avalue: var D):bool {.closure.} ): PNode[T,D] = if n != nil: - var n1 = n.Left + var n1 = n.left if n1 != nil : var n2 = VisitAll(n1, visit) if n1 != n2 : - n.Left = n2 + n.left = n2 var i = 0 - while i < n.Count : + while i < n.count : var w = n.slots[i] if not w.isClean : - if visit(w.Key, w.Value) : - Result = DeleteItem(n, i) - if Result == nil : return + if visit(w.key, w.value) : + result = DeleteItem(n, i) + if result == nil : return dec(i) - n1 = w.Node + n1 = w.node if n1 != nil : var n2 = VisitAll(n1, visit) if n1 != n2 : - w.Node = n2 + w.node = n2 inc(i) return n @@ -396,20 +396,20 @@ iterator keys* [T,D] (n: PNode[T,D]): T = var nd = n var i = -1 while true : - if i < nd.Count : + if i < nd.count : Path[level].Nd = nd Path[level].Xi = i if i < 0 : - if nd.Left != nil : - nd = nd.Left + if nd.left != nil : + nd = nd.left inc(level) else : inc(i) else : var w = nd.slots[i] if not w.isClean() : - yield w.Key - if w.Node != nil : - nd = w.Node + yield w.key + if w.node != nil : + nd = w.node i = -1 inc(level) else : inc(i) @@ -424,22 +424,22 @@ iterator keys* [T,D] (n: PNode[T,D]): T = when isMainModule: proc test() = - var oldValue: Int - var root = InternalPut[int, int](nil, 312, 312, oldValue) - var someOtherRoot = InternalPut[string, int](nil, "312", 312, oldValue) - var it1 = InternalFind(root, 312) - echo it1.Value + var oldvalue: int + var root = internalPut[int, int](nil, 312, 312, oldvalue) + var someOtherRoot = internalPut[string, int](nil, "312", 312, oldvalue) + var it1 = internalFind(root, 312) + echo it1.value for i in 1..1_000_000: - root = InternalPut(root, i, i, oldValue) + root = internalPut(root, i, i, oldvalue) var cnt = 0 - oldValue = -1 + oldvalue = -1 when true : # code compiles, when this or the other when is switched to false for k in root.keys : - if k <= oldValue : + if k <= oldvalue : echo k - oldValue = k + oldvalue = k inc(cnt) echo cnt when true : @@ -450,21 +450,21 @@ when isMainModule: root = VisitAll(root, proc(key: int, value: var int): bool = return key mod 2 == 0 ) cnt = 0 - oldValue = -1 + oldvalue = -1 VisitAll(root, proc(key: int, value: int) {.closure.} = - if key <= oldValue : + if key <= oldvalue : echo key - oldValue = key + oldvalue = key inc(cnt) ) echo cnt root = VisitAll(root, proc(key: int, value: var int): bool = return key mod 2 != 0 ) cnt = 0 - oldValue = -1 + oldvalue = -1 VisitAll(root, proc(key: int, value: int) {.closure.} = - if key <= oldValue : + if key <= oldvalue : echo "error ", key - oldValue = key + oldvalue = key inc(cnt) ) echo cnt #traceTree(root) diff --git a/tests/generics/tgenericprocvar.nim b/tests/generics/tgenericprocvar.nim index 1eba81fec..dca9c8538 100644 --- a/tests/generics/tgenericprocvar.nim +++ b/tests/generics/tgenericprocvar.nim @@ -25,7 +25,7 @@ proc filter[T,D](data: seq[T], env:D, pred: TFilterProc[T,D]): seq[T] = for e in data: if pred(e, env): result.add(e) -proc predTest(item: int, value: int): Bool = +proc predTest(item: int, value: int): bool = return item <= value proc test(data: seq[int], value: int): seq[int] = diff --git a/tests/generics/tgenericvariant.nim b/tests/generics/tgenericvariant.nim index 51d01355a..0150cda8d 100644 --- a/tests/generics/tgenericvariant.nim +++ b/tests/generics/tgenericvariant.nim @@ -1,15 +1,15 @@ type TMaybe[T] = object - case empty: Bool - of False: value: T + case empty: bool + of false: value: T else: nil proc Just*[T](val: T): TMaybe[T] = - result.empty = False + result.empty = false result.value = val proc Nothing[T](): TMaybe[T] = - result.empty = True + result.empty = true proc safeReadLine(): TMaybe[string] = var r = stdin.readLine() diff --git a/tests/generics/tinferredgenericprocs.nim b/tests/generics/tinferredgenericprocs.nim index ac445fd32..12adfe965 100644 --- a/tests/generics/tinferredgenericprocs.nim +++ b/tests/generics/tinferredgenericprocs.nim @@ -5,7 +5,7 @@ discard """ 3''' """ -# https://github.com/Araq/Nimrod/issues/797 +# https://github.com/Araq/Nim/issues/797 proc foo[T](s:T):string = $s type IntStringProc = proc(x: int): string diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim index e1bc43ce3..bbfca7e3c 100644 --- a/tests/generics/tmetafield.nim +++ b/tests/generics/tmetafield.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nimrod check $options $file" + cmd: "nim check $options $file" errormsg: "'proc' is not a concrete type" errormsg: "'Foo' is not a concrete type." errormsg: "invalid type: 'TBaseMed'" diff --git a/tests/generics/tspecialised_is_equivalent.nim b/tests/generics/tspecialised_is_equivalent.nim index 60b976e90..ace562862 100644 --- a/tests/generics/tspecialised_is_equivalent.nim +++ b/tests/generics/tspecialised_is_equivalent.nim @@ -1,5 +1,5 @@ ## -## specialised_is_equivalent Nimrod Module +## specialised_is_equivalent Nim Module ## ## Created by Eric Doughty-Papassideris on 2011-02-16. ## Copyright (c) 2011 FWA. All rights reserved. diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim index 7109bba18..5887f7db3 100644 --- a/tests/generics/tthread_generic.nim +++ b/tests/generics/tthread_generic.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nimrod $target --hints:on --threads:on $options $file" + cmd: "nim $target --hints:on --threads:on $options $file" """ type diff --git a/tests/iter/titer2.nim b/tests/iter/titer2.nim index 71c7327a7..5c407ebe4 100644 --- a/tests/iter/titer2.nim +++ b/tests/iter/titer2.nim @@ -1,6 +1,6 @@ discard """ output: '''true''' - cmd: "nimrod $target --gc:none --hints:on --warnings:off $options $file" + cmd: "nim $target --gc:none --hints:on --warnings:off $options $file" """ import hashes @@ -44,8 +44,8 @@ block Test1: # a non-generic iterator! var t = initTable[int, string]() - for k, v in t.pairs: nil - for k, v in t.pairs: nil + for k, v in t.pairs: discard + for k, v in t.pairs: discard echo "true" diff --git a/tests/iter/titer6.nim b/tests/iter/titer6.nim index dceace0e0..2abfa0860 100644 --- a/tests/iter/titer6.nim +++ b/tests/iter/titer6.nim @@ -21,13 +21,13 @@ iterator tokenize2(s: string, seps: set[char] = Whitespace): tuple[ yield (substr(s, i, j-1), false) i = j -for word, isSep in tokenize2("ta da", whiteSpace): +for word, isSep in tokenize2("ta da", WhiteSpace): var titer2TestVar = 0 stdout.write(titer2TestVar) proc wordWrap2(s: string, maxLineWidth = 80, splitLongWords = true, - seps: set[char] = whitespace, + seps: set[char] = Whitespace, newLine = "\n"): string = result = "" for word, isSep in tokenize2(s, seps): diff --git a/tests/iter/titer8.nim b/tests/iter/titer8.nim index af0e643f1..3bc01122f 100644 --- a/tests/iter/titer8.nim +++ b/tests/iter/titer8.nim @@ -47,7 +47,7 @@ iterator count3(): int {.closure.} = yield 2 yield 3 -for word, isSep in tokenize2("ta da", whiteSpace): +for word, isSep in tokenize2("ta da", WhiteSpace): if not isSep: stdout.write(word) echo "" @@ -56,7 +56,7 @@ proc inProc() = for c in count3(): echo c - for word, isSep in tokenize2("ta da", whiteSpace): + for word, isSep in tokenize2("ta da", WhiteSpace): stdout.write(word) for c in count3(): diff --git a/tests/js.nim b/tests/js.nim index becc17834..e5e432366 100644 --- a/tests/js.nim +++ b/tests/js.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nimrod js --hints:on $options $file" + cmd: "nim js --hints:on $options $file" """ # This file tests the JavaScript generator diff --git a/tests/let/tlet.nim b/tests/let/tlet.nim index 3d36432fb..6703ba254 100644 --- a/tests/let/tlet.nim +++ b/tests/let/tlet.nim @@ -3,9 +3,9 @@ discard """ errormsg: "'name' cannot be assigned to" """ -Echo("What's your name? ") +echo("What's your name? ") let name = readLine(stdin) while name == "": - Echo("Please tell me your name: ") + echo("Please tell me your name: ") name = readLine(stdin) diff --git a/tests/lookups/tkoeniglookup.nim b/tests/lookups/tkoeniglookup.nim index e6f5c0112..6c42798ae 100644 --- a/tests/lookups/tkoeniglookup.nim +++ b/tests/lookups/tkoeniglookup.nim @@ -2,7 +2,7 @@ discard """ output: '''x: 0 y: 0''' """ -proc ToString*[T](x: T): string = return $x +proc toString*[T](x: T): string = return $x type diff --git a/tests/macros/tdebugstmt.nim b/tests/macros/tdebugstmt.nim index 865dc436a..00c55ccd8 100644 --- a/tests/macros/tdebugstmt.nim +++ b/tests/macros/tdebugstmt.nim @@ -7,7 +7,7 @@ x: some string''' import macros macro debug(n: varargs[expr]): stmt = - # `n` is a Nimrod AST that contains the whole macro invocation + # `n` is a Nim AST that contains the whole macro invocation # this macro returns a list of statements: result = newNimNode(nnkStmtList, n) # iterate over any argument that is passed to this macro: diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim index 6f4fb650e..fec00dbf8 100644 --- a/tests/manyloc/argument_parser/argument_parser.nim +++ b/tests/manyloc/argument_parser/argument_parser.nim @@ -1,7 +1,7 @@ ## Command line parsing module for Nimrod. ## -## `Nimrod <http://nimrod-code.org>`_ provides the `parseopt module -## <http://nimrod-code.org/parseopt.html>`_ to parse options from the +## `Nim <http://nim-code.org>`_ provides the `parseopt module +## <http://nim-code.org/parseopt.html>`_ to parse options from the ## commandline. This module tries to provide functionality to prevent you from ## writing commandline parsing and let you concentrate on providing the best ## possible experience for your users. @@ -76,14 +76,14 @@ type case kind*: Tparam_kind of PK_EMPTY: nil of PK_INT: int_val*: int - of PK_BIGGEST_INT: big_int_val*: biggestInt + of PK_BIGGEST_INT: big_int_val*: BiggestInt of PK_FLOAT: float_val*: float - of PK_BIGGEST_FLOAT: big_float_val*: biggestFloat + of PK_BIGGEST_FLOAT: big_float_val*: BiggestFloat of PK_STRING: str_val*: string of PK_BOOL: bool_val*: bool of PK_HELP: nil - Tcommandline_results* = object of TObject ## \ + Tcommandline_results* = object of RootObj ## \ ## Contains the results of the parsing. ## ## Usually this is the result of the parse() call, but you can inherit from @@ -97,7 +97,7 @@ type ## the first name variant for all options to avoid you repeating the test ## with different keys. positional_parameters*: seq[Tparsed_parameter] - options*: TOrderedTable[string, Tparsed_parameter] + options*: OrderedTable[string, Tparsed_parameter] # - Tparam_kind procs @@ -169,7 +169,7 @@ template new_parsed_parameter*(tkind: Tparam_kind, expr): Tparsed_parameter = ## assign the variable to, and thus you reduce code clutter and may use this ## to initialise single assignments variables in `let` blocks. Example: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## let ## parsed_param1 = new_parsed_parameter(PK_FLOAT, 3.41) ## parsed_param2 = new_parsed_parameter(PK_BIGGEST_INT, 2358123 * 23123) @@ -193,7 +193,7 @@ template new_parsed_parameter*(tkind: Tparam_kind, expr): Tparsed_parameter = proc init*(param: var Tcommandline_results; positional_parameters: seq[Tparsed_parameter] = @[]; - options: TOrderedTable[string, Tparsed_parameter] = + options: OrderedTable[string, Tparsed_parameter] = initOrderedTable[string, Tparsed_parameter](4)) = ## Initialization helper with default parameters. param.positional_parameters = positional_parameters @@ -231,12 +231,12 @@ template run_custom_proc(parsed_parameter: Tparsed_parameter, ## Pass in the string of the parameter triggering the call. If the if not custom_validator.isNil: except: - raise_or_quit(EInvalidValue, ("Couldn't run custom proc for " & + raise_or_quit(ValueError, ("Couldn't run custom proc for " & "parameter $1:\n$2" % [escape(parameter), getCurrentExceptionMsg()])) let message = custom_validator(parameter, parsed_parameter) if not message.isNil and message.len > 0: - raise_or_quit(EInvalidValue, ("Failed to validate value for " & + raise_or_quit(ValueError, ("Failed to validate value for " & "parameter $1:\n$2" % [escape(parameter), message])) @@ -246,50 +246,50 @@ proc parse_parameter(quit_on_failure: bool, param, value: string, ## ## Pass the parameter string which requires a value and the text the user ## passed in for it. It will be parsed according to the param_kind. This proc - ## will raise (EInvalidValue, EOverflow) if something can't be parsed. + ## will raise (ValueError, EOverflow) if something can't be parsed. result.kind = param_kind case param_kind: of PK_INT: try: result.int_val = value.parseInt - except EOverflow: - raise_or_quit(EOverflow, ("parameter $1 requires an " & + except OverflowError: + raise_or_quit(OverflowError, ("parameter $1 requires an " & "integer, but $2 is too large to fit into one") % [param, escape(value)]) - except EInvalidValue: - raise_or_quit(EInvalidValue, ("parameter $1 requires an " & + except ValueError: + raise_or_quit(ValueError, ("parameter $1 requires an " & "integer, but $2 can't be parsed into one") % [param, escape(value)]) of PK_STRING: result.str_val = value of PK_FLOAT: try: result.float_val = value.parseFloat - except EInvalidValue: - raise_or_quit(EInvalidValue, ("parameter $1 requires a " & + except ValueError: + raise_or_quit(ValueError, ("parameter $1 requires a " & "float, but $2 can't be parsed into one") % [param, escape(value)]) of PK_BOOL: try: result.bool_val = value.parseBool - except EInvalidValue: - raise_or_quit(EInvalidValue, ("parameter $1 requires a " & + except ValueError: + raise_or_quit(ValueError, ("parameter $1 requires a " & "boolean, but $2 can't be parsed into one. Valid values are: " & "y, yes, true, 1, on, n, no, false, 0, off") % [param, escape(value)]) of PK_BIGGEST_INT: try: let parsed_len = parseBiggestInt(value, result.big_int_val) if value.len != parsed_len or parsed_len < 1: - raise_or_quit(EInvalidValue, ("parameter $1 requires an " & + raise_or_quit(ValueError, ("parameter $1 requires an " & "integer, but $2 can't be parsed completely into one") % [ param, escape(value)]) - except EInvalidValue: - raise_or_quit(EInvalidValue, ("parameter $1 requires an " & + except ValueError: + raise_or_quit(ValueError, ("parameter $1 requires an " & "integer, but $2 can't be parsed into one") % [param, escape(value)]) of PK_BIGGEST_FLOAT: try: let parsed_len = parseBiggestFloat(value, result.big_float_val) if value.len != parsed_len or parsed_len < 1: - raise_or_quit(EInvalidValue, ("parameter $1 requires a " & + raise_or_quit(ValueError, ("parameter $1 requires a " & "float, but $2 can't be parsed completely into one") % [ param, escape(value)]) - except EInvalidValue: - raise_or_quit(EInvalidValue, ("parameter $1 requires a " & + except ValueError: + raise_or_quit(ValueError, ("parameter $1 requires a " & "float, but $2 can't be parsed into one") % [param, escape(value)]) of PK_EMPTY: discard @@ -298,15 +298,15 @@ proc parse_parameter(quit_on_failure: bool, param, value: string, template build_specification_lookup(): - TOrderedTable[string, ptr Tparameter_specification] = + OrderedTable[string, ptr Tparameter_specification] = ## Returns the table used to keep pointers to all of the specifications. - var result {.gensym.}: TOrderedTable[string, ptr Tparameter_specification] + var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification] result = initOrderedTable[string, ptr Tparameter_specification]( nextPowerOfTwo(expected.len)) for i in 0..expected.len-1: for param_to_detect in expected[i].names: if result.hasKey(param_to_detect): - raise_or_quit(EInvalidKey, + raise_or_quit(KeyError, "Parameter $1 repeated in input specification" % param_to_detect) else: result[param_to_detect] = addr(expected[i]) @@ -344,7 +344,7 @@ proc parse*(expected: seq[Tparameter_specification] = @[], ## ## If there is any kind of error and quit_on_failure is true, the quit proc ## will be called with a user error message. If quit_on_failure is false - ## errors will raise exceptions (usually EInvalidValue or EOverflow) instead + ## errors will raise exceptions (usually ValueError or EOverflow) instead ## for you to catch and handle. assert type_of_positional_parameters != PK_EMPTY and @@ -359,7 +359,7 @@ proc parse*(expected: seq[Tparameter_specification] = @[], # Prepare the input parameter list, maybe get it from the OS if not available. var args = args if args == nil: - let total_params = ParamCount() + let total_params = paramCount() #echo "Got no explicit args, retrieving from OS. Count: ", total_params newSeq(args, total_params) for i in 0..total_params - 1: @@ -387,7 +387,7 @@ proc parse*(expected: seq[Tparameter_specification] = @[], if param.consumes == PK_HELP: echo_help(expected, type_of_positional_parameters, bad_prefixes, end_of_options) - raise_or_quit(EInvalidKey, "") + raise_or_quit(KeyError, "") if param.consumes != PK_EMPTY: if i + 1 < args.len: @@ -396,14 +396,14 @@ proc parse*(expected: seq[Tparameter_specification] = @[], run_custom_proc(parsed, param.custom_validator, arg) i += 1 else: - raise_or_quit(EInvalidValue, ("parameter $1 requires a " & + raise_or_quit(ValueError, ("parameter $1 requires a " & "value, but none was provided") % [arg]) result.options[param.names[0]] = parsed break adding_positional_parameter else: for bad_prefix in bad_prefixes: if arg.startsWith(bad_prefix): - raise_or_quit(EInvalidValue, ("Found ambiguos parameter '$1' " & + raise_or_quit(ValueError, ("Found ambiguos parameter '$1' " & "starting with '$2', put '$3' as the previous parameter " & "if you want to force it as positional parameter.") % [arg, bad_prefix, end_of_options]) @@ -415,7 +415,7 @@ proc parse*(expected: seq[Tparameter_specification] = @[], i += 1 -proc toString(runes: seq[TRune]): string = +proc toString(runes: seq[Rune]): string = result = "" for rune in runes: result.add(rune.toUTF8) @@ -424,7 +424,7 @@ proc ascii_cmp(a, b: string): int = ## Comparison ignoring non ascii characters, for better switch sorting. let a = filterIt(toSeq(runes(a)), it.isAlpha()) # Can't use filterIt twice, github bug #351. - let b = filter(toSeq(runes(b)), proc(x: TRune): bool = x.isAlpha()) + let b = filter(toSeq(runes(b)), proc(x: Rune): bool = x.isAlpha()) return system.cmp(toString(a), toString(b)) diff --git a/tests/manyloc/argument_parser/ex_wget.nimrod.cfg b/tests/manyloc/argument_parser/ex_wget.nim.cfg index 4ea571d31..4ea571d31 100644 --- a/tests/manyloc/argument_parser/ex_wget.nimrod.cfg +++ b/tests/manyloc/argument_parser/ex_wget.nim.cfg diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim index d9c933939..d079a2e72 100644 --- a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim +++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim @@ -21,8 +21,8 @@ const Lib = "libchipmunk.so.6.1.1" -when defined(MoreNimrod): - {.hint: "MoreNimrod defined; some Chipmunk functions replaced in Nimrod".} +when defined(MoreNim): + {.hint: "MoreNim defined; some Chipmunk functions replaced in Nim".} {.deadCodeElim: on.} from math import sqrt, sin, cos, arctan2 when defined(CpUseFloat): @@ -729,7 +729,7 @@ proc isRogue*(body: PBody): Bool {.inline.} = defGetter(PBody, CpFloat, m, Mass) #/ Set the mass of a body. -when defined(MoreNimrod): +when defined(MoreNim): defSetter(PBody, CpFloat, m, Mass) else: proc setMass*(body: PBody; m: CpFloat){. @@ -738,7 +738,7 @@ else: #/ Get the moment of a body. defGetter(PBody, CpFloat, i, Moment) #/ Set the moment of a body. -when defined(MoreNimrod): +when defined(MoreNim): defSetter(PBody, CpFloat, i, Moment) else: proc SetMoment*(body: PBody; i: CpFloat) {. @@ -747,7 +747,7 @@ else: #/ Get the position of a body. defGetter(PBody, TVector, p, Pos) #/ Set the position of a body. -when defined(MoreNimrod): +when defined(MoreNim): defSetter(PBody, TVector, p, Pos) else: proc setPos*(body: PBody; pos: TVector) {. @@ -1088,7 +1088,7 @@ proc getSegmentRadius*(shape: PShape): CpFloat {. #var VersionString*{.importc: "cpVersionString", dynlib: Lib.}: cstring #/ Calculate the moment of inertia for a circle. #/ @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0. -when defined(MoreNimrod): +when defined(MoreNim): proc momentForCircle*(m, r1, r2: CpFloat; offset: TVector): CpFloat {.cdecl.} = result = m * (0.5 * (r1 * r1 + r2 * r2) + lenSq(offset)) else: diff --git a/tests/manyloc/keineschweine/dependencies/nake/nake.nim b/tests/manyloc/keineschweine/dependencies/nake/nake.nim index eade28c70..5828e400c 100644 --- a/tests/manyloc/keineschweine/dependencies/nake/nake.nim +++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim @@ -58,7 +58,7 @@ when isMainModule: for i in 1..paramCount(): args.add paramStr(i) args.add " " - quit(shell("nimrod", "c", "-r", "nakefile.nim", args)) + quit(shell("nim", "c", "-r", "nakefile.nim", args)) else: addQuitProc(proc() {.noconv.} = var diff --git a/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim index 24af63d10..bdf2139c9 100644 --- a/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim +++ b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim @@ -2,7 +2,7 @@ import nake nakeImports task "install", "compile and install nake binary": - if shell("nimrod", "c", "nake") == 0: + if shell("nim", "c", "nake") == 0: let path = getEnv("PATH").split(PathSep) for index, dir in pairs(path): echo " ", index, ". ", dir diff --git a/tests/manyloc/keineschweine/enet_server/nakefile.nim b/tests/manyloc/keineschweine/enet_server/nakefile.nim index 1ca93a340..3764c6271 100644 --- a/tests/manyloc/keineschweine/enet_server/nakefile.nim +++ b/tests/manyloc/keineschweine/enet_server/nakefile.nim @@ -5,9 +5,9 @@ const ServerDefines = "-d:NoSFML --forceBuild" task "server", "build the server": - if shell("nimrod", ServerDefines, "-r", "compile", "enet_server") != 0: + if shell("nim", ServerDefines, "-r", "compile", "enet_server") != 0: quit "Failed to build" task "gui", "build the server GUI mode": - if shell("nimrod", "--app:gui", ServerDefines, "-r", "compile", "enet_server") != 0: + if shell("nim", "--app:gui", ServerDefines, "-r", "compile", "enet_server") != 0: quit "Failed to build" diff --git a/tests/manyloc/keineschweine/keineschweine.nimrod.cfg b/tests/manyloc/keineschweine/keineschweine.nim.cfg index ca6c75f6e..ca6c75f6e 100644 --- a/tests/manyloc/keineschweine/keineschweine.nimrod.cfg +++ b/tests/manyloc/keineschweine/keineschweine.nim.cfg diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim index 4b1b35662..04b745003 100644 --- a/tests/manyloc/nake/nake.nim +++ b/tests/manyloc/nake/nake.nim @@ -58,7 +58,7 @@ when isMainModule: for i in 1..paramCount(): args.add paramStr(i) args.add " " - quit(shell("nimrod", "c", "-r", "nakefile.nim", args)) + quit(shell("nim", "c", "-r", "nakefile.nim", args)) else: addQuitProc(proc() {.noconv.} = var diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim index 700f9ab49..d1d712964 100644 --- a/tests/manyloc/nake/nakefile.nim +++ b/tests/manyloc/nake/nakefile.nim @@ -9,16 +9,16 @@ const BinLibs = "http://dl.dropbox.com/u/37533467/libs-2012-09-12.zip" ExeName = "keineschweine" ServerDefines = "-d:NoSFML -d:NoChipmunk" - TestBuildDefines = "-d:escapeMenuTest -d:debugWeps -d:showFPS -d:moreNimrod -d:debugKeys -d:foo -d:recordMode --forceBuild" + TestBuildDefines = "-d:escapeMenuTest -d:debugWeps -d:showFPS -d:moreNim -d:debugKeys -d:foo -d:recordMode --forceBuild" ReleaseDefines = "-d:release --deadCodeElim:on" ReleaseTestDefines = "-d:debugWeps -d:debugKeys --forceBuild" task "testprofile", "..": - if shell("nimrod", TestBuildDefines, "--profiler:on", "--stacktrace:on", "compile", ExeName) == 0: + if shell("nim", TestBuildDefines, "--profiler:on", "--stacktrace:on", "compile", ExeName) == 0: shell "."/ExeName, "offline" task "test", "Build with test defines": - if shell("nimrod", TestBuildDefines, "compile", ExeName) != 0: + if shell("nim", TestBuildDefines, "compile", ExeName) != 0: quit "The build failed." task "testrun", "Build with test defines and run": @@ -26,22 +26,22 @@ task "testrun", "Build with test defines and run": shell "."/ExeName task "test2", "Build release test build test release build": - if shell("nimrod", ReleaseDefines, ReleaseTestDefines, "compile", ExeName) == 0: + if shell("nim", ReleaseDefines, ReleaseTestDefines, "compile", ExeName) == 0: shell "."/ExeName discard """task "dirserver", "build the directory server": withDir "server": - if shell("nimrod", ServerDefines, "compile", "dirserver") != 0: + if shell("nim", ServerDefines, "compile", "dirserver") != 0: echo "Failed to build the dirserver" quit 1""" task "zoneserver", "build the zone server": withDir "enet_server": - if shell("nimrod", ServerDefines, "compile", "enet_server") != 0: + if shell("nim", ServerDefines, "compile", "enet_server") != 0: quit "Failed to build the zoneserver" task "zoneserver-gui", "build the zone server, with gui!": withDir "enet_server": - if shell("nimrod", ServerDefines, "--app:gui", "compile", "enet_server") != 0: + if shell("nim", ServerDefines, "--app:gui", "compile", "enet_server") != 0: quit "Failed to build the zoneserver" task "servers", "build the server and directory server": @@ -54,7 +54,7 @@ task "all", "run SERVERS and TEST tasks": runTask "test" task "release", "release build": - let res = shell("nimrod", ReleaseDefines, "compile", ExeName) + let res = shell("nim", ReleaseDefines, "compile", ExeName) if res != 0: echo "The build failed." quit 1 @@ -84,7 +84,7 @@ task "download", "download game assets": skipAssets = false path = expandFilename("data") path.add DirSep - path.add(extractFilename(gameAssets)) + path.add(extractFilename(GameAssets)) if existsFile(path): echo "The file already exists\n", "[R]emove [M]ove [Q]uit [S]kip Source: ", GameAssets @@ -92,7 +92,7 @@ task "download", "download game assets": of "r": removeFile path of "m": - moveFile path, path/../(extractFilename(gameAssets)&"-old") + moveFile path, path/../(extractFilename(GameAssets)&"-old") of "s": skipAssets = true else: @@ -101,7 +101,7 @@ task "download", "download game assets": echo "Downloading from ", GameAssets if not skipAssets: echo "Downloading to ", path - downloadFile gameAssets, path + downloadFile GameAssets, path echo "Download finished" let targetDir = parentDir(parentDir(path)) diff --git a/tests/manyloc/nake/nakefile.nimrod.cfg b/tests/manyloc/nake/nakefile.nim.cfg index 6f3e86fe6..6f3e86fe6 100644 --- a/tests/manyloc/nake/nakefile.nimrod.cfg +++ b/tests/manyloc/nake/nakefile.nim.cfg diff --git a/tests/manyloc/named_argument_bug/main.nimrod.cfg b/tests/manyloc/named_argument_bug/main.nim.cfg index 27cf8e688..27cf8e688 100644 --- a/tests/manyloc/named_argument_bug/main.nimrod.cfg +++ b/tests/manyloc/named_argument_bug/main.nim.cfg diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim index a6b7bac63..3b57acb8e 100644 --- a/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim +++ b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim @@ -3,10 +3,10 @@ import tri_engine/config type - TV2*[T:TNumber=TR] = array[0..1, T] - TV3*[T:TNumber=TR] = array[0..2, T] - TV4*[T:TNumber=TR] = array[0..3, T] - TVT*[T:TNumber=TR] = TV2|TV3|TV4 + TV2*[T:SomeNumber=TR] = array[0..1, T] + TV3*[T:SomeNumber=TR] = array[0..2, T] + TV4*[T:SomeNumber=TR] = array[0..3, T] + TVT*[T:SomeNumber=TR] = TV2|TV3|TV4 #TV2* = array[0..1, TR] #TV3* = array[0..2, TR] #TV4* = array[0..3, TR] diff --git a/tests/manyloc/packages/noconflicts.nimrod.cfg b/tests/manyloc/packages/noconflicts.nim.cfg index 88974ab8c..88974ab8c 100644 --- a/tests/manyloc/packages/noconflicts.nimrod.cfg +++ b/tests/manyloc/packages/noconflicts.nim.cfg diff --git a/tests/manyloc/standalone/barebone.nimrod.cfg b/tests/manyloc/standalone/barebone.nim.cfg index 52ec64e3f..52ec64e3f 100644 --- a/tests/manyloc/standalone/barebone.nimrod.cfg +++ b/tests/manyloc/standalone/barebone.nim.cfg diff --git a/tests/metatype/tcompositetypeclasses.nim b/tests/metatype/tcompositetypeclasses.nim index a2db73769..5ae93795f 100644 --- a/tests/metatype/tcompositetypeclasses.nim +++ b/tests/metatype/tcompositetypeclasses.nim @@ -33,7 +33,7 @@ accept baz(vbaz) reject baz(vnotbaz) reject bar(vfoo) -# https://github.com/Araq/Nimrod/issues/517 +# https://github.com/Araq/Nim/issues/517 type TVecT*[T] = array[0..1, T]|array[0..2, T]|array[0..3, T] TVec2* = array[0..1, float32] @@ -43,7 +43,7 @@ proc f[T](a: TVecT[T], b: TVecT[T]): T = discard var x: float = f([0.0'f32, 0.0'f32], [0.0'f32, 0.0'f32]) var y = f(TVec2([0.0'f32, 0.0'f32]), TVec2([0.0'f32, 0.0'f32])) -# https://github.com/Araq/Nimrod/issues/602 +# https://github.com/Araq/Nim/issues/602 type TTest = object TTest2* = object diff --git a/tests/metatype/ttypeclasses.nim b/tests/metatype/ttypeclasses.nim index 677229868..db9db7713 100644 --- a/tests/metatype/ttypeclasses.nim +++ b/tests/metatype/ttypeclasses.nim @@ -1,3 +1,18 @@ +discard """ + output: '''12 +1xxx +true0 +12 +testtest +1010 +11string +testtest1 +seq +seq +seq +foo seq +foo of numeric'''""" + type TFoo[T] = object val: T diff --git a/tests/metatype/typeclassinference.nim b/tests/metatype/typeclassinference.nim index 72b5aca96..2ac037ac5 100644 --- a/tests/metatype/typeclassinference.nim +++ b/tests/metatype/typeclassinference.nim @@ -1,3 +1,8 @@ +discard """ + errormsg: "type mismatch: got (string) but expected 'ptr'" + line: 20 +""" + import typetraits type @@ -8,3 +13,9 @@ var x = Vec([1, 2, 3]) static: assert x.type.name == "Vec[static[int](3), int]" +var str1: string = "hello, world!" +var ptr1: ptr = addr(str1) + +var str2: string = "hello, world!" +var ptr2: ptr = str2 + diff --git a/tests/misc/t99bott.nim b/tests/misc/t99bott.nim index d18cb0d5c..b3b30d296 100644 --- a/tests/misc/t99bott.nim +++ b/tests/misc/t99bott.nim @@ -6,7 +6,7 @@ discard """ """ ## 99 Bottles of Beer ## http://www.99-bottles-of-beer.net/ -## Nimrod version +## Nim version ## Author: Philippe Lhoste <PhiLho(a)GMX.net> http://Phi.Lho.free.fr # 2012-11-25 diff --git a/tests/misc/tdllvar.nim b/tests/misc/tdllvar.nim index ab767770c..5a31dfbbb 100644 --- a/tests/misc/tdllvar.nim +++ b/tests/misc/tdllvar.nim @@ -2,9 +2,9 @@ import os proc getDllName: string = result = "mylib.dll" - if ExistsFile(result): return + if fileExists(result): return result = "mylib2.dll" - if ExistsFile(result): return + if fileExists(result): return quit("could not load dynamic library") proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().} diff --git a/tests/misc/temit.nim b/tests/misc/temit.nim index ff8df0585..e2a9eaff1 100644 --- a/tests/misc/temit.nim +++ b/tests/misc/temit.nim @@ -10,8 +10,8 @@ static int cvariable = 420; """.} proc embedsC() = - var nimrodVar = 89 - {.emit: """printf("%d\n", cvariable + (int)`nimrodVar`);""".} + var nimVar = 89 + {.emit: """printf("%d\n", cvariable + (int)`nimVar`);""".} embedsC() diff --git a/tests/misc/teventemitter.nim b/tests/misc/teventemitter.nim index 9ecf72ea2..bfcf95701 100644 --- a/tests/misc/teventemitter.nim +++ b/tests/misc/teventemitter.nim @@ -5,29 +5,29 @@ discard """ import tables, lists type - TEventArgs = object of TObject - TEventEmitter = object of TObject - events*: TTable[string, TDoublyLinkedList[proc(e: TEventArgs) {.nimcall.}]] + EventArgs = object of RootObj + EventEmitter = object of RootObj + events*: Table[string, DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]] -proc emit*(emitter: TEventEmitter, event: string, args: TEventArgs) = +proc emit*(emitter: EventEmitter, event: string, args: EventArgs) = for func in nodes(emitter.events[event]): func.value(args) #call function with args. -proc on*(emitter: var TEventEmitter, event: string, - func: proc(e: TEventArgs) {.nimcall.}) = +proc on*(emitter: var EventEmitter, event: string, + func: proc(e: EventArgs) {.nimcall.}) = if not hasKey(emitter.events, event): - var list: TDoublyLinkedList[proc(e: TEventArgs) {.nimcall.}] + var list: DoublyLinkedList[proc(e: EventArgs) {.nimcall.}] add(emitter.events, event, list) #if not, add it. append(emitter.events.mget(event), func) -proc initEmitter(emitter: var TEventEmitter) = +proc initEmitter(emitter: var EventEmitter) = emitter.events = initTable[string, - TDoublyLinkedList[proc(e: TEventArgs) {.nimcall.}]]() + DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]]() var - ee: TEventEmitter - args: TEventArgs + ee: EventEmitter + args: EventArgs initEmitter(ee) -ee.on("print", proc(e: TEventArgs) = echo("pie")) +ee.on("print", proc(e: EventArgs) = echo("pie")) ee.emit("print", args) diff --git a/tests/misc/thallo.nim b/tests/misc/thallo.nim index 7244c27a1..cbeb45b97 100644 --- a/tests/misc/thallo.nim +++ b/tests/misc/thallo.nim @@ -37,7 +37,7 @@ macrotest(stdout) #GC_disable() -echo("This was compiled by Nimrod version " & system.nimrodVersion) +echo("This was compiled by Nim version " & system.NimVersion) writeln(stdout, "Hello", " World", "!") echo(["a", "b", "c", "d"].len) diff --git a/tests/misc/tints.nim b/tests/misc/tints.nim index fb2852af9..3e413026a 100644 --- a/tests/misc/tints.nim +++ b/tests/misc/tints.nim @@ -41,5 +41,5 @@ test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8) test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64) test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32) -Echo("Success") #OUT Success +echo("Success") #OUT Success diff --git a/tests/misc/tlastmod.nim b/tests/misc/tlastmod.nim index 75b047fc8..92ac922f7 100644 --- a/tests/misc/tlastmod.nim +++ b/tests/misc/tlastmod.nim @@ -6,13 +6,13 @@ import proc main() = var a, b: TTime - a = getLastModificationTime(ParamStr(1)) - b = getLastModificationTime(ParamStr(2)) + a = getLastModificationTime(paramStr(1)) + b = getLastModificationTime(paramStr(2)) writeln(stdout, $a) writeln(stdout, $b) if a < b: - Write(stdout, "$2 is newer than $1\n" % [ParamStr(1), ParamStr(2)]) + write(stdout, "$2 is newer than $1\n" % [paramStr(1), paramStr(2)]) else: - Write(stdout, "$1 is newer than $2\n" % [ParamStr(1), ParamStr(2)]) + write(stdout, "$1 is newer than $2\n" % [paramStr(1), paramStr(2)]) main() diff --git a/tests/misc/tloops.nim b/tests/misc/tloops.nim index f6f939769..1aada0298 100644 --- a/tests/misc/tloops.nim +++ b/tests/misc/tloops.nim @@ -31,7 +31,7 @@ proc TestLoops() = break break - while True: + while true: break diff --git a/tests/misc/tmandelbrot.nim b/tests/misc/tmandelbrot.nim index bb1b46d89..4228b0416 100644 --- a/tests/misc/tmandelbrot.nim +++ b/tests/misc/tmandelbrot.nim @@ -1,8 +1,8 @@ discard """ - cmd: "nimrod $target --hints:on -d:release $options $file" + cmd: "nim $target --hints:on -d:release $options $file" """ -# -*- nimrod -*- +# -*- nim -*- import math import os diff --git a/tests/misc/tnot.nim b/tests/misc/tnot.nim index cd0f538e6..6193e21e1 100644 --- a/tests/misc/tnot.nim +++ b/tests/misc/tnot.nim @@ -5,16 +5,16 @@ discard """ """ # BUG: following compiles, but should not: -proc nodeOfDegree(x: Int): bool = +proc nodeOfDegree(x: int): bool = result = false proc main = for j in 0..2: for i in 0..10: if not nodeOfDegree(1) >= 0: #ERROR_MSG type mismatch - Echo "Yes" + echo "Yes" else: - Echo "No" + echo "No" main() diff --git a/tests/misc/tpos.nim b/tests/misc/tpos.nim index 3d72536dd..5560ef050 100644 --- a/tests/misc/tpos.nim +++ b/tests/misc/tpos.nim @@ -14,10 +14,10 @@ proc mypos(sub, s: string, start: int = 0): int = if i >= N: result = -1 else: - while True: + while true: if s[i] == sub[j]: - Inc(i) - Inc(j) + inc(i) + inc(j) else: i = i - j + 1 j = 0 diff --git a/tests/misc/tprep.nim b/tests/misc/tprep.nim index 4ef9e2543..8f40300d6 100644 --- a/tests/misc/tprep.nim +++ b/tests/misc/tprep.nim @@ -24,7 +24,7 @@ else: var s: string -write(stdout, "compiled at " & system.compileDate & - " " & compileTime & "\n") +write(stdout, "compiled at " & system.CompileDate & + " " & CompileTime & "\n") echo getDateStr() echo getClockStr() diff --git a/tests/misc/tradix.nim b/tests/misc/tradix.nim index e5998ee12..311aa9ccd 100644 --- a/tests/misc/tradix.nim +++ b/tests/misc/tradix.nim @@ -4,7 +4,7 @@ ## We use a radix tree with node compression. ## There are two node kinds: -const bitsPerUnit = 8*sizeof(int) +const BitsPerUnit = 8*sizeof(int) type TRadixNodeKind = enum rnLinear, rnFull, rnLeafBits, rnLeafLinear @@ -42,13 +42,13 @@ proc testBit(w, i: int): bool {.inline.} = result = (w and (1 shl (i %% BitsPerUnit))) != 0 proc setBit(w: var int, i: int) {.inline.} = - w = w or (1 shl (i %% bitsPerUnit)) + w = w or (1 shl (i %% BitsPerUnit)) proc resetBit(w: var int, i: int) {.inline.} = - w = w and not (1 shl (i %% bitsPerUnit)) + w = w and not (1 shl (i %% BitsPerUnit)) proc testOrSetBit(w: var int, i: int): bool {.inline.} = - var x = (1 shl (i %% bitsPerUnit)) + var x = (1 shl (i %% BitsPerUnit)) if (w and x) != 0: return true w = w or x @@ -78,7 +78,7 @@ proc exclLeaf(r: PRadixNode, a: int) = return else: assert(false) -proc contains*(r: PRadixNode, a: TAddress): bool = +proc contains*(r: PRadixNode, a: ByteAddress): bool = if r == nil: return false var x = searchInner(r, a shr 24 and 0xff) if x == nil: return false @@ -88,7 +88,7 @@ proc contains*(r: PRadixNode, a: TAddress): bool = if x == nil: return false return searchLeaf(x, a and 0xff) -proc excl*(r: PRadixNode, a: TAddress): bool = +proc excl*(r: PRadixNode, a: ByteAddress): bool = if r == nil: return false var x = searchInner(r, a shr 24 and 0xff) if x == nil: return false @@ -167,10 +167,10 @@ proc addInner(r: var PRadixNode, a: int, d: int): bool = return addInner(x.b[k], a, d-8) else: assert(false) -proc incl*(r: var PRadixNode, a: TAddress) {.inline.} = +proc incl*(r: var PRadixNode, a: ByteAddress) {.inline.} = discard addInner(r, a, 24) -proc testOrIncl*(r: var PRadixNode, a: TAddress): bool {.inline.} = +proc testOrIncl*(r: var PRadixNode, a: ByteAddress): bool {.inline.} = return addInner(r, a, 24) iterator innerElements(r: PRadixNode): tuple[prefix: int, n: PRadixNode] = @@ -204,7 +204,7 @@ iterator leafElements(r: PRadixNode): int = yield ze(r.keys[i]) else: assert(false) -iterator elements*(r: PRadixNode): TAddress {.inline.} = +iterator elements*(r: PRadixNode): ByteAddress {.inline.} = for p1, n1 in innerElements(r): for p2, n2 in innerElements(n1): for p3, n3 in innerElements(n2): @@ -297,7 +297,7 @@ when false: result = ze(r.keys[i.x]) inc(i.x) - iterator elements(r: PRadixNode): TAddress {.inline.} = + iterator elements(r: PRadixNode): ByteAddress {.inline.} = var a, b, c, d: TRadixIter init(a, r) diff --git a/tests/misc/treadln.nim b/tests/misc/treadln.nim index 1117ab5f9..1edbea992 100644 --- a/tests/misc/treadln.nim +++ b/tests/misc/treadln.nim @@ -2,11 +2,11 @@ # Macintosh, Unix or Windows text format. var - inp: TFile + inp: File line: string if open(inp, "readme.txt"): - while not EndOfFile(inp): + while not endOfFile(inp): line = readLine(inp) echo("#" & line & "#") close(inp) diff --git a/tests/misc/tsimplesort.nim b/tests/misc/tsimplesort.nim index 0167ca78a..c282b3445 100644 --- a/tests/misc/tsimplesort.nim +++ b/tests/misc/tsimplesort.nim @@ -4,11 +4,7 @@ discard """ import hashes, math - -when defined(shallowADT): - {.pragma: myShallow, shallow.} -else: - {.pragma: myShallow.} +{.pragma: myShallow.} type TSlotEnum = enum seEmpty, seFilled, seDeleted @@ -63,7 +59,7 @@ template rawInsertImpl() = data[h].val = val data[h].slot = seFilled -proc RawGet[A, B](t: TTable[A, B], key: A): int = +proc rawGet[A, B](t: TTable[A, B], key: A): int = rawGetImpl() proc `[]`*[A, B](t: TTable[A, B], key: A): B = @@ -71,31 +67,31 @@ proc `[]`*[A, B](t: TTable[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 index = rawGet(t, key) if index >= 0: result = t.data[index].val proc hasKey*[A, B](t: TTable[A, B], key: A): bool = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 -proc RawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B], +proc rawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B], key: A, val: B) = rawInsertImpl() -proc Enlarge[A, B](t: var TTable[A, B]) = +proc enlarge[A, B](t: var TTable[A, B]) = var n: TKeyValuePairSeq[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) + if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val) swap(t.data, n) -template PutImpl() = - var index = RawGet(t, key) +template putImpl() = + var index = rawGet(t, key) if index >= 0: t.data[index].val = val else: - if mustRehash(len(t.data), t.counter): Enlarge(t) - RawInsert(t, t.data, key, val) + if mustRehash(len(t.data), t.counter): enlarge(t) + rawInsert(t, t.data, key, val) inc(t.counter) proc `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) = @@ -104,7 +100,7 @@ proc `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) = proc del*[A, B](t: var TTable[A, B], key: A) = ## deletes `key` from hash table `t`. - var index = RawGet(t, key) + var index = rawGet(t, key) if index >= 0: t.data[index].slot = seDeleted dec(t.counter) @@ -183,24 +179,24 @@ proc hasKey*[A](t: TCountTable[A], key: A): bool = ## returns true iff `key` is in the table `t`. result = rawGet(t, key) >= 0 -proc RawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]], +proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]], key: A, val: int) = var h: THash = hash(key) and high(data) while data[h].val != 0: h = nextTry(h, high(data)) data[h].key = key data[h].val = val -proc Enlarge[A](t: var TCountTable[A]) = +proc enlarge[A](t: var TCountTable[A]) = var n: seq[tuple[key: A, val: int]] newSeq(n, len(t.data) * growthFactor) for i in countup(0, high(t.data)): - if t.data[i].val != 0: RawInsert(t, n, t.data[i].key, t.data[i].val) + if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val) swap(t.data, n) proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) = ## puts a (key, value)-pair into `t`. `val` has to be positive. assert val > 0 - PutImpl() + putImpl() proc initCountTable*[A](initialSize=64): TCountTable[A] = ## creates a new count table that is empty. `initialSize` needs to be @@ -224,11 +220,11 @@ proc inc*[A](t: var TCountTable[A], key: A, val = 1) = if index >= 0: inc(t.data[index].val, val) else: - if mustRehash(len(t.data), t.counter): Enlarge(t) - RawInsert(t, t.data, key, val) + if mustRehash(len(t.data), t.counter): enlarge(t) + rawInsert(t, t.data, key, val) inc(t.counter) -proc Smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] = +proc smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] = ## returns the largest (key,val)-pair. Efficiency: O(n) assert t.len > 0 var minIdx = 0 @@ -237,7 +233,7 @@ proc Smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] = result.key = t.data[minIdx].key result.val = t.data[minIdx].val -proc Largest*[A](t: TCountTable[A]): tuple[key: A, val: int] = +proc largest*[A](t: TCountTable[A]): tuple[key: A, val: int] = ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n) assert t.len > 0 var maxIdx = 0 diff --git a/tests/misc/tvarnums.nim b/tests/misc/tvarnums.nim index 4f99df8b9..b880cf006 100644 --- a/tests/misc/tvarnums.nim +++ b/tests/misc/tvarnums.nim @@ -74,7 +74,7 @@ proc toNum(b: TBuffer): int32 = while (ze(b[i]) and 128) != 0: inc(i) result = result or ((int32(ze(b[i])) and 127'i32) shl Shift) - Shift = shift + 7'i32 + Shift = Shift + 7'i32 if (ze(b[0]) and (1 shl 6)) != 0: # sign bit set? result = (not result) +% 1'i32 # this is the same as ``- result`` diff --git a/tests/objects/tobjcov.nim b/tests/objects/tobjcov.nim index fc44edf8e..8391727f2 100644 --- a/tests/objects/tobjcov.nim +++ b/tests/objects/tobjcov.nim @@ -9,7 +9,7 @@ type proc ap(x: var TA) = x.a = -1 proc bp(x: var TB) = x.b[high(x.b)] = -1 -# in Nimrod proc (x: TB) is compatible to proc (x: TA), +# in Nim proc (x: TB) is compatible to proc (x: TA), # but this is not type safe: var f = cast[proc (x: var TA) {.nimcall.}](bp) var a: TA diff --git a/tests/objvariant/tyaoption.nim b/tests/objvariant/tyaoption.nim index 635e60bb8..7a29b8008 100644 --- a/tests/objvariant/tyaoption.nim +++ b/tests/objvariant/tyaoption.nim @@ -7,7 +7,7 @@ some(10)''' import strutils type Option[A] = object - case isDefined*: Bool + case isDefined*: bool of true: value*: A of false: @@ -19,7 +19,7 @@ proc some[A](value: A): Option[A] = proc none[A](): Option[A] = Option[A](isDefined: false) -proc `$`[A](o: Option[A]): String = +proc `$`[A](o: Option[A]): string = if o.isDefined: "some($1)" % [$o.value] else: @@ -27,14 +27,14 @@ proc `$`[A](o: Option[A]): String = let x = some("str") let y = some(5) -let z = none[Int]() +let z = none[int]() echo x, ", ", y, ", ", z -proc intOrString[A : Int | String](o: Option[A]): Option[A] = - when A is Int: +proc intOrString[A : int | string](o: Option[A]): Option[A] = + when A is int: some(o.value + 5) - elif A is String: + elif A is string: some(o.value & "!") else: o diff --git a/tests/overflw/toverflw.nim b/tests/overflw/toverflw.nim index cd7b65acf..fbe0d0a38 100644 --- a/tests/overflw/toverflw.nim +++ b/tests/overflw/toverflw.nim @@ -2,7 +2,7 @@ discard """ file: "toverflw.nim" output: "the computation overflowed" """ -# Tests nimrod's ability to detect overflows +# Tests nim's ability to detect overflows {.push overflowChecks: on.} @@ -12,7 +12,7 @@ a = high(int) b = -2 try: writeln(stdout, b - a) -except EOverflow: +except OverflowError: writeln(stdout, "the computation overflowed") {.pop.} # overflow check diff --git a/tests/overflw/toverflw2.nim b/tests/overflw/toverflw2.nim index f7fe3d574..75bd4cdf5 100644 --- a/tests/overflw/toverflw2.nim +++ b/tests/overflw/toverflw2.nim @@ -1,6 +1,6 @@ discard """ file: "toverflw2.nim" - outputsub: "Error: unhandled exception: over- or underflow [EOverflow]" + outputsub: "Error: unhandled exception: over- or underflow [OverflowError]" exitcode: "1" """ var a : int32 = 2147483647 diff --git a/tests/parallel/nimrod.cfg b/tests/parallel/nim.cfg index b81c89721..b81c89721 100644 --- a/tests/parallel/nimrod.cfg +++ b/tests/parallel/nim.cfg diff --git a/tests/parallel/tdeepcopy2.nim b/tests/parallel/tdeepcopy2.nim new file mode 100644 index 000000000..748ef4d9b --- /dev/null +++ b/tests/parallel/tdeepcopy2.nim @@ -0,0 +1,35 @@ +discard """ + output: '''called deepCopy for int +called deepCopy for int +done999 999 +""" + +import threadpool + + +type + Bar[T] = object + x: T + +proc deepCopy[T](b: ref Bar[T]): ref Bar[T] {.override.} = + result.new + result.x = b.x + when T is int: + echo "called deepCopy for int" + else: + echo "called deepCopy for something else" + +proc foo(b: ref Bar[int]): int = 999 + +# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()': + +proc main = + var dummy: ref Bar[int] + new(dummy) + dummy.x = 44 + parallel: + let f = spawn foo(dummy) + let b = spawn foo(dummy) + echo "done", f, " ", b + +main() diff --git a/tests/parallel/tflowvar.nim b/tests/parallel/tflowvar.nim index 77fab14b5..fd3aa326e 100644 --- a/tests/parallel/tflowvar.nim +++ b/tests/parallel/tflowvar.nim @@ -1,11 +1,14 @@ discard """ - output: '''foobarfoobarbazbearbazbear''' - cmd: "nimrod $target --threads:on $options $file" + output: '''foobarfoobar +bazbearbazbear + +1''' + cmd: "nim $target --threads:on $options $file" """ import threadpool -proc computeSomething(a, b: string): string = a & b & a & b +proc computeSomething(a, b: string): string = a & b & a & b & "\n" proc main = let fvA = spawn computeSomething("foo", "bar") @@ -15,3 +18,19 @@ proc main = main() sync() + + +type + TIntSeq = seq[int] + +proc t(): TIntSeq = + result = @[1] + +proc p(): int = + var a: FlowVar[TIntSeq] + parallel: + var aa = spawn t() + a = aa + result = (^a)[0] + +echo p() diff --git a/tests/parallel/tguard1.nim b/tests/parallel/tguard1.nim new file mode 100644 index 000000000..d96e17589 --- /dev/null +++ b/tests/parallel/tguard1.nim @@ -0,0 +1,37 @@ + +when false: + template lock(a, b: ptr TLock; body: stmt) = + if cast[ByteAddress](a) < cast[ByteAddress](b): + pthread_mutex_lock(a) + pthread_mutex_lock(b) + else: + pthread_mutex_lock(b) + pthread_mutex_lock(a) + {.locks: [a, b].}: + try: + body + finally: + pthread_mutex_unlock(a) + pthread_mutex_unlock(b) + +type + ProtectedCounter[T] = object + i {.guard: L.}: T + L: int + +var + c: ProtectedCounter[int] + +c.i = 89 + +template atomicRead(L, x): expr = + {.locks: [L].}: + x + +proc main = + {.locks: [c.L].}: + inc c.i + discard + echo(atomicRead(c.L, c.i)) + +main() diff --git a/tests/parallel/tguard2.nim b/tests/parallel/tguard2.nim new file mode 100644 index 000000000..b69ea3371 --- /dev/null +++ b/tests/parallel/tguard2.nim @@ -0,0 +1,27 @@ +discard """ + errormsg: "unguarded access: c.i" + line: 25 +""" + +type + ProtectedCounter[T] = object + i {.guard: L.}: T + L: int + +var + c: ProtectedCounter[int] + +c.i = 89 + +template atomicRead(L, x): expr = + {.locks: [L].}: + x + +proc main = + {.locks: [c.L].}: + inc c.i + discard + echo(atomicRead(c.L, c.i)) + echo c.i + +main() diff --git a/tests/parallel/tlet_spawn.nim b/tests/parallel/tlet_spawn.nim new file mode 100644 index 000000000..463ee1a47 --- /dev/null +++ b/tests/parallel/tlet_spawn.nim @@ -0,0 +1,14 @@ + +import threadpool + +proc foo(): int = 999 + +# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()': + +proc main = + parallel: + let f = spawn foo() + let b = spawn foo() + echo "done", f, " ", b + +main() diff --git a/tests/parallel/tsysspawn.nim b/tests/parallel/tsysspawn.nim index fc7921b0e..7244a5ee6 100644 --- a/tests/parallel/tsysspawn.nim +++ b/tests/parallel/tsysspawn.nim @@ -1,7 +1,7 @@ discard """ output: '''4 8''' - cmd: "nimrod $target --threads:on $options $file" + cmd: "nim $target --threads:on $options $file" """ import threadpool diff --git a/tests/parallel/tsysspawnbadarg.nim b/tests/parallel/tsysspawnbadarg.nim index ad798a7d3..2d3ffd241 100644 --- a/tests/parallel/tsysspawnbadarg.nim +++ b/tests/parallel/tsysspawnbadarg.nim @@ -1,7 +1,7 @@ discard """ line: 9 errormsg: "'spawn' takes a call expression" - cmd: "nimrod $target --threads:on $options $file" + cmd: "nim $target --threads:on $options $file" """ import threadpool diff --git a/tests/procvar/tprocvars.nim b/tests/procvar/tprocvars.nim index dc7592526..50d5d29f2 100644 --- a/tests/procvar/tprocvars.nim +++ b/tests/procvar/tprocvars.nim @@ -1,6 +1,6 @@ -proc doSomething(v: Int, x: proc(v:Int):Int): Int = return x(v) -proc doSomething(v: Int, x: proc(v:Int)) = x(v) +proc doSomething(v: int, x: proc(v:int):int): int = return x(v) +proc doSomething(v: int, x: proc(v:int)) = x(v) -echo doSomething(10, proc(v: Int): Int = return v div 2) +echo doSomething(10, proc(v: int): int = return v div 2) diff --git a/tests/range/tsubrange2.nim b/tests/range/tsubrange2.nim index d14111bb9..759d16b9c 100644 --- a/tests/range/tsubrange2.nim +++ b/tests/range/tsubrange2.nim @@ -1,6 +1,6 @@ discard """ file: "tsubrange2.nim" - outputsub: "value out of range: 50 [EOutOfRange]" + outputsub: "value out of range: 50 [RangeError]" exitcode: "1" """ diff --git a/tests/range/tsubrange3.nim b/tests/range/tsubrange3.nim index 9afb5018b..600161cfd 100644 --- a/tests/range/tsubrange3.nim +++ b/tests/range/tsubrange3.nim @@ -1,6 +1,6 @@ discard """ file: "tsubrange.nim" - outputsub: "value out of range: 50 [EOutOfRange]" + outputsub: "value out of range: 50 [RangeError]" exitcode: "1" """ @@ -16,4 +16,3 @@ var r = y #p y - diff --git a/tests/showoff/thtml2.nim b/tests/showoff/thtml2.nim index 8a451ebf1..faeb4e50d 100644 --- a/tests/showoff/thtml2.nim +++ b/tests/showoff/thtml2.nim @@ -1,5 +1,5 @@ discard """ - output: "<html><head><title>now look at this</title></head><body><ul><li>Nimrod is quite capable</li></ul></body></html>" + output: "<html><head><title>now look at this</title></head><body><ul><li>Nim is quite capable</li></ul></body></html>" """ import strutils @@ -32,6 +32,6 @@ html mainPage: title "now look at this" body: ul: - li "Nimrod is quite capable" + li "Nim is quite capable" echo mainPage() diff --git a/tests/stdlib/techo.nim b/tests/stdlib/techo.nim index 0fa4b5fe0..9cef9205f 100644 --- a/tests/stdlib/techo.nim +++ b/tests/stdlib/techo.nim @@ -1,3 +1,3 @@ -# Simplest Nimrod program +# Simplest Nim program echo "Hello, World!" diff --git a/tests/stdlib/tircbot.nim b/tests/stdlib/tircbot.nim index f0417c7ac..b91300762 100644 --- a/tests/stdlib/tircbot.nim +++ b/tests/stdlib/tircbot.nim @@ -191,7 +191,7 @@ type const ircServer = "irc.freenode.net" - joinChans = @["#nimrod"] + joinChans = @["#nim"] botNickname = "NimBot" proc setSeen(d: TDb, s: TSeen) = @@ -271,7 +271,7 @@ proc handleWebMessage(state: PState, line: string) = message.add("-" & $commit["removed"].len & "]: ") message.add(limitCommitMsg(commit["message"].str)) - # Send message to #nimrod. + # Send message to #nim. state.ircClient.privmsg(joinChans[0], message) elif json.hasKey("redisinfo"): assert json["redisinfo"].hasKey("port") @@ -420,7 +420,7 @@ proc handleIrc(irc: PAsyncIRC, event: TIRCEvent, state: PState) = seenNick.msg = msg state.database.setSeen(seenNick) of MNick: - createSeen(PSeenNick, event.nick, "#nimrod") + createSeen(PSeenNick, event.nick, "#nim") seenNick.newNick = event.params[0] state.database.setSeen(seenNick) else: diff --git a/tests/stdlib/tpegs.nim b/tests/stdlib/tpegs.nim index 6e488bab4..e5353e4ff 100644 --- a/tests/stdlib/tpegs.nim +++ b/tests/stdlib/tpegs.nim @@ -851,7 +851,7 @@ template `=~`*(s: string, pattern: TPeg): expr = ## This calls ``match`` with an implicit declared ``matches`` array that ## can be used in the scope of the ``=~`` call: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## if line =~ peg"\s* {\w+} \s* '=' \s* {\w+}": ## # matches a key=value pair: @@ -897,12 +897,12 @@ proc replacef*(s: string, sub: TPeg, by: string): string {. ## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by` ## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## ## "var1<-keykey; val2<-key2key2" result = "" @@ -979,13 +979,13 @@ iterator split*(s: string, sep: TPeg): string = ## Substrings are separated by the PEG `sep`. ## Examples: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## for word in split("00232this02939is39an22example111", peg"\d+"): ## writeln(stdout, word) ## ## Results in: ## - ## .. code-block:: nimrod + ## .. code-block:: nim ## "this" ## "is" ## "an" diff --git a/tests/stdlib/tunidecode.nim b/tests/stdlib/tunidecode.nim index 647858825..689453c76 100644 --- a/tests/stdlib/tunidecode.nim +++ b/tests/stdlib/tunidecode.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nimrod $target --hints:on -d:embedUnidecodeTable $options $file" + cmd: "nim $target --hints:on -d:embedUnidecodeTable $options $file" output: "Ausserst" """ diff --git a/tests/stdlib/txmlgen.nim b/tests/stdlib/txmlgen.nim index 917427abc..fa1dffe56 100644 --- a/tests/stdlib/txmlgen.nim +++ b/tests/stdlib/txmlgen.nim @@ -1,11 +1,11 @@ discard """ file: "txmlgen.nim" - output: "<h1><a href=\"http://force7.de/nimrod\">Nimrod</a></h1>" + output: "<h1><a href=\"http://force7.de/nim\">Nim</a></h1>" """ import htmlgen -var nim = "Nimrod" -echo h1(a(href="http://force7.de/nimrod", nim)) +var nim = "Nim" +echo h1(a(href="http://force7.de/nim", nim)) diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim index 931871f15..bfe2dc94a 100644 --- a/tests/stdlib/txmltree.nim +++ b/tests/stdlib/txmltree.nim @@ -5,9 +5,9 @@ discard """ import xmltree, strtabs -var x = <>a(href="nimrod.de", newText("www.nimrod-test.de")) +var x = <>a(href="nim.de", newText("www.nim-test.de")) -echo($x == "<a href=\"nimrod.de\">www.nimrod-test.de</a>") +echo($x == "<a href=\"nim.de\">www.nim-test.de</a>") diff --git a/tests/table/ttables.nim b/tests/table/ttables.nim index 60446b5a3..de4aaed5e 100644 --- a/tests/table/ttables.nim +++ b/tests/table/ttables.nim @@ -84,7 +84,7 @@ block orderedTableTest1: block countTableTest1: var s = data.toTable var t = initCountTable[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/template/t_otemplates.nim b/tests/template/t_otemplates.nim index 7de728ab2..1a9075d20 100644 --- a/tests/template/t_otemplates.nim +++ b/tests/template/t_otemplates.nim @@ -3,8 +3,8 @@ discard """ """ # Ref: -# http://nimrod-lang.org/macros.html -# http://nimrod-lang.org/parseutils.html +# http://nim-lang.org/macros.html +# http://nim-lang.org/parseutils.html # Imports @@ -313,7 +313,7 @@ proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool proc parse_template(node: PNimrodNode, value: string) = ## Parses through entire template, outputing valid - ## Nimrod code into the input `node` AST. + ## Nim code into the input `node` AST. var index = 0 while index < value.len and parse_until_symbol(node, value, index): nil diff --git a/tests/template/tissue993.nim b/tests/template/tissue993.nim index d39f43942..dae9df683 100644 --- a/tests/template/tissue993.nim +++ b/tests/template/tissue993.nim @@ -1,5 +1,5 @@ -type pnode* = ref object of tobject +type PNode* = ref object of RootObj template litNode (name, ty): stmt = type name* = ref object of PNode @@ -8,7 +8,7 @@ litNode PIntNode, int import json -template withKey*(j: PJsonNode; key: string; varname: expr; +template withKey*(j: JsonNode; key: string; varname: expr; body:stmt): stmt {.immediate.} = if j.hasKey(key): let varname{.inject.}= j[key] diff --git a/tests/testament/backend.nim b/tests/testament/backend.nim index 5199bb9d6..c7122e1b2 100644 --- a/tests/testament/backend.nim +++ b/tests/testament/backend.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Tester +# The Nim Tester # (c) Copyright 2014 Andreas Rumpf # # Look at license.txt for more info. diff --git a/tests/testament/caasdriver.nim b/tests/testament/caasdriver.nim index ddfe88273..8f2eec33b 100644 --- a/tests/testament/caasdriver.nim +++ b/tests/testament/caasdriver.nim @@ -9,7 +9,7 @@ type TRunMode = enum ProcRun, CaasRun, SymbolProcRun - TNimrodSession* = object + NimSession* = object nim: PProcess # Holds the open process for CaasRun sessions, nil otherwise. mode: TRunMode # Stores the type of run mode the session was started with. lastOutput: string # Preserves the last output, needed for ProcRun mode. @@ -26,15 +26,15 @@ const var TesterDir = getAppDir() / ".." - NimrodBin = TesterDir / "../bin/nimrod" + NimBin = TesterDir / "../bin/nim" -proc replaceVars(session: var TNimrodSession, text: string): string = +proc replaceVars(session: var NimSession, text: string): string = result = text.replace(filenameReplaceVar, session.filename) result = result.replace(moduleReplaceVar, session.modname) result = result.replace(silentReplaceVar, silentReplaceText) -proc startNimrodSession(project, script: string, mode: TRunMode): - TNimrodSession = +proc startNimSession(project, script: string, mode: TRunMode): + NimSession = let (dir, name, ext) = project.splitFile result.mode = mode result.lastOutput = "" @@ -50,10 +50,10 @@ proc startNimrodSession(project, script: string, mode: TRunMode): removeDir(nimcacheDir / "nimcache") if mode == CaasRun: - result.nim = startProcess(NimrodBin, workingDir = dir, + result.nim = startProcess(NimBin, workingDir = dir, args = ["serve", "--server.type:stdin", name]) -proc doCaasCommand(session: var TNimrodSession, command: string): string = +proc doCaasCommand(session: var NimSession, command: string): string = assert session.mode == CaasRun session.nim.inputStream.write(session.replaceVars(command) & "\n") session.nim.inputStream.flush @@ -69,11 +69,11 @@ proc doCaasCommand(session: var TNimrodSession, command: string): string = result = "FAILED TO EXECUTE: " & command & "\n" & result break -proc doProcCommand(session: var TNimrodSession, command: string): string = +proc doProcCommand(session: var NimSession, command: string): string = assert session.mode == ProcRun or session.mode == SymbolProcRun except: result = "FAILED TO EXECUTE: " & command & "\n" & result var - process = startProcess(NimrodBin, args = session.replaceVars(command).split) + process = startProcess(NimBin, args = session.replaceVars(command).split) stream = outputStream(process) line = TaintedString("") @@ -84,7 +84,7 @@ proc doProcCommand(session: var TNimrodSession, command: string): string = process.close() -proc doCommand(session: var TNimrodSession, command: string) = +proc doCommand(session: var NimSession, command: string) = if session.mode == CaasRun: if not session.nim.running: session.lastOutput = "FAILED TO EXECUTE: " & command & "\n" & @@ -102,7 +102,7 @@ proc doCommand(session: var TNimrodSession, command: string) = session.lastOutput = doProcCommand(session, command & " " & session.filename) -proc close(session: var TNimrodSession) {.destructor.} = +proc close(session: var NimSession) {.destructor.} = if session.mode == CaasRun: session.nim.close @@ -114,7 +114,7 @@ proc doScenario(script: string, output: PStream, mode: TRunMode, verbose: bool): if f.readLine(project): var - s = startNimrodSession(script.parentDir / project.string, script, mode) + s = startNimSession(script.parentDir / project.string, script, mode) tline = TaintedString("") ln = 1 diff --git a/tests/testament/categories.nim b/tests/testament/categories.nim index 02f7dc1d7..566a74cab 100644 --- a/tests/testament/categories.nim +++ b/tests/testament/categories.nim @@ -1,6 +1,6 @@ # # -# Nimrod Tester +# Nim Tester # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -20,7 +20,7 @@ const proc delNimCache() = try: removeDir(nimcacheDir) - except EOS: + except OSError: echo "[Warning] could not delete: ", nimcacheDir proc runRodFiles(r: var TResults, cat: Category, options: string) = @@ -71,7 +71,7 @@ proc compileRodFiles(r: var TResults, cat: Category, options: string) = proc safeCopyFile(src, dest: string) = try: copyFile(src, dest) - except EOS: + except OSError: echo "[Warning] could not copy: ", src, " to ", dest proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = @@ -87,7 +87,7 @@ proc runBasicDLLTest(c, r: var TResults, cat: Category, options: string) = else: # posix relies on crappy LD_LIBRARY_PATH (ugh!): var libpath = getenv"LD_LIBRARY_PATH".string - if peg"\i '/nimrod' (!'/')* '/lib'" notin libpath: + if peg"\i '/nim' (!'/')* '/lib'" notin libpath: echo "[Warning] insufficient LD_LIBRARY_PATH" var serverDll = DynlibFormat % "server" safeCopyFile("tests/dll" / serverDll, "lib" / serverDll) @@ -192,9 +192,9 @@ proc jsTests(r: var TResults, cat: Category, options: string) = # testSpec(r, t, options) proc findMainFile(dir: string): string = - # finds the file belonging to ".nimrod.cfg"; if there is no such file + # finds the file belonging to ".nim.cfg"; if there is no such file # it returns the some ".nim" file if there is only one: - const cfgExt = ".nimrod.cfg" + const cfgExt = ".nim.cfg" result = "" var nimFiles = 0 for kind, file in os.walkDir(dir): @@ -236,8 +236,8 @@ let packageDir = babelDir / "pkgs" packageIndex = babelDir / "packages.json" -proc waitForExitEx(p: PProcess): int = - var outp: PStream = outputStream(p) +proc waitForExitEx(p: Process): int = + var outp = outputStream(p) var line = newStringOfCap(120).TaintedString while true: if outp.readLine(line): @@ -250,7 +250,7 @@ proc waitForExitEx(p: PProcess): int = proc getPackageDir(package: string): string = ## TODO - Replace this with dom's version comparison magic. var commandOutput = execCmdEx("babel path $#" % package) - if commandOutput.exitCode != quitSuccess: + if commandOutput.exitCode != QuitSuccess: return "" else: result = commandOutput[0].string @@ -278,7 +278,7 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = echo("[Warning] - Cannot run babel tests: Babel binary not found.") return - if execCmd("$# update" % babelExe) == quitFailure: + if execCmd("$# update" % babelExe) == QuitFailure: echo("[Warning] - Cannot run babel tests: Babel update failed.") return @@ -291,7 +291,7 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = installProcess = startProcess(babelExe, "", ["install", "-y", name]) installStatus = waitForExitEx(installProcess) installProcess.close - if installStatus != quitSuccess: + if installStatus != QuitSuccess: r.addResult(test, "", "", reInstallFailed) continue @@ -301,11 +301,11 @@ proc testBabelPackages(r: var TResults, cat: Category, filter: PackageFilter) = buildProcess = startProcess(babelExe, buildPath, ["build"]) buildStatus = waitForExitEx(buildProcess) buildProcess.close - if buildStatus != quitSuccess: + if buildStatus != QuitSuccess: r.addResult(test, "", "", reBuildFailed) r.addResult(test, "", "", reSuccess) r.addResult(packageFileTest, "", "", reSuccess) - except EJsonParsingError: + except JsonParsingError: echo("[Warning] - Cannot run babel tests: Invalid package file.") r.addResult(packageFileTest, "", "", reBuildFailed) diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim index b91475aee..b9eda5383 100644 --- a/tests/testament/htmlgen.nim +++ b/tests/testament/htmlgen.nim @@ -1,6 +1,6 @@ # # -# Nimrod Tester +# Nim Tester # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -107,7 +107,7 @@ div.tabContent.hide { display: none; } HtmlEnd = "</body></html>" proc td(s: string): string = - result = "<td>" & s.substr(0, 200).XMLEncode & "</td>" + result = "<td>" & s.substr(0, 200).xmlEncode & "</td>" proc getCommit(db: TDbConn, c: int): string = var commit = c diff --git a/tests/testament/specs.nim b/tests/testament/specs.nim index 184f07c51..37fe8cfee 100644 --- a/tests/testament/specs.nim +++ b/tests/testament/specs.nim @@ -1,6 +1,6 @@ # # -# Nimrod Tester +# Nim Tester # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this @@ -10,7 +10,7 @@ import parseutils, strutils, os, osproc, streams, parsecfg const - cmdTemplate* = r"nimrod $target --hints:on $options $file" + cmdTemplate* = r"nim $target --hints:on $options $file" type TTestAction* = enum @@ -18,7 +18,7 @@ type actionRun = "run" actionReject = "reject" TResultEnum* = enum - reNimrodcCrash, # nimrod compiler seems to have crashed + reNimcCrash, # nim compiler seems to have crashed reMsgsDiffer, # error messages differ reFilesDiffer, # expected and given filenames differ reLinesDiffer, # expected and given line numbers differ @@ -59,7 +59,7 @@ when not declared(parseCfgBool): case normalize(s) of "y", "yes", "true", "1", "on": result = true of "n", "no", "false", "0", "off": result = false - else: raise newException(EInvalidValue, "cannot interpret as a bool: " & s) + else: raise newException(ValueError, "cannot interpret as a bool: " & s) proc extractSpec(filename: string): string = const tripleQuote = "\"\"\"" @@ -78,7 +78,7 @@ when not defined(nimhygiene): template parseSpecAux(fillResult: stmt) {.immediate.} = var ss = newStringStream(extractSpec(filename)) - var p {.inject.}: TCfgParser + var p {.inject.}: CfgParser open(p, ss, filename, 1) while true: var e {.inject.} = next(p) diff --git a/tests/testament/tester.nim b/tests/testament/tester.nim index fc6b4ff95..b74fa99c8 100644 --- a/tests/testament/tester.nim +++ b/tests/testament/tester.nim @@ -1,13 +1,13 @@ # # -# Nimrod Tester +# Nim Tester # (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # -## This program verifies Nimrod against the testcases. +## This program verifies Nim against the testcases. import parseutils, strutils, pegs, os, osproc, streams, parsecfg, json, @@ -146,9 +146,9 @@ proc codegenCheck(test: TTest, check: string, given: var TSpec) = let contents = readFile(genFile).string if contents.find(check.peg) < 0: given.err = reCodegenFailure - except EInvalidValue: + except ValueError: given.err = reInvalidPeg - except EIO: + except IOError: given.err = reCodeNotFound proc makeDeterministic(s: string): string = @@ -193,7 +193,7 @@ proc testSpec(r: var TResults, test: TTest) = return var (buf, exitCode) = execCmdEx( (if test.target == targetJS: "nodejs " else: "") & exeFile) - if exitCode != expected.ExitCode: + if exitCode != expected.exitCode: r.addResult(test, "exitcode: " & $expected.exitCode, "exitcode: " & $exitCode, reExitCodesDiffer) else: @@ -246,15 +246,15 @@ proc main() = if p.kind == cmdLongoption: case p.key.string.normalize of "print", "verbose": optPrintResults = true - else: quit usage + else: quit Usage p.next() - if p.kind != cmdArgument: quit usage + if p.kind != cmdArgument: quit Usage var action = p.key.string.normalize p.next() var r = initResults() case action of "all": - let testsDir = "tests" & dirSep + let testsDir = "tests" & DirSep for kind, dir in walkDir(testsDir): assert testsDir.startsWith(testsDir) let cat = dir[testsDir.len .. -1] @@ -272,7 +272,7 @@ proc main() = generateHtml(resultsFile, commit) generateJson(jsonFile, commit) else: - quit usage + quit Usage if optPrintResults: if action == "html": openDefaultBrowser(resultsFile) @@ -280,6 +280,6 @@ proc main() = backend.close() if paramCount() == 0: - quit usage + quit Usage main() diff --git a/tests/threads/nimrod.cfg b/tests/threads/nim.cfg index b81c89721..b81c89721 100644 --- a/tests/threads/nimrod.cfg +++ b/tests/threads/nim.cfg diff --git a/tests/threads/tthreadanalysis.nim b/tests/threads/tthreadanalysis.nim index 37369b79c..b222f15a9 100644 --- a/tests/threads/tthreadanalysis.nim +++ b/tests/threads/tthreadanalysis.nim @@ -2,7 +2,7 @@ discard """ outputsub: "101" errormsg: "'threadFunc' is not GC-safe" line: 39 - cmd: "nimrod $target --hints:on --threads:on $options $file" + cmd: "nim $target --hints:on --threads:on $options $file" """ import os diff --git a/tests/threads/tthreadanalysis2.nim b/tests/threads/tthreadanalysis2.nim index bcc09db98..d5b2cd430 100644 --- a/tests/threads/tthreadanalysis2.nim +++ b/tests/threads/tthreadanalysis2.nim @@ -2,7 +2,7 @@ discard """ file: "tthreadanalysis2.nim" line: 37 errormsg: "'threadFunc' is not GC-safe" - cmd: "nimrod $target --hints:on --threads:on $options $file" + cmd: "nim $target --hints:on --threads:on $options $file" """ import os diff --git a/tests/threads/tthreadheapviolation1.nim b/tests/threads/tthreadheapviolation1.nim index e0629ed08..94e1b64db 100644 --- a/tests/threads/tthreadheapviolation1.nim +++ b/tests/threads/tthreadheapviolation1.nim @@ -1,7 +1,7 @@ discard """ line: 11 errormsg: "'horrible' is not GC-safe" - cmd: "nimrod $target --hints:on --threads:on $options $file" + cmd: "nim $target --hints:on --threads:on $options $file" """ var diff --git a/tests/trmacros/targlist.nim b/tests/trmacros/targlist.nim index e416edf0a..321b3d5d2 100644 --- a/tests/trmacros/targlist.nim +++ b/tests/trmacros/targlist.nim @@ -3,7 +3,7 @@ discard """ """ proc f(x: varargs[string, `$`]) = discard -template optF{f(X)}(x: varargs[expr]) = +template optF{f(x)}(x: varargs[expr]) = writeln(stdout, x) f 1, 2, false, 3, "ha" diff --git a/tests/typerel/tnoargopenarray.nim b/tests/typerel/tnoargopenarray.nim index 872ec86d2..20ebe5ecc 100644 --- a/tests/typerel/tnoargopenarray.nim +++ b/tests/typerel/tnoargopenarray.nim @@ -1,7 +1,7 @@ import db_sqlite -var db: TDbConn -Exec(db, sql"create table blabla()") +var db: DbConn +exec(db, sql"create table blabla()") diff --git a/tests/typerel/trectuple.nim b/tests/typerel/trectuple.nim index 7c43ec5ba..ebaaa2ea7 100644 --- a/tests/typerel/trectuple.nim +++ b/tests/typerel/trectuple.nim @@ -1,3 +1,7 @@ +discard """ + errormsg: "illegal recursion in type 'TNode'" + line: 8 +""" type PNode = ref TNode diff --git a/tests/typerel/trectuples.nim b/tests/typerel/trectuples.nim index c59cfe880..a74e4859c 100644 --- a/tests/typerel/trectuples.nim +++ b/tests/typerel/trectuples.nim @@ -1,3 +1,7 @@ +discard """ + errormsg: "illegal recursion in type 'Node'" + line: 6 +""" type Node = tuple[left: ref Node] diff --git a/tests/types/tforwty2.nim b/tests/types/tforwty2.nim index 5d15e112a..d103314c5 100644 --- a/tests/types/tforwty2.nim +++ b/tests/types/tforwty2.nim @@ -6,7 +6,7 @@ type PSDL_semaphore = ptr TSDL_semaphore TSDL_semaphore {.final.} = object - sem: Pointer #PSem_t; + sem: pointer #PSem_t; when not defined(USE_NAMED_SEMAPHORES): sem_data: int when defined(BROKEN_SEMGETVALUE): @@ -18,5 +18,5 @@ type PSDL_Sem = ptr TSDL_Sem TSDL_Sem = TSDL_Semaphore -proc SDL_CreateSemaphore(initial_value: Int32): PSDL_Sem {. +proc SDL_CreateSemaphore(initial_value: int32): PSDL_Sem {. importc: "SDL_CreateSemaphore".} diff --git a/tests/types/tillegaltyperecursion.nim b/tests/types/tillegaltyperecursion.nim index 114e4d08e..ebdbc1d13 100644 --- a/tests/types/tillegaltyperecursion.nim +++ b/tests/types/tillegaltyperecursion.nim @@ -1,5 +1,5 @@ discard """ - cmd: "nimrod $target --threads:on $options $file" + cmd: "nim $target --threads:on $options $file" errormsg: "illegal recursion in type 'TIRC'" line: 16 """ @@ -62,5 +62,5 @@ proc Connect*(irc: var TIRC, nick: string, host: string, port: int = 6667) = when isMainModule: var irc = initIRC() irc.Connect("AmryBot[Nim]","irc.freenode.net",6667) - irc.sendRaw("JOIN #nimrod") + irc.sendRaw("JOIN #nim") os.Sleep(4000) diff --git a/tests/types/tillrec.nim b/tests/types/tillrec.nim index 1d1ec0622..18757140a 100644 --- a/tests/types/tillrec.nim +++ b/tests/types/tillrec.nim @@ -11,6 +11,6 @@ type kids: seq[TLegal] TIllegal {.final.} = object #ERROR_MSG illegal recursion in type 'TIllegal' - y: Int + y: int x: array[0..3, TIllegal] diff --git a/tests/usingstmt/tusingstatement.nim b/tests/usingstmt/tusingstatement.nim index a33aced4c..b58478d74 100644 --- a/tests/usingstmt/tusingstatement.nim +++ b/tests/usingstmt/tusingstatement.nim @@ -9,7 +9,7 @@ import # This macro mimics the using statement from C# # # It's kept only as a test for the macro system -# Nimrod's destructors offer a mechanism for automatic +# Nim's destructors offer a mechanism for automatic # disposal of resources. # macro autoClose(e: expr): stmt {.immediate.} = diff --git a/tests/varstmt/tlet.nim b/tests/varstmt/tlet.nim index ba355c5d8..138f34433 100644 --- a/tests/varstmt/tlet.nim +++ b/tests/varstmt/tlet.nim @@ -10,7 +10,7 @@ proc main = elif name == "name": echo("Very funny, your name is name.") else: - Echo("Hi, ", name, "!") + echo("Hi, ", name, "!") let (x, y) = ("abc", name) echo y, x diff --git a/tests/vm/tasmparser.nim b/tests/vm/tasmparser.nim new file mode 100644 index 000000000..67313c858 --- /dev/null +++ b/tests/vm/tasmparser.nim @@ -0,0 +1,174 @@ + +# bug #1513 + +import os, parseutils, strutils, ropes, macros + +var + code {.compileTime.} = "" + start {.compileTime.} = 0 + line {.compileTime.} = 1 + cpp {.compileTime.} = "" + token {.compileTime.} = "" + +proc log (msg: string) {.compileTime.} = + echo msg + +proc asmx64 () {.compileTime} = + + #log "code = $1" % code + + const asmx64pre = "{.emit: \"\"\"{x64asm& x= *x64asm_ptr(`asm0`); try {" + const asmx64post = "} catch (Xbyak::Error e) { printf (\"asmx64 error: %s\\n\", e.what ()); }}\"\"\".} " + + const xp = "x." + + const symbolStart = { '_', 'a'..'z', 'A' .. 'Z' } + const symbol = { '0'..'9' } + symbolStart + const eolComment = { ';' } + const endOfLine = { '\l', '\r' } + const leadingWhiteSpace = { ' ' } + + const end_or_comment = endOfLine + eolComment + { '\0' } + + const passthrough_start = { '{', '`' } + const passthrough_end = { '}', '`', '\0' } + + const end_or_symbol_or_comment_or_passthrough = symbolStart + end_or_comment + passthrough_start + + + proc abortAsmParse (err:string) = + discard + + let codeLen = code.len + #let codeEnd = codeLen-1 + cpp.add asmx64pre + + #log "{$1}\n" % [code] + + type asmParseState = enum leading, mnemonic, betweenArguments, arguments, endCmd, skipToEndOfLine + + var state:asmParseState = leading + + proc checkEnd (err:string) = + let ch = code [start] + if int (ch) == 0: + abortAsmParse (err) + + proc get_passthrough () = + inc start + let prev_start = start + let prev_token = token + start += code.parseUntil (token, passthrough_end, start) + checkEnd ("Failed to find passthrough end delimiter from offset $1 for:$2\n$3" % [$prev_start, $(code [prev_start-prev_token.len..prev_start]), token[1..token.len-1]]) + inc start + cpp.add "`" + cpp.add token + cpp.add "`" + + var inparse = true + + proc checkCmdEnd () = + if codeLen == start: + state = endCmd + inparse = false + + while inparse: + checkCmdEnd () + + log ("state=$1 start=$2" % [$state, $start]) + + case state: + of leading: + + echo "b100 ", start + start += code.skipWhile (leadingWhiteSpace, start) + echo "b200 ", start + let ch = code [start] + if ch in endOfLine: + inc (line) + #echo "c100 ", start, ' ', code + start += code.skipWhile (endOfline, start) + #echo "c200 ", start, ' ', code + continue + elif ch in symbolStart: + state = mnemonic + elif ch in eolComment: + state = skipToEndOfLine + elif ch in passthrough_start: + get_passthrough () + echo "d100 ", start + start += code.parseUntil (token, end_or_symbol_or_comment_or_passthrough, start) + echo "d200 ", start + cpp.add token + state = mnemonic + elif int (ch) == 0: + break + else: + abortAsmParse ("after '$3' illegal character at offset $1: $2" % [$start, $(int (ch)), token]) + + of mnemonic: + echo "e100 ", start + start += code.parseWhile (token, symbol, start) + echo "e200 ", start + cpp.add xp + cpp.add token + cpp.add "(" + state = betweenArguments + + of betweenArguments: + let tmp = start + let rcode = code + start += rcode.parseUntil (token, end_or_symbol_or_comment_or_passthrough, tmp) + cpp.add token + + if codeLen <= start: + state = endCmd + continue + + let ch = code [start] + if ch in passthrough_start: + get_passthrough () + continue + if (ch in {'x', 'X'}) and ('0' == code [start-1]): + token = $(code [start]) + cpp.add token + inc start + continue + state = arguments + + of arguments: + if code [start] in end_or_comment: + state = endCmd + continue + start += code.parseWhile (token, symbol, start) + cpp.add xp + cpp.add token + state = betweenArguments + + of endCmd: + cpp.add ");\n" + state = skipToEndOfLine + + of skipToEndOfLine: + echo "a100 ", start + start += code.skipUntil (endOfLine, start) + echo "a200 ", start + start += code.skipWhile (endOfline, start) + echo "a300 ", start + inc line + state = leading + + cpp.add asmx64post + + echo ($cpp) + +macro asmx64x (code_in:expr) : stmt = + code = $code_in + echo ("code.len = $1, code = >>>$2<<<" % [$code.len, code]) + asmx64 () + discard result + +asmx64x """ + mov rax, {m} + ret +""" diff --git a/tests/vm/tcompiletimetable.nim b/tests/vm/tcompiletimetable.nim index f1d3ecd4e..df6ead56f 100644 --- a/tests/vm/tcompiletimetable.nim +++ b/tests/vm/tcompiletimetable.nim @@ -2,18 +2,19 @@ discard """ msg: '''2 3 4:2 - ''' +Got Hi +Got Hey''' """ # bug #404 -import macros, tables +import macros, tables, strtabs var ZOOT{.compileTime.} = initTable[int, int](2) var iii {.compiletime.} = 1 macro zoo:stmt= - zoot[iii] = iii*2 + ZOOT[iii] = iii*2 inc iii echo iii @@ -29,9 +30,7 @@ tupleUnpack # bug #903 -import strtabs - -var x {.compileTime.}: PStringTable +var x {.compileTime.}: StringTableRef macro addStuff(stuff, body: expr): stmt {.immediate.} = result = newNimNode(nnkStmtList) diff --git a/tests/vm/tconsteval.nim b/tests/vm/tconsteval.nim index 16fd8f4b8..96a1bafe8 100644 --- a/tests/vm/tconsteval.nim +++ b/tests/vm/tconsteval.nim @@ -6,7 +6,7 @@ import strutils const HelpText = """ +-----------------------------------------------------------------+ -| Maintenance program for Nimrod | +| Maintenance program for Nim | | Version $1| | (c) 2012 Andreas Rumpf | +-----------------------------------------------------------------+ @@ -19,13 +19,13 @@ Options: --help, -h shows this help and quits Possible Commands: boot [options] bootstraps with given command line options - clean cleans Nimrod project; removes generated files + clean cleans Nim project; removes generated files web generates the website csource [options] builds the C sources for installation zip builds the installation ZIP package inno builds the Inno Setup installer -""" % [NimrodVersion & repeatChar(44-len(NimrodVersion)), +""" % [NimVersion & repeatChar(44-len(NimVersion)), CompileDate, CompileTime] -echo helpText +echo HelpText diff --git a/tests/vm/trgba.nim b/tests/vm/trgba.nim index b1d94702f..22eec4d6e 100644 --- a/tests/vm/trgba.nim +++ b/tests/vm/trgba.nim @@ -6,20 +6,20 @@ discard """ #bug #1009 type - TAggRgba8* = array[4, Byte] + TAggRgba8* = array[4, byte] -template R*(self: TAggRgba8): Byte = self[0] -template G*(self: TAggRgba8): Byte = self[1] -template B*(self: TAggRgba8): Byte = self[2] -template A*(self: TAggRgba8): Byte = self[3] +template R*(self: TAggRgba8): byte = self[0] +template G*(self: TAggRgba8): byte = self[1] +template B*(self: TAggRgba8): byte = self[2] +template A*(self: TAggRgba8): byte = self[3] -template `R=`*(self: TAggRgba8, val: Byte) = +template `R=`*(self: TAggRgba8, val: byte) = self[0] = val -template `G=`*(self: TAggRgba8, val: Byte) = +template `G=`*(self: TAggRgba8, val: byte) = self[1] = val -template `B=`*(self: TAggRgba8, val: Byte) = +template `B=`*(self: TAggRgba8, val: byte) = self[2] = val -template `A=`*(self: TAggRgba8, val: Byte) = +template `A=`*(self: TAggRgba8, val: byte) = self[3] = val proc ABGR* (val: int| int64): TAggRgba8 = diff --git a/todo.txt b/todo.txt index d8085226d..1e01793de 100644 --- a/todo.txt +++ b/todo.txt @@ -1,18 +1,21 @@ +version 0.10 +============ + +- fix the bug that keeps 'defer' template from working +- Test nimfix on various babel packages + + version 0.9.6 ============= -- scopes are still broken for generic instantiation! -- implicit deref for parameter matching +- split idetools into separate tool +- split docgen into separate tool Concurrency ----------- -- 'deepCopy' needs to be instantiated for - generics *when the type is constructed* -- test 'deepCopy' -- overloading of '='; general lift mechanism +- test 'deepCopy' for closures -- the disjoint checker needs to deal with 'a = spawn f(); g = spawn f()' - implement 'foo[1..4] = spawn(f[4..7])' - document the new 'spawn' and 'parallel' statements @@ -20,20 +23,15 @@ 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 -- implement lock levels --> first without the more complex race avoidance Misc ---- -- fix the bug that keeps 'defer' template from working - make '--implicitStatic:on' the default -- fix the tuple unpacking in lambda bug - make tuple unpacking work in a non-var/let context -- special rule for ``[]=`` +- special rule for ``[]=``, items, pairs - built-in 'getImpl' -- type API for macros; make 'spawn' a macro -- markAndSweepGC should expose an API for fibers - prevent 'alloc(TypeWithGCedMemory)' - some table related tests are wrong (memory usage checks) @@ -41,102 +39,47 @@ Misc Bugs ==== -- bug: 'type T = ref T' not recognized as illegal recursion +- VM: Pegs do not work at compile-time +- VM: ptr/ref T cannot work in general +- scopes are still broken for generic instantiation! - bug: type conversions concerning proc types are weird - compilation of niminst takes way too long. looks like a regression - docgen: sometimes effects are listed twice -- 'result' is not properly cleaned for NRVO --> use uninit checking instead - blocks can "export" an identifier but the CCG generates {} for them ... version 0.9.x ============= + +- implicit deref for parameter matching +- overloading of '=' +- allow simple read accesses to global variables --> difficult to ensure that + no data races happen - pragmas need 'bindSym' support - pragmas need re-work: 'push' is dangerous, 'hasPragma' does not work reliably with user-defined pragmas - memory manager: add a measure of fragmentation - implement 'bits' pragmas - we need a magic thisModule symbol -- provide --nilChecks:on|off - ensure (ref T)(a, b) works as a type conversion and type constructor - optimize 'genericReset'; 'newException' leads to code bloat -- stack-less GC version 0.9.X ============= - macros as type pragmas +- implement type API for macros - lazy overloading resolution: * special case ``tyStmt`` -- FFI: - * test: times.format with the FFI - document NimMain and check whether it works for threading -- 'quote' without 'do' doesn't work: parser/grammar issue; could be supported - - -version 0.9.X -============= - -- implement the missing features wrt inheritance -- better support for macros that rewrite procs -- macros need access to types and symbols (partially implemented) -- enforce 'simpleExpr' more often --> doesn't work; tkProc is - part of primary! -- the typeDesc/expr unification is weird and only necessary because of - the ambiguous a[T] construct: It would be easy to support a[expr] for - generics but require a[.typeDesc] if that's required; this would also - allow [.ref T.](x) for a more general type conversion construct; for - templates that would work too: T([.ref int]) - - -Concurrency/Effect system -========================= - -- shared memory heap: ``shared ref`` etc. The only hard part in the GC is to - "stop the world". However, it may be worthwhile to generate explicit - (or implicit) syncGC() calls in loops. Automatic loop injection seems - troublesome, but maybe we can come up with a simple heuristic. (All procs - that `new` shared memory are syncGC() candidates... But then 'new' itself - calls syncGC() so that's pointless.) Hm instead of an heuristic simply - provide a ``syncgc`` pragma to trigger compiler injection --> more general: - an ``injectLoop`` pragma -- 'writes: []' effect; track reads/writes for shared types -- use the effect system for static deadlock prevention and race detection -- ``~`` operator for effects -- introduce 'noaddr' pragma to prevent taking the address of a location; this - is very handy to prevent aliasing of global data - - -version 0.9.XX -============== - -- make 'clamp' a magic for the range stuff -- better type syntax for functions and tuples: tuple(int, int); (int,int)->int - - -Memory safety -============= - -- object branch transitions from low(selector) are unsafe! ---> Needs a - deprecation path -- object branch transitions can't work with the current 'reset'; add a 'reset' - with an additional parameter --> simple: - provide a 'reset(x, TObj(k: nkValue))' instead? why bother? '=' does the - same. -- returning 'var T' is unsafe and needs some static analysis - GC == -- precise stack marking; embrace C++ code generation for that -- marker procs for Boehm GC - hybrid GC -- acyclic vs prunable; introduce GC hints - use big blocks in the allocator -- object pooling support for *hard* realtime systems - provide tool/API to track leaks/object counts - resizing of strings/sequences could take into account the memory that is allocated @@ -147,33 +90,3 @@ CGEN - codegen should use "NIM_CAST" macro and respect aliasing rules for GCC - ``restrict`` pragma + backend support - 'const' objects including case objects - - -Not essential for 1.0.0 -======================= - -- allow implicit forward declarations of procs via a pragma (so that the - wrappers can deactivate it): better solution: introduce the notion of a - 'proc section' that is similar to a type section. -- implement the "snoopResult" pragma; no, make a strutils with string append - semantics instead ... -- implement "closure tuple consists of a single 'ref'" optimization -- new feature: ``distinct T with operations`` -- arglist as a type (iterator chaining); variable length type lists for generics -- implement marker procs for message passing -- implement closures that support nesting of *procs* > 1 -- object constructors: static check for fields if discriminator is known at - compile time -- prove array accesses - - -Optimizations -============= - -- optimize 'if' with a constant condition --> necessary in frontend for better - dead code elimination; also necessary to prevent ``if c > 0: 1 div c`` -- escape analysis for string/seq seems to be easy to do too; - even further write barrier specialization -- inlining of first class functions -- proc specialization in the code gen for write barrier specialization -- VM/optimizer: implement on the fly CSE diff --git a/tools/cmerge.nim b/tools/cmerge.nim index 003b0e555..d2e540481 100644 --- a/tools/cmerge.nim +++ b/tools/cmerge.nim @@ -3,10 +3,10 @@ import os, sets, pegs type - TProcessResult = enum prSkipIncludeDir, prAddIncludeDir + ProcessResult = enum prSkipIncludeDir, prAddIncludeDir -proc process(dir, infile: string, outfile: TFile, - processed: var TSet[string]): TProcessResult = +proc process(dir, infile: string, outfile: File, + processed: var HashSet[string]): ProcessResult = if processed.containsOrIncl(infile): return prSkipIncludeDir let toProcess = dir / infile if not existsFile(toProcess): @@ -24,7 +24,7 @@ proc process(dir, infile: string, outfile: TFile, writeln(outfile, line) proc main(dir, outfile: string) = - var o: TFile + var o: File if open(o, outfile, fmWrite): var processed = initSet[string]() processed.incl(outfile) diff --git a/tools/detect/detect.nim b/tools/detect/detect.nim index 87b682ad5..77efdaacd 100644 --- a/tools/detect/detect.nim +++ b/tools/detect/detect.nim @@ -1,8 +1,8 @@ # Posix detect program # (c) 2010 Andreas Rumpf -# This program produces a C program that produces a Nimrod include file. -# The Nimrod include file lists the values of each POSIX constant. +# This program produces a C program that produces a Nim include file. +# The Nim include file lists the values of each POSIX constant. # This is needed because POSIX is brain-dead: It only cares for C, any other # language is ignored. It would have been easier had they specified the # concrete values of the constants. Sigh. diff --git a/tools/nimgrep.nim b/tools/nimgrep.nim index 28d92402e..a38f2a88f 100644 --- a/tools/nimgrep.nim +++ b/tools/nimgrep.nim @@ -1,6 +1,6 @@ # # -# Nimrod Grep Utility +# Nim Grep Utility # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this @@ -12,7 +12,7 @@ import const Version = "0.9" - Usage = "nimgrep - Nimrod Grep Utility Version " & version & """ + Usage = "nimgrep - Nim Grep Utility Version " & Version & """ (c) 2012 Andreas Rumpf Usage: @@ -58,7 +58,7 @@ proc ask(msg: string): string = stdout.write(msg) result = stdin.readLine() -proc Confirm: TConfirmEnum = +proc confirm: TConfirmEnum = while true: case normalize(ask(" [a]bort; [y]es, a[l]l, [n]o, non[e]: ")) of "a", "abort": return ceAbort @@ -81,20 +81,20 @@ proc countLines(s: string, first, last: int): int = proc beforePattern(s: string, first: int): int = result = first-1 while result >= 0: - if s[result] in newlines: break + if s[result] in NewLines: break dec(result) inc(result) proc afterPattern(s: string, last: int): int = result = last+1 while result < s.len: - if s[result] in newlines: break + if s[result] in NewLines: break inc(result) dec(result) proc writeColored(s: string) = if useWriteStyled: - terminal.WriteStyled(s, {styleUnderscore, styleBright}) + terminal.writeStyled(s, {styleUnderscore, styleBright}) else: stdout.write(s) @@ -125,12 +125,12 @@ proc processFile(filename: string) = var buffer: string try: buffer = system.readFile(filename) - except EIO: + except IOError: echo "cannot open file: ", filename return if optVerbose in options: stdout.writeln(filename) var pegp: TPeg - var rep: TRegex + var rep: Regex var result: string if optRegex in options: @@ -171,7 +171,7 @@ proc processFile(filename: string) = r = replace(wholeMatch, rep, replacement % matches) if optConfirm in options: highlight(buffer, wholeMatch, r, t, line, showRepl=true) - case Confirm() + case confirm() of ceAbort: quit(0) of ceYes: reallyReplace = true of ceAll: @@ -194,7 +194,7 @@ proc processFile(filename: string) = i = t.last+1 if optReplace in options: result.add(substr(buffer, i)) - var f: TFile + var f: File if open(f, filename, fmWrite): f.write(result) f.close() @@ -234,8 +234,8 @@ proc styleInsensitive(s: string): string = while s[i] != '>' and s[i] != '\0': addx() of '\\': addx() - if s[i] in strutils.digits: - while s[i] in strutils.digits: addx() + if s[i] in strutils.Digits: + while s[i] in strutils.Digits: addx() else: addx() else: addx() @@ -267,7 +267,7 @@ proc checkOptions(subset: TOptions, a, b: string) = for kind, key, val in getopt(): case kind of cmdArgument: - if options.contains(optStdIn): + if options.contains(optStdin): filenames.add(key) elif pattern.len == 0: pattern = key @@ -275,7 +275,7 @@ for kind, key, val in getopt(): replacement = key else: filenames.add(key) - of cmdLongOption, cmdShortOption: + of cmdLongoption, cmdShortOption: case normalize(key) of "find", "f": incl(options, optFind) of "replace", "r": incl(options, optReplace) diff --git a/tools/nimgrep.nimrod.cfg b/tools/nimgrep.nim.cfg index 6d0ea5aad..6d0ea5aad 100644 --- a/tools/nimgrep.nimrod.cfg +++ b/tools/nimgrep.nim.cfg diff --git a/tools/niminst/debcreation.nim b/tools/niminst/debcreation.nim index 1f4a8630e..574f7ea6b 100644 --- a/tools/niminst/debcreation.nim +++ b/tools/niminst/debcreation.nim @@ -1,6 +1,6 @@ # # -# The Nimrod Installation Generator +# The Nim Installation Generator # (c) Copyright 2012 Dominik Picheta # # See the file "copying.txt", included in this @@ -104,7 +104,7 @@ proc createChangelog(pkgName, version, maintainer: string): string = formatDateTime(getGMTime(getTime()), "+0000")) proc createRules(): string = - ## Creates a nimrod application-agnostic rules file for building deb packages. + ## Creates a nim application-agnostic rules file for building deb packages. ## Please note: this assumes the c sources have been built and the ## ``build.sh`` and ``install.sh`` files are available. result = "" @@ -131,9 +131,9 @@ proc createDotInstall(pkgName: string, binaries, config, docs, for c in config: addN(pkgName / c & " " & "etc/") for d in docs: - addN(pkgName / d & " " & "usr/share/doc/nimrod/") + addN(pkgName / d & " " & "usr/share/doc/nim/") for l1 in lib: - addN(pkgName / l1 & " " & "usr/lib/nimrod") + addN(pkgName / l1 & " " & "usr/lib/nim") proc makeMtn(name, email: string): string = return name & " <" & email & ">" @@ -145,7 +145,7 @@ proc prepDeb*(packName, version, mtnName, mtnEmail, shortDesc, desc: string, licenses: seq[tuple[files, license: string]], binaries, config, docs, lib: seq[string], buildDepends, pkgDepends = "") = - ## binaries/config/docs/lib: files relative to nimrod's root, that need to + ## binaries/config/docs/lib: files relative to nim's root, that need to ## be installed. let pkgName = packName.toLower() @@ -212,24 +212,24 @@ proc prepDeb*(packName, version, mtnName, mtnEmail, shortDesc, desc: string, echo("And execute `debuild -us -uc` to build the .deb") when isMainModule: - #var controlFile = createControl("nimrod", "Dominik Picheta <morfeusz8@gmail.com>", - # "The Nimrod compiler", "Compiler for the Nimrod programming language", "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)") + #var controlFile = createControl("nim", "Dominik Picheta <morfeusz8@gmail.com>", + # "The Nim compiler", "Compiler for the Nim programming language", "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)") #echo(controlFile) - #var copyrightFile = createCopyright("nimrod", "Dominik Picheta", "morfeusz8@a.b", "0.8.14", - # @[("bin/nimrod", "gpl2"), ("lib/*", "lgpl")]) + #var copyrightFile = createCopyright("nim", "Dominik Picheta", "morfeusz8@a.b", "0.8.14", + # @[("bin/nim", "gpl2"), ("lib/*", "lgpl")]) #echo copyrightFile - #var changelogFile = createChangelog("nimrod", "0.8.14", "Dom P <m@b.c>") + #var changelogFile = createChangelog("nim", "0.8.14", "Dom P <m@b.c>") #echo(changelogFile) #echo(createRules()) - prepDeb("nimrod", "0.9.2", "Dominik Picheta", "morfeusz8@gmail.com", - "The Nimrod compiler", "Compiler for the Nimrod programming language", - @[("bin/nimrod", "MIT"), ("lib/*", "MIT")], - @["bin/nimrod"], @["config/*"], @["doc/*"], @["lib/*"], + prepDeb("nim", "0.9.2", "Dominik Picheta", "morfeusz8@gmail.com", + "The Nim compiler", "Compiler for the Nim programming language", + @[("bin/nim", "MIT"), ("lib/*", "MIT")], + @["bin/nim"], @["config/*"], @["doc/*"], @["lib/*"], "gcc (>= 4:4.3.2)", "gcc (>= 4:4.3.2)") diff --git a/tools/niminst/niminst.nim b/tools/niminst/niminst.nim index bf8a7a84f..686a0bfa3 100644 --- a/tools/niminst/niminst.nim +++ b/tools/niminst/niminst.nim @@ -1,7 +1,7 @@ # # -# The Nimrod Installation Generator -# (c) Copyright 2013 Andreas Rumpf +# The Nim Installation Generator +# (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -60,7 +60,7 @@ type explicitPlatforms: bool vars: PStringTable app: TAppType - nimrodArgs: string + nimArgs: string debOpts: TDebOptions const @@ -85,7 +85,7 @@ proc initConfigData(c: var TConfigData) = c.license = "" c.infile = "" c.outdir = "" - c.nimrodArgs = "" + c.nimArgs = "" c.libpath = "" c.innoSetupFlag = false c.installScript = false @@ -126,7 +126,7 @@ include "deinstall.tmpl" const Version = "0.9" - Usage = "niminst - Nimrod Installation Generator Version " & Version & """ + Usage = "niminst - Nim Installation Generator Version " & Version & """ (c) 2013 Andreas Rumpf Usage: @@ -166,7 +166,7 @@ proc parseCmdLine(c: var TConfigData) = else: quit(Usage) else: c.infile = addFileExt(key.string, "ini") - c.nimrodArgs = cmdLineRest(p).string + c.nimArgs = cmdLineRest(p).string break of cmdLongoption, cmdShortOption: case normalize(key.string) @@ -451,14 +451,14 @@ proc srcdist(c: var TConfigData) = var dir = getOutputDir(c) / buildDir(osA, cpuA) if existsDir(dir): removeDir(dir) createDir(dir) - var cmd = ("nimrod compile -f --symbolfiles:off --compileonly " & + var cmd = ("nim compile -f --symbolfiles:off --compileonly " & "--gen_mapping --cc:gcc --skipUserCfg" & " --os:$# --cpu:$# $# $#") % - [osname, cpuname, c.nimrodArgs, + [osname, cpuname, c.nimArgs, changeFileExt(c.infile, "nim")] echo(cmd) if execShellCmd(cmd) != 0: - quit("Error: call to nimrod compiler failed") + quit("Error: call to nim compiler failed") readCFiles(c, osA, cpuA) for i in 0 .. c.cfiles[osA][cpuA].len-1: let dest = dir / extractFilename(c.cfiles[osA][cpuA][i]) diff --git a/tools/nimrepl.nim b/tools/nimrepl.nim index 4b6379bd5..0c9f94616 100644 --- a/tools/nimrepl.nim +++ b/tools/nimrepl.nim @@ -1,6 +1,6 @@ # # -# Nimrod REPL +# Nim REPL # (c) Copyright 2012 Dominik Picheta # # See the file "copying.txt", included in this @@ -14,8 +14,8 @@ when defined(tinyc): else: const runCmd = "c -r" -var nimExe = findExe("nimrod") -if nimExe.len == 0: nimExe = "../bin" / addFileExt("nimrod", os.exeExt) +var nimExe = findExe("nim") +if nimExe.len == 0: nimExe = "../bin" / addFileExt("nim", os.exeExt) proc execCode(code: string): string = var f: TFile @@ -36,7 +36,7 @@ var OutputTextBuffer: PTextBuffer proc destroy(widget: PWidget, data: pgpointer){.cdecl.} = main_quit() -proc FileOpenClicked(menuitem: PMenuItem, userdata: pgpointer) {.cdecl.} = +proc fileOpenClicked(menuitem: PMenuItem, userdata: pgpointer) {.cdecl.} = var path = ChooseFileToOpen(w) if path != "": var file = readFile(path) @@ -45,7 +45,7 @@ proc FileOpenClicked(menuitem: PMenuItem, userdata: pgpointer) {.cdecl.} = else: error(w, "Unable to read from file") -proc FileSaveClicked(menuitem: PMenuItem, userdata: pgpointer) {.cdecl.} = +proc fileSaveClicked(menuitem: PMenuItem, userdata: pgpointer) {.cdecl.} = var path = ChooseFileToSave(w) if path == "": return @@ -115,12 +115,12 @@ proc initControls() = append(FileMenu, OpenMenuItem) show(OpenMenuItem) discard signal_connect(OpenMenuItem, "activate", - SIGNAL_FUNC(FileOpenClicked), nil) + SIGNAL_FUNC(fileOpenClicked), nil) var SaveMenuItem = menu_item_new("Save...") append(FileMenu, SaveMenuItem) show(SaveMenuItem) discard signal_connect(SaveMenuItem, "activate", - SIGNAL_FUNC(FileSaveClicked), nil) + SIGNAL_FUNC(fileSaveClicked), nil) var FileMenuItem = menu_item_new("File") diff --git a/tools/nimweb.nim b/tools/nimweb.nim index d76c5e354..a98a27a13 100644 --- a/tools/nimweb.nim +++ b/tools/nimweb.nim @@ -1,7 +1,7 @@ # # -# Nimrod Website Generator -# (c) Copyright 2012 Andreas Rumpf +# Nim Website Generator +# (c) Copyright 2014 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -13,14 +13,14 @@ import type TKeyValPair = tuple[key, id, val: string] - TConfigData = object of TObject + TConfigData = object of RootObj tabs, links: seq[TKeyValPair] doc, srcdoc, srcdoc2, webdoc, pdf: seq[string] authors, projectName, projectTitle, logo, infile, outdir, ticker: string - vars: PStringTable - nimrodArgs: string + vars: StringTableRef + nimArgs: string gitCommit: string - quotations: TTable[string, tuple[quote, author: string]] + quotations: Table[string, tuple[quote, author: string]] numProcessors: int # Set by parallelBuild:n, only works for values > 0. TRssItem = object year, month, day, title: string @@ -35,7 +35,7 @@ proc initConfigData(c: var TConfigData) = c.pdf = @[] c.infile = "" c.outdir = "" - c.nimrodArgs = "--hint[Conf]:off " + c.nimArgs = "--hint[Conf]:off " c.authors = "" c.projectTitle = "" c.projectName = "" @@ -55,10 +55,10 @@ include "website.tmpl" # ------------------------- configuration file ------------------------------- const - Version = "0.7" - Usage = "nimweb - Nimrod Website Generator Version " & version & """ + version = "0.7" + usage = "nimweb - Nim Website Generator Version " & version & """ - (c) 2012 Andreas Rumpf + (c) 2014 Andreas Rumpf Usage: nimweb [options] ini-file[.ini] [compile_options] Options: @@ -112,30 +112,30 @@ proc parseCmdLine(c: var TConfigData) = case kind of cmdArgument: c.infile = addFileExt(key, "ini") - c.nimrodArgs.add(cmdLineRest(p)) + c.nimArgs.add(cmdLineRest(p)) break of cmdLongOption, cmdShortOption: case normalize(key) of "help", "h": - stdout.write(Usage) + stdout.write(usage) quit(0) of "version", "v": - stdout.write(Version & "\n") + stdout.write(version & "\n") quit(0) of "o", "output": c.outdir = val of "parallelbuild": try: let num = parseInt(val) if num != 0: c.numProcessors = num - except EInvalidValue: + except ValueError: quit("invalid numeric value for --parallelBuild") of "var": var idx = val.find('=') if idx < 0: quit("invalid command line") c.vars[substr(val, 0, idx-1)] = substr(val, idx+1) - else: quit(Usage) + else: quit(usage) of cmdEnd: break - if c.infile.len == 0: quit(Usage) + if c.infile.len == 0: quit(usage) proc walkDirRecursively(s: var seq[string], root, ext: string) = for k, f in walkDir(root): @@ -155,68 +155,65 @@ proc addFiles(s: var seq[string], dir, ext: string, patterns: seq[string]) = proc parseIniFile(c: var TConfigData) = var - p: TCfgParser + p: CfgParser section: string # current section var input = newFileStream(c.infile, fmRead) - if input != nil: - open(p, input, c.infile) - while true: - var k = next(p) - case k.kind - of cfgEof: break - of cfgSectionStart: - section = normalize(k.section) - case section - of "project", "links", "tabs", "ticker", "documentation", "var": discard - else: echo("[Warning] Skipping unknown section: " & section) - - of cfgKeyValuePair: - var v = k.value % c.vars - c.vars[k.key] = v - - case section - of "project": - case normalize(k.key) - of "name": c.projectName = v - of "title": c.projectTitle = v - of "logo": c.logo = v - of "authors": c.authors = v - else: quit(errorStr(p, "unknown variable: " & k.key)) - of "var": discard - of "links": - let valID = v.split(';') - add(c.links, (k.key.replace('_', ' '), valID[1], valID[0])) - of "tabs": add(c.tabs, (k.key, "", v)) - of "ticker": c.ticker = v - of "documentation": - case normalize(k.key) - of "doc": addFiles(c.doc, "doc", ".txt", split(v, {';'})) - of "pdf": addFiles(c.pdf, "doc", ".txt", split(v, {';'})) - of "srcdoc": addFiles(c.srcdoc, "lib", ".nim", split(v, {';'})) - of "srcdoc2": addFiles(c.srcdoc2, "lib", ".nim", split(v, {';'})) - of "webdoc": addFiles(c.webdoc, "lib", ".nim", split(v, {';'})) - of "parallelbuild": - try: - let num = parseInt(v) - if num != 0: c.numProcessors = num - except EInvalidValue: - quit("invalid numeric value for --parallelBuild in config") - else: quit(errorStr(p, "unknown variable: " & k.key)) - of "quotations": - let vSplit = v.split('-') - doAssert vSplit.len == 2 - c.quotations[k.key.normalize] = (vSplit[0], vSplit[1]) - else: discard - - of cfgOption: quit(errorStr(p, "syntax error")) - of cfgError: quit(errorStr(p, k.msg)) - close(p) - if c.projectName.len == 0: - c.projectName = changeFileExt(extractFilename(c.infile), "") - if c.outdir.len == 0: - c.outdir = splitFile(c.infile).dir - else: - quit("cannot open: " & c.infile) + if input == nil: quit("cannot open: " & c.infile) + open(p, input, c.infile) + while true: + var k = next(p) + case k.kind + of cfgEof: break + of cfgSectionStart: + section = normalize(k.section) + case section + of "project", "links", "tabs", "ticker", "documentation", "var": discard + else: echo("[Warning] Skipping unknown section: " & section) + + of cfgKeyValuePair: + var v = k.value % c.vars + c.vars[k.key] = v + + case section + of "project": + case normalize(k.key) + of "name": c.projectName = v + of "title": c.projectTitle = v + of "logo": c.logo = v + of "authors": c.authors = v + else: quit(errorStr(p, "unknown variable: " & k.key)) + of "var": discard + of "links": + let valID = v.split(';') + add(c.links, (k.key.replace('_', ' '), valID[1], valID[0])) + of "tabs": add(c.tabs, (k.key, "", v)) + of "ticker": c.ticker = v + of "documentation": + case normalize(k.key) + of "doc": addFiles(c.doc, "doc", ".txt", split(v, {';'})) + of "pdf": addFiles(c.pdf, "doc", ".txt", split(v, {';'})) + of "srcdoc": addFiles(c.srcdoc, "lib", ".nim", split(v, {';'})) + of "srcdoc2": addFiles(c.srcdoc2, "lib", ".nim", split(v, {';'})) + of "webdoc": addFiles(c.webdoc, "lib", ".nim", split(v, {';'})) + of "parallelbuild": + try: + let num = parseInt(v) + if num != 0: c.numProcessors = num + except ValueError: + quit("invalid numeric value for --parallelBuild in config") + else: quit(errorStr(p, "unknown variable: " & k.key)) + of "quotations": + let vSplit = v.split('-') + doAssert vSplit.len == 2 + c.quotations[k.key.normalize] = (vSplit[0], vSplit[1]) + else: discard + of cfgOption: quit(errorStr(p, "syntax error")) + of cfgError: quit(errorStr(p, k.msg)) + close(p) + if c.projectName.len == 0: + c.projectName = changeFileExt(extractFilename(c.infile), "") + if c.outdir.len == 0: + c.outdir = splitFile(c.infile).dir # Ugly hack to override git command output when building private repo. if c.vars.hasKey("githash"): let githash = c.vars["githash"].strip @@ -238,8 +235,7 @@ proc mexec(cmds: openarray[string], processors: int) = if processors < 2: sexec(cmds) return - - if 0 != execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd}): + if execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd}) != 0: echo "external program failed, retrying serial work queue for logs!" sexec(cmds) @@ -250,10 +246,10 @@ proc buildDocSamples(c: var TConfigData, destPath: string) = ## it didn't make much sense to integrate into the existing generic ## documentation builders. const src = "doc"/"docgen_sample.nim" - exec("nimrod doc $# -o:$# $#" % - [c.nimrodArgs, destPath / "docgen_sample.html", src]) - exec("nimrod doc2 $# -o:$# $#" % - [c.nimrodArgs, destPath / "docgen_sample2.html", src]) + exec("nim doc $# -o:$# $#" % + [c.nimArgs, destPath / "docgen_sample.html", src]) + exec("nim doc2 $# -o:$# $#" % + [c.nimArgs, destPath / "docgen_sample2.html", src]) proc buildDoc(c: var TConfigData, destPath: string) = # call nim for the documentation: @@ -261,30 +257,30 @@ proc buildDoc(c: var TConfigData, destPath: string) = commands = newSeq[string](len(c.doc) + len(c.srcdoc) + len(c.srcdoc2)) i = 0 for d in items(c.doc): - commands[i] = "nimrod rst2html $# --docSeeSrcUrl:$# -o:$# --index:on $#" % - [c.nimrodArgs, c.gitCommit, + commands[i] = "nim rst2html $# --docSeeSrcUrl:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitCommit, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc for d in items(c.srcdoc): - commands[i] = "nimrod doc $# --docSeeSrcUrl:$# -o:$# --index:on $#" % - [c.nimrodArgs, c.gitCommit, + commands[i] = "nim doc $# --docSeeSrcUrl:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitCommit, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc for d in items(c.srcdoc2): - commands[i] = "nimrod doc2 $# --docSeeSrcUrl:$# -o:$# --index:on $#" % - [c.nimrodArgs, c.gitCommit, + commands[i] = "nim doc2 $# --docSeeSrcUrl:$# -o:$# --index:on $#" % + [c.nimArgs, c.gitCommit, destPath / changeFileExt(splitFile(d).name, "html"), d] i.inc mexec(commands, c.numProcessors) - exec("nimrod buildIndex -o:$1/theindex.html $1" % [destPath]) + exec("nim buildIndex -o:$1/theindex.html $1" % [destPath]) proc buildPdfDoc(c: var TConfigData, destPath: string) = if os.execShellCmd("pdflatex -version") != 0: echo "pdflatex not found; no PDF documentation generated" else: for d in items(c.pdf): - exec("nimrod rst2tex $# $#" % [c.nimrodArgs, d]) + exec("nim rst2tex $# $#" % [c.nimArgs, d]) # call LaTeX twice to get cross references right: exec("pdflatex " & changeFileExt(d, "tex")) exec("pdflatex " & changeFileExt(d, "tex")) @@ -302,8 +298,8 @@ 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] = "nimrod doc $# --docSeeSrcUrl:$# -o:$# $#" % - [c.nimrodArgs, c.gitCommit, + commands[i] = "nim doc $# --docSeeSrcUrl:$# -o:$# $#" % + [c.nimArgs, c.gitCommit, destPath / changeFileExt(splitFile(doc).name, "html"), doc] mexec(commands, c.numProcessors) @@ -311,7 +307,7 @@ proc parseNewsTitles(inputFilename: string): seq[TRssItem] = # parses the file for titles and returns them as TRssItem blocks. let reYearMonthDayTitle = re(rYearMonthDayTitle) var - input: TFile + input: File line = "" result = @[] @@ -347,7 +343,7 @@ proc genNewsLink(title: string): string = proc generateRss(outputFilename: string, news: seq[TRssItem]) = # Given a list of rss items generates an rss overwriting destination. var - output: TFile + output: File if not open(output, outputFilename, mode = fmWrite): quit("Could not write to $1 for rss generation" % [outputFilename]) @@ -387,28 +383,28 @@ proc buildNewsRss(c: var TConfigData, destPath: string) = generateRss(destFilename, parseNewsTitles(srcFilename)) proc buildJS(destPath: string) = - exec("nimrod js -d:release --out:$1 web/babelpkglist.nim" % + exec("nim js -d:release --out:$1 web/babelpkglist.nim" % [destPath / "babelpkglist.js"]) proc main(c: var TConfigData) = const - cmd = "nimrod rst2html --compileonly $1 -o:web/$2.temp web/$2.txt" + cmd = "nim rst2html --compileonly $1 -o:web/$2.temp web/$2.txt" if c.ticker.len > 0: try: c.ticker = readFile("web" / c.ticker) - except EIO: + except IOError: quit("[Error] cannot open: " & c.ticker) for i in 0..c.tabs.len-1: var file = c.tabs[i].val let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: "" - exec(cmd % [c.nimrodArgs, file]) + exec(cmd % [c.nimArgs, file]) var temp = "web" / changeFileExt(file, "temp") var content: string try: content = readFile(temp) - except EIO: + except IOError: quit("[Error] cannot open: " & temp) - var f: TFile + var f: File var outfile = "web/upload/$#.html" % file if not existsDir("web/upload"): createDir("web/upload") diff --git a/tools/website.tmpl b/tools/website.tmpl index 1d6242736..f3cacdb64 100644 --- a/tools/website.tmpl +++ b/tools/website.tmpl @@ -80,7 +80,7 @@ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - ga('create', 'UA-48159761-1', 'nimrod-lang.org'); + ga('create', 'UA-48159761-1', 'nim-lang.org'); ga('send', 'pageview'); </script> diff --git a/web/download.txt b/web/download.txt index 557788217..6d860b332 100644 --- a/web/download.txt +++ b/web/download.txt @@ -121,8 +121,8 @@ Bleeding edge binaries are available from the `Nimrod build farm <http://build.n Source ====== -Starting with 0.9.4 we now advise people to build directly from the -github `master <https://github.com/Araq/Nimrod#compiling>`_ branch:: +Use the following commands to build the compiler from source. +Change the branch to suit your needs:: git clone -b master git://github.com/Araq/Nimrod.git cd Nimrod diff --git a/web/news.txt b/web/news.txt index 2d7086be6..ceb23a6dd 100644 --- a/web/news.txt +++ b/web/news.txt @@ -14,8 +14,12 @@ News ``threadpool``. - The symbol binding rules in generics changed: ``bar`` in ``foo.bar`` is now considered for implicit early binding. - - ``c2nim`` moved into its own repository and is now a Babel package. - - ``pas2nim`` moved into its own repository and is now a Babel package. + - ``c2nim`` moved into its own + `repository <https://github.com/nimrod-code/c2nim>`_ + and is now a Nimble package. + - ``pas2nim`` moved into its own + `repository <https://github.com/nimrod-code/pas2nim>`_ + and is now a Nimble package. - ``system.$`` for floating point types now produces a human friendly string representation. - ``uri.TUrl`` as well as the ``parseurl`` module are now deprecated in favour @@ -29,13 +33,49 @@ News - ``--threadanalysis:on`` is now the default. To make your program compile you can disable it but this is only a temporary solution as this option will disappear soon! - + - ``system.fileHandle`` has been renamed to ``system.getFileHandle`` to + prevent name conflicts with the new type ``FileHandle``. + - Comments are now not part of the AST, as such you cannot use them in place + of ``discard``. + - The ``irc`` module has been moved into its own + `repository <https://github.com/nimrod-code/irc>`_ + and is now a Nimble package. + - Many wrappers have been moved into their own repositories and are now + Nimble packages including ``lua``, ``opengl``, ``x11``, ``nim-zmq``, + ``gtk2``, ``mongo``, ``cairo``, ``tcl``, ``python`` and + `more <https://github.com/Araq/Nimrod/issues/623>`_. They can be + found under the `nim-code <https://github.com/nimrod-code>`_ organisation. + - Removed the deprecated ``web`` module, the ``httpclient`` module should + be used instead. + - String case (or any non-ordinal case) statements + without 'else' are deprecated. + - Recursive tuple types are not allowed anymore. Use ``object`` instead. + + + Compiler Additions + ------------------ + + - The compiler now supports *mixed* Objective C / C++ / C code generation: + The modules that use ``importCpp`` or ``importObjc`` are compiled to C++ + or Objective C code, any other module is compiled to C code. This + improves interoperability. + Language Additions ------------------ - There is a new ``parallel`` statement for safe fork&join parallel computing. - + - ``guard`` and ``lock`` pragmas have been implemented to support safer + concurrent programming. + - The following procs are now available at compile-time:: + + math.sqrt, math.ln, math.log10, math.log2, math.exp, math.round, + math.arccos, math.arcsin, math.arctan, math.arctan2, math.cos, math.cosh, + math.hypot, math.sinh, math.sin, math.tan, math.tanh, math.pow, + math.trunc, math.floor, math.ceil, math.fmod, + os.getEnv, os.existsEnv, os.dirExists, os.fileExists, + system.writeFile + Library Additions ----------------- @@ -87,7 +127,7 @@ the use of an ``await`` macro which behaves similar to C#'s await. The following is a very simple chat server demonstrating Nimrod's new async capabilities. -.. code-block::nimrod +.. code-block::nim import asyncnet, asyncdispatch var clients: seq[PAsyncSocket] = @[] @@ -120,7 +160,7 @@ Syntactic sugar for anonymous procedures has also been introduced. It too has been implemented as a macro. The following shows some simple usage of the new syntax: -.. code-block::nimrod +.. code-block::nim import future var s = @[1, 2, 3, 4, 5] diff --git a/web/nimrod.ini b/web/nim.ini index 64376cd66..1bf75e209 100644 --- a/web/nimrod.ini +++ b/web/nim.ini @@ -1,15 +1,15 @@ [Project] -Name: "Nimrod" -Title: "Nimrod Programming Language" +Name: "Nim" +Title: "Nim Programming Language" Logo: "efficient, expressive, elegant" Authors: "Andreas Rumpf and contributors" [Links] # Underscores are replaced with a space. # Everything after ; is the ID -User_Forum: "http://forum.nimrod-code.org;link_forum" +User_Forum: "http://forum.nim-lang.org;link_forum" Aporia_IDE: "https://github.com/nimrod-code/Aporia;link_aporia" -Nimbuild: "http://build.nimrod-code.org;link_nimbuild" +Nimbuild: "http://build.nim-lang.org;link_nimbuild" [Tabs] # Menu entry: filename @@ -36,10 +36,10 @@ UNIX. We don't believe this to be a coincidence. - Jeremy S. Anderson.""" [Documentation] -doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview;filters" +doc: "endb;intern;apis;lib;manual;tut1;tut2;nimc;overview;filters" doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt" -pdf: "manual;lib;tut1;tut2;nimrodc;niminst;gc" -srcdoc2: "system.nim;impure/graphics;wrappers/sdl" +pdf: "manual;lib;tut1;tut2;nimc;niminst;gc" +srcdoc2: "system.nim" srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned" srcdoc2: "impure/re;pure/sockets;pure/typetraits" srcdoc: "system/threads.nim;system/channels.nim;js/dom" @@ -47,7 +47,7 @@ srcdoc2: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm" srcdoc2: "pure/complex;pure/times;pure/osproc;pure/pegs;pure/dynlib" srcdoc2: "pure/parseopt;pure/parseopt2;pure/hashes;pure/strtabs;pure/lexbase" srcdoc2: "pure/parsecfg;pure/parsexml;pure/parsecsv;pure/parsesql" -srcdoc2: "pure/streams;pure/terminal;pure/cgi;impure/web;pure/unicode" +srcdoc2: "pure/streams;pure/terminal;pure/cgi;pure/unicode" srcdoc2: "impure/zipfiles;pure/htmlgen;pure/parseutils;pure/browsers" srcdoc2: "impure/db_postgres;impure/db_mysql;impure/db_sqlite" srcdoc2: "pure/httpserver;pure/httpclient;pure/smtp;impure/ssl;pure/fsmonitor" @@ -67,20 +67,20 @@ srcdoc2: "pure/rawsockets;pure/asynchttpserver;pure/net;pure/selectors;pure/futu srcdoc2: "wrappers/expat;wrappers/readline/history" srcdoc2: "wrappers/libsvm.nim;wrappers/libuv" srcdoc2: "wrappers/zip/zlib;wrappers/zip/libzip" -srcdoc2: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup" +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" -webdoc: "wrappers/libcurl;pure/md5;wrappers/mysql;wrappers/iup" +webdoc: "pure/md5;wrappers/mysql;wrappers/iup" webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc" webdoc: "wrappers/expat;wrappers/pcre" webdoc: "wrappers/tre;wrappers/openssl" webdoc: "wrappers/libuv;wrappers/joyent_http_parser" -webdoc: "posix/posix;wrappers/odbcsql;impure/dialogs" +webdoc: "posix/posix;wrappers/odbcsql" webdoc: "wrappers/zip/zlib;wrappers/zip/libzip" webdoc: "wrappers/libsvm.nim" webdoc: "windows" diff --git a/web/question.txt b/web/question.txt index be90cc67a..e6f4d40a5 100644 --- a/web/question.txt +++ b/web/question.txt @@ -31,8 +31,8 @@ runtime or interpreter. What have been the major influences in the language's design? ------------------------------------------------------------- -The language borrows heavily from: Modula 3, Delphi, Ada, C++, Python, Lisp, -Oberon. As far as possible the list is sorted by the impact of influence. +The language borrows heavily from (in order of impact): Modula 3, Delphi, Ada, +C++, Python, Lisp, Oberon. |