diff options
author | Araq <rumpf_a@web.de> | 2014-08-27 23:42:51 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-08-27 23:42:51 +0200 |
commit | 11b69587554a99deb93ca2447ee3aeeacdb647c5 (patch) | |
tree | c4e580c4b084f85283f7159cb4772c93f9c08a5e | |
parent | 15a7bcc89f43b36da1973b53db3b9e466f9f49f6 (diff) | |
download | Nim-11b69587554a99deb93ca2447ee3aeeacdb647c5.tar.gz |
big rename
98 files changed, 2498 insertions, 2348 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index c5b367977..b6878c56e 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 diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index eeaf53649..9484bbe90 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 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/manual.txt b/doc/manual.txt index d18ede409..10fe78336 100644 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -87,7 +87,7 @@ 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 +.. code-block:: nim var a: array[0..1, char] let i = 5 try: @@ -159,7 +159,7 @@ 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 +.. code-block:: nim i = 0 # This is a single comment over multiple lines belonging to the # assignment statement. The scanner merges these two pieces. @@ -172,7 +172,7 @@ aligned to the preceding one, it does not start a new comment: The alignment requirement does not hold if the preceding comment piece ends in a backslash (followed by optional whitespace): -.. code-block:: nimrod +.. code-block:: nim type TMyObject {.final, pure, acyclic.} = object # comment continues: \ # we have lots of space here to comment 'TMyObject'. @@ -203,7 +203,7 @@ operator characters instead. The following keywords are reserved and cannot be used as identifiers: -.. code-block:: nimrod +.. code-block:: nim :file: keywords.txt Some keywords are unused; they are reserved for future developments of the @@ -268,7 +268,7 @@ 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 +.. code-block:: nim """"long string within quotes"""" Produces:: @@ -286,13 +286,13 @@ 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 +.. 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:: nimrod +.. code-block:: nim r"a""b" @@ -542,7 +542,7 @@ 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 +.. code-block:: nim #! strongSpaces if foo+4 * 4 == 8 and b&c | 9 ++ bar: @@ -554,7 +554,7 @@ is still parsed as ``1 + (3 * 4)``, but ``1+3 * 4`` is parsed as ``(1+3) * 4``: Furthermore whether an operator is used a prefix operator is affected by the number of spaces: -.. code-block:: nimrod +.. code-block:: nim #! strongSpaces echo $foo # is parsed as @@ -563,7 +563,7 @@ number of spaces: This also affects whether ``[]``, ``{}``, ``()`` are parsed as constructors or as accessors: -.. code-block:: nimrod +.. code-block:: nim #! strongSpaces echo (1,2) # is parsed as @@ -689,7 +689,7 @@ 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:: nimrod +.. code-block:: nim var myInt16 = 5i16 var myInt: int myInt16 + 34 # of type ``int16`` @@ -710,7 +710,7 @@ 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 +.. code-block:: nim type TSubrange = range[0..5] @@ -735,7 +735,7 @@ constant *x* so that (x+1) is a number of two. This means that the following code is accepted: -.. code-block:: nimrod +.. code-block:: nim case (x and 3) + 7 of 7: echo "A" of 8: echo "B" @@ -788,7 +788,7 @@ These exceptions inherit from the `EFloatingPoint`: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:: nimrod +.. code-block:: nim {.NanChecks: on, InfChecks: on.} var a = 1.0 var b = 0.0 @@ -819,7 +819,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 @@ -849,7 +849,7 @@ Enumeration types Enumeration types define a new type whose values consist of the ones specified. The values are ordered. Example: -.. code-block:: nimrod +.. code-block:: nim type TDirection = enum @@ -873,7 +873,7 @@ explicitly given is assigned the value of the previous field + 1. An explicit ordered enum can have *holes*: -.. code-block:: nimrod +.. code-block:: nim type TTokenType = enum a = 2, b = 4, c = 89 # holes are valid @@ -887,7 +887,7 @@ 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 +.. code-block:: nim type TMyEnum = enum @@ -904,7 +904,7 @@ 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 +.. code-block:: nim type TMyEnum {.pure.} = enum @@ -927,7 +927,7 @@ 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 +.. code-block:: nim case paramStr(i) of "-v": incl(options, optVerbose) @@ -953,7 +953,7 @@ 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:: nimrod +.. code-block:: nim proc printf(formatstr: cstring) {.importc: "printf", varargs, header: "<stdio.h>".} @@ -966,10 +966,10 @@ 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 +A `$` proc is defined for cstrings that returns a string. Thus to get a nim string from a cstring: -.. code-block:: nimrod +.. code-block:: nim var str: string = "Hello!" var cstr: cstring = s var newstr: string = $cstr @@ -1002,7 +1002,7 @@ A sequence may be passed to a parameter that is of type *open array*. Example: -.. code-block:: nimrod +.. code-block:: nim type TIntArray = array[0..5, int] # an array that is indexed with 0..5 @@ -1051,7 +1051,7 @@ 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 +.. code-block:: nim proc myWriteln(f: TFile, a: varargs[string]) = for s in items(a): write(f, s) @@ -1065,7 +1065,7 @@ 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 +.. code-block:: nim proc myWriteln(f: TFile, a: varargs[string, `$`]) = for s in items(a): write(f, s) @@ -1098,7 +1098,7 @@ 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 +.. code-block:: nim type TPerson = tuple[name: string, age: int] # type representing a person: @@ -1116,7 +1116,7 @@ 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 +.. code-block:: nim type TPerson = tuple # type representing a person name: string # a person consists of a name @@ -1126,7 +1126,7 @@ 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 +.. code-block:: nim type TPerson {.inheritable.} = object name*: string # the * means that `name` is accessible from other modules @@ -1154,7 +1154,7 @@ 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 +.. code-block:: nim var student = TStudent(name: "Anton", age: 5, id: 3) For a ``ref object`` type ``system.new`` is invoked implicitly. @@ -1167,7 +1167,7 @@ variant types are needed. An example: -.. code-block:: nimrod +.. code-block:: nim # This is an example how an abstract syntax tree could be modelled in Nim type @@ -1249,7 +1249,7 @@ 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 @@ -1267,7 +1267,7 @@ 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 +.. code-block:: nim type Node = ref object @@ -1287,7 +1287,7 @@ 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 +.. code-block:: nim type TData = tuple[x, y: int, s: string] @@ -1326,7 +1326,7 @@ 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 +.. code-block:: nim type PObject = ref TObj not nil TProc = (proc (x, y: int)) not nil @@ -1355,7 +1355,7 @@ 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 +.. code-block:: nim type Kernel = object Userspace = object @@ -1377,7 +1377,7 @@ 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 +.. code-block:: nim # from system proc dealloc(p: pointer) @@ -1414,7 +1414,7 @@ types to achieve `functional`:idx: programming techniques. Examples: -.. code-block:: nimrod +.. code-block:: nim proc printItem(x: int) = ... @@ -1424,7 +1424,7 @@ Examples: forEach(printItem) # this will NOT work because calling conventions differ -.. code-block:: nimrod +.. code-block:: nim type TOnMouseMove = proc (x, y: int) {.closure.} @@ -1532,7 +1532,7 @@ 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 +.. code-block:: nim type TDollar = distinct int TEuro = distinct int @@ -1570,7 +1570,7 @@ should not generate all this code only to optimize it away later - after all The pragma `borrow`:idx: has been designed to solve this problem; in principle it generates the above trivial implementations: -.. code-block:: nimrod +.. 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.} @@ -1582,7 +1582,7 @@ 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 +.. code-block:: nim template additive(typ: typedesc): stmt = proc `+` *(x, y: typ): typ {.borrow.} proc `-` *(x, y: typ): typ {.borrow.} @@ -1616,7 +1616,7 @@ currency. This can be solved with templates_. The borrow pragma can also be used to annotate the distinct type to allow certain builtin operations to be lifted: -.. code-block:: nimrod +.. code-block:: nim type Foo = object a, b: int @@ -1640,7 +1640,7 @@ 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:: nimrod +.. code-block:: nim import strutils proc query(db: TDbHandle, statement: string) = ... @@ -1655,7 +1655,7 @@ 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 +.. code-block:: nim type TSQL = distinct string @@ -1672,7 +1672,7 @@ 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 +.. code-block:: nim import strutils, sequtils proc properQuote(s: string): TSQL = @@ -1703,7 +1703,7 @@ 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 +.. code-block:: nim proc nothing(x, y: void): void = echo "ha" @@ -1711,7 +1711,7 @@ the procedure does not return a value: The ``void`` type is particularly useful for generic code: -.. code-block:: nimrod +.. code-block:: nim proc callProc[T](p: proc (x: T), x: T) = when T is void: p() @@ -1726,7 +1726,7 @@ The ``void`` type is particularly useful for generic code: However, a ``void`` type cannot be inferred in generic code: -.. code-block:: nimrod +.. code-block:: nim callProc(emptyProc) # Error: type mismatch: got (proc ()) # but expected one of: @@ -1749,7 +1749,7 @@ 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:: nimrod +.. code-block:: nim proc typeEqualsAux(a, b: PType, s: var set[PType * PType]): bool = if (a,b) in s: return true @@ -1795,7 +1795,7 @@ 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 +.. code-block:: nim proc typeEqualsOrDistinct(a, b: PType): bool = if a.kind == b.kind: case a.kind @@ -1835,7 +1835,7 @@ 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 +.. code-block:: nim proc isSubtype(a, b: PType): bool = if a.kind == b.kind: case a.kind @@ -1854,7 +1854,7 @@ Convertible relation A type ``a`` is **implicitly** convertible to type ``b`` iff the following algorithm returns true: -.. code-block:: nimrod +.. code-block:: nim # XXX range types? proc isImplicitlyConvertible(a, b: PType): bool = case a.kind @@ -1884,7 +1884,7 @@ algorithm returns true: A type ``a`` is **explicitly** convertible to type ``b`` iff the following algorithm returns true: -.. code-block:: nimrod +.. code-block:: nim proc isIntegralType(t: PType): bool = result = isOrdinal(t) or t.kind in {float, float32, float64} @@ -1898,7 +1898,7 @@ algorithm returns true: The convertible relation can be relaxed by a user-defined type `converter`:idx:. -.. code-block:: nimrod +.. code-block:: nim converter toInt(x: char): int = result = ord(x) var @@ -1960,7 +1960,7 @@ Discard statement Example: -.. code-block:: nimrod +.. code-block:: nim proc p(x, y: int): int = result = x + y @@ -1975,7 +1975,7 @@ 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 +.. code-block:: nim proc p(x, y: int): int {.discardable.} = result = x + y @@ -1983,7 +1983,7 @@ been declared with the `discardable`:idx: pragma: An empty ``discard`` statement is often used as a null statement: -.. code-block:: nimrod +.. code-block:: nim proc classify(s: string) = case s[0] of SymChars, '_': echo "an identifier" @@ -1998,7 +1998,7 @@ 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 +.. code-block:: nim var a: int = 0 @@ -2031,14 +2031,14 @@ 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 +.. 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:: nimrod +.. code-block:: nim proc returnUndefinedValue: int {.noinit.} = discard @@ -2047,7 +2047,7 @@ 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 +.. code-block:: nim type TMyObject = object {.requiresInit.} @@ -2082,7 +2082,7 @@ 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:: nimrod +.. code-block:: nim import strutils const constEval = contains("abc", 'b') # computed at compile time! @@ -2128,7 +2128,7 @@ If statement Example: -.. code-block:: nimrod +.. code-block:: nim var name = readLine(stdin) @@ -2152,7 +2152,7 @@ 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 +.. 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): @@ -2168,7 +2168,7 @@ Case statement Example: -.. code-block:: nimrod +.. code-block:: nim case readline(stdin) of "delete-everything", "restart-computer": @@ -2205,7 +2205,7 @@ 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 +.. code-block:: nim const SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'} @@ -2228,7 +2228,7 @@ When statement Example: -.. code-block:: nimrod +.. code-block:: nim when sizeof(int) == 2: echo("running on a 16 bit system!") @@ -2258,14 +2258,14 @@ Return statement Example: -.. code-block:: nimrod +.. 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:: nimrod +.. code-block:: nim result = expr return result @@ -2275,7 +2275,7 @@ 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 +.. code-block:: nim proc returnZero(): int = # implicitly returns 0 @@ -2285,7 +2285,7 @@ Yield statement Example: -.. code-block:: nimrod +.. code-block:: nim yield (1, 2, 3) The ``yield`` statement is used instead of the ``return`` statement in @@ -2301,7 +2301,7 @@ Block statement Example: -.. code-block:: nimrod +.. code-block:: nim var found = false block myblock: for i in 0..3: @@ -2322,7 +2322,7 @@ Break statement Example: -.. code-block:: nimrod +.. code-block:: nim break The ``break`` statement is used to leave a block immediately. If ``symbol`` @@ -2335,7 +2335,7 @@ While statement Example: -.. code-block:: nimrod +.. code-block:: nim echo("Please tell me your password: \n") var pw = readLine(stdin) while pw != "12345": @@ -2355,7 +2355,7 @@ 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 +.. code-block:: nim while expr1: stmt1 continue @@ -2363,7 +2363,7 @@ statement is syntactic sugar for a nested block: Is equivalent to: -.. code-block:: nimrod +.. code-block:: nim while expr1: block myBlockName: stmt1 @@ -2379,7 +2379,7 @@ 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:: nimrod +.. code-block:: nim {.push stackTrace:off.} proc addInt(a, b: int): int = # a in eax, and b in edx @@ -2394,7 +2394,7 @@ specified in the statement's pragmas. The default special character is ``'`'``: If the GNU assembler is used, quotes and newlines are inserted automatically: -.. code-block:: nimrod +.. code-block:: nim proc addInt(a, b: int): int = asm """ addl %%ecx, %%eax @@ -2407,7 +2407,7 @@ If the GNU assembler is used, quotes and newlines are inserted automatically: Instead of: -.. code-block:: nimrod +.. code-block:: nim proc addInt(a, b: int): int = asm """ "addl %%ecx, %%eax\n" @@ -2430,7 +2430,7 @@ 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 +.. code-block:: nim var s = socket() using s @@ -2447,7 +2447,7 @@ 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 +.. code-block:: nim import windows, sdl using sdl.SetTimer @@ -2456,7 +2456,7 @@ 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 +.. code-block:: nim var a, b = "kill it" using a add(" with fire") @@ -2476,7 +2476,7 @@ If expression An `if expression` is almost like an if statement, but it is an expression. Example: -.. code-block:: nimrod +.. code-block:: nim var y = if x > 8: 9 else: 10 An if expression always results in a value, so the ``else`` part is @@ -2492,7 +2492,7 @@ Case expression The `case expression` is again very similar to the case statement: -.. code-block:: nimrod +.. code-block:: nim var favoriteFood = case animal of "dog": "bones" of "cat": "mice" @@ -2510,7 +2510,7 @@ Table constructor A table constructor is syntactic sugar for an array constructor: -.. code-block:: nimrod +.. code-block:: nim {"key1": "value1", "key2", "key3": "value2"} # is the same as: @@ -2545,7 +2545,7 @@ Type casts ---------- Example: -.. code-block:: nimrod +.. code-block:: nim cast[int](x) Type casts are a crude mechanism to interpret the bit pattern of @@ -2563,7 +2563,7 @@ 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 +.. code-block:: nim let t1 = "Hello" var @@ -2594,7 +2594,7 @@ 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 +.. code-block:: nim proc toLower(c: Char): Char = # toLower for characters if c in {'A'..'Z'}: @@ -2609,7 +2609,7 @@ the best match for the arguments. Example: Calling a procedure can be done in many different ways: -.. code-block:: nimrod +.. code-block:: nim proc callme(x, y: int, s: string = "", c: char, b: bool = false) = ... # call with positional arguments # parameter bindings: @@ -2627,7 +2627,7 @@ A procedure cannot modify its parameters (unless the parameters have the type `Operators`:idx: are procedures with a special operator symbol as identifier: -.. code-block:: nimrod +.. code-block:: nim proc `$` (x: int): string = # converts an integer to a string; this is a prefix operator. result = intToStr(x) @@ -2641,7 +2641,7 @@ 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 +.. code-block:: nim proc `*+` (a, b, c: int): int = # Multiply and add result = a * b + c @@ -2659,7 +2659,7 @@ 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 +.. code-block:: nim echo("abc".len) # is the same as echo(len("abc")) echo("abc".toUpper()) @@ -2676,7 +2676,7 @@ 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 @@ -2707,7 +2707,7 @@ 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 +.. code-block:: nim proc optarg(x:int, y:int = 0):int = x + y proc singlearg(x:int):int = 20*x @@ -2744,7 +2744,7 @@ Anonymous Procs Procs can also be treated as expressions, in which case it's allowed to omit the proc's name. -.. code-block:: nimrod +.. code-block:: nim var cities = @["Frankfurt", "Tokyo", "New York"] cities.sort(proc (x,y: string): int = @@ -2761,7 +2761,7 @@ Do notation As a special more convenient notation, proc expressions involved in procedure calls can use the ``do`` keyword: -.. code-block:: nimrod +.. code-block:: nim sort(cities) do (x,y: string) -> int: cmp(x.len, y.len) # Less parenthesis using the method plus command syntax: @@ -2773,7 +2773,7 @@ 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 +.. code-block:: nim proc performWithUndo(task: proc(), undo: proc()) = ... performWithUndo do: @@ -2806,7 +2806,7 @@ Var parameters -------------- The type of a parameter may be prefixed with the ``var`` keyword: -.. code-block:: nimrod +.. code-block:: nim proc divmod(a, b: int; res, remainder: var int) = res = a div b remainder = a mod b @@ -2824,7 +2824,7 @@ 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 +.. code-block:: nim proc divmod(a, b: int; res, remainder: ptr int) = res[] = a div b remainder[] = a mod b @@ -2838,7 +2838,7 @@ above example is equivalent to: 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 +.. code-block:: nim proc divmod(a, b: int): tuple[res, remainder: int] = (a div b, a mod b) @@ -2849,7 +2849,7 @@ return values. This can be done in a cleaner way by returning a tuple: One can use `tuple unpacking`:idx: to access the tuple's fields: -.. code-block:: nimrod +.. code-block:: nim var (x, y) = divmod(8, 5) # tuple unpacking assert x == 1 assert y == 3 @@ -2861,7 +2861,7 @@ 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 +.. code-block:: nim var g = 0 proc WriteAccessToG(): var int = @@ -2873,14 +2873,14 @@ returned value is an l-value and can be modified by the caller: It is a compile time error if the implicitly introduced pointer could be used to access a location beyond its lifetime: -.. code-block:: nimrod +.. 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:: nimrod +.. 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]) @@ -2901,7 +2901,7 @@ Multi-methods Procedures always use static dispatch. Multi-methods use dynamic dispatch. -.. code-block:: nimrod +.. code-block:: nim type TExpr = object ## abstract base class for an expression TLiteral = object of TExpr @@ -2937,7 +2937,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 TUnit = object of TThing @@ -2987,7 +2987,7 @@ 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 +.. code-block:: nim # this definition exists in the system module iterator items*(a: string): char {.inline.} = var i = 0 @@ -3000,7 +3000,7 @@ state are automatically saved between calls. Example: The compiler generates code as if the programmer would have written this: -.. code-block:: nimrod +.. code-block:: nim var i = 0 while i < len(a): var ch = a[i] @@ -3019,7 +3019,7 @@ 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 +.. code-block:: nim for x in [1,2,3]: echo x If the for loop has exactly 2 variables, a ``pairs`` iterator is implicitly @@ -3042,7 +3042,7 @@ templates, macros and other inline iterators. In contrast to that, a `closure iterator`:idx: can be passed around more freely: -.. code-block:: nimrod +.. code-block:: nim iterator count0(): int {.closure.} = yield 0 @@ -3073,7 +3073,7 @@ 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 +.. code-block:: nim # simple tasking: type TTask = iterator (ticker: int) @@ -3112,7 +3112,7 @@ 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 +.. code-block:: nim proc mycount(a, b: int): iterator (): int = result = iterator (): int = var x = a @@ -3139,7 +3139,7 @@ Type sections Example: -.. code-block:: nimrod +.. code-block:: nim type # example demonstrating mutually recursive types PNode = ref TNode # a traced pointer to a TNode TNode = object @@ -3166,7 +3166,7 @@ Try statement Example: -.. 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 @@ -3214,7 +3214,7 @@ Except and finally statements Any statements following them in the current block will be considered to be in an implicit try block: -.. code-block:: nimrod +.. code-block:: nim var f = open("numbers.txt") finally: close(f) ... @@ -3224,7 +3224,7 @@ 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 +.. code-block:: nim proc test() = raise newException(E_base, "Hey ho") @@ -3242,7 +3242,7 @@ Raise statement Example: -.. code-block:: nimrod +.. code-block:: nim raise newEOS("operating system failed") Apart from built-in operations like array indexing, memory allocation, etc. @@ -3265,7 +3265,7 @@ called within the ``try`` statement that should be affected. This allows for a Lisp-like `condition system`:idx:\: -.. code-block:: nimrod +.. code-block:: nim var myFile = open("broken.txt", fmWrite) try: onRaise do (e: ref E_Base)-> bool: @@ -3294,14 +3294,14 @@ 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:: nimrod +.. code-block:: nim 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 +.. code-block:: nim proc p(): bool {.raises: [].} = try: unsafeCall() @@ -3313,7 +3313,7 @@ An empty ``raises`` list (``raises: []``) means that no exception may be raised: A ``raises`` list can also be attached to a proc type. This affects type compatibility: -.. code-block:: nimrod +.. code-block:: nim type TCallback = proc (s: string) {.raises: [EIO].} var @@ -3348,7 +3348,7 @@ possibly raised exceptions; the algorithm operates on ``p``'s call graph: Rules 1-2 ensure the following works: -.. code-block:: nimrod +.. code-block:: nim proc noRaise(x: proc()) {.raises: [].} = # unknown call that might raise anything, but valid: x() @@ -3371,7 +3371,7 @@ 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:: nimrod +.. code-block:: nim type IO = object ## input/output effect proc readLine(): string {.tags: [IO].} @@ -3402,7 +3402,7 @@ 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 +.. code-block:: nim proc p(what: bool) = if what: raise newException(EIO, "IO") @@ -3419,7 +3419,7 @@ Generics Example: -.. code-block:: nimrod +.. code-block:: nim type TBinaryTree[T] = object # TBinaryTree is a generic type with # with generic param ``T`` @@ -3478,7 +3478,7 @@ 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 +.. code-block:: nim type TTable[TKey, TValue] = object keys: seq[TKey] @@ -3493,7 +3493,7 @@ 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 +.. code-block:: nim var x = 0 var y: type(x) # y has type int @@ -3502,7 +3502,7 @@ 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 +.. code-block:: nim import strutils # strutils contains both a ``split`` proc and iterator, but since an @@ -3541,7 +3541,7 @@ 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 +.. code-block:: nim # create a type class that will match all tuple and object types type TRecordType = tuple or object @@ -3556,7 +3556,7 @@ 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:: nimrod +.. code-block:: nim proc onlyIntOrString[T: int|string](x, y: T) = discard onlyIntOrString(450, 616) # valid @@ -3567,7 +3567,7 @@ 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 +.. 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 @@ -3582,7 +3582,7 @@ 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:: nimrod +.. code-block:: nim # allow any combination of param types proc concat(a, b): string = $a & $b @@ -3590,7 +3590,7 @@ 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 +.. code-block:: nim type TMatrix[T, Rows, Columns] = object ... @@ -3603,7 +3603,7 @@ 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 +.. code-block:: nim seq[ref object] # Any sequence storing references to any object type type T1 = auto @@ -3630,7 +3630,7 @@ matched type must satisfy. Declarative type classes are written in the following form: -.. code-block:: nimrod +.. code-block:: nim type Comparable = generic x, y (x < y) is bool @@ -3661,7 +3661,7 @@ 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 +.. code-block:: nim type OutputStream = generic S write(var S, string) @@ -3678,7 +3678,7 @@ 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:: nimrod +.. code-block:: nim proc makePair(a, b): auto = (first: a, second: b) The return type will be treated as additional generic param and can be @@ -3700,7 +3700,7 @@ 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 +.. code-block:: nim type TIndex = distinct int @@ -3719,7 +3719,7 @@ too. A symbol can be forced to be open by a `mixin`:idx: declaration: -.. code-block:: nimrod +.. 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: @@ -3736,7 +3736,7 @@ 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 +.. code-block:: nim # Module A var lastId = 0 @@ -3746,7 +3746,7 @@ definition): inc(lastId) lastId -.. code-block:: nimrod +.. code-block:: nim # Module B import A @@ -3767,7 +3767,7 @@ The syntax to *invoke* a template is the same as calling a procedure. Example: -.. code-block:: nimrod +.. code-block:: nim template `!=` (a, b: expr): expr = # this definition exists in the System module not (a == b) @@ -3796,7 +3796,7 @@ 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 +.. code-block:: nim template declareInt(x: expr) = var x: int @@ -3807,7 +3807,7 @@ 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 +.. code-block:: nim template declareInt(x: expr) {.immediate.} = var x: int @@ -3822,7 +3822,7 @@ 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 +.. code-block:: nim template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} = var f: TFile @@ -3848,7 +3848,7 @@ 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 +.. code-block:: nim # Module A var lastId = 0 @@ -3857,7 +3857,7 @@ bound from the definition scope of the template: inc(lastId) lastId -.. code-block:: nimrod +.. code-block:: nim # Module B import A @@ -3873,7 +3873,7 @@ Identifier construction In templates identifiers can be constructed with the backticks notation: -.. code-block:: nimrod +.. code-block:: nim template typedef(name: expr, typ: typedesc) {.immediate.} = type @@ -3894,7 +3894,7 @@ 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 +.. code-block:: nim # module 'm' type @@ -3911,7 +3911,7 @@ shadowed by the same argument name even when fully qualified: But the global symbol can properly be captured by a ``bind`` statement: -.. code-block:: nimrod +.. code-block:: nim # module 'm' type @@ -3934,7 +3934,7 @@ 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 +.. code-block:: nim template newException*(exceptn: typedesc, message: string): expr = var @@ -3957,7 +3957,7 @@ 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 +.. 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 @@ -3971,7 +3971,7 @@ template parameter, it is an inject'ed symbol: 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 +.. code-block:: nim {.pragma myInject: inject.} template t() = @@ -4008,7 +4008,7 @@ Expression Macros The following example implements a powerful ``debug`` command that accepts a variable number of arguments: -.. code-block:: nimrod +.. code-block:: nim # to work with Nim syntax trees, we need an API that is defined in the # ``macros`` module: import macros @@ -4037,7 +4037,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]) @@ -4065,7 +4065,7 @@ 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 +.. code-block:: nim import macros macro debug(n: varargs[expr]): stmt = @@ -4086,7 +4086,7 @@ builtin can be used for that: The macro call expands to: -.. code-block:: nimrod +.. code-block:: nim write(stdout, "a[0]") write(stdout, ": ") writeln(stdout, a[0]) @@ -4113,7 +4113,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 import macros macro case_token(n: stmt): stmt = @@ -4147,14 +4147,14 @@ 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 +.. code-block:: nim template m(s: stmt) = discard proc p() {.m.} = discard This is a simple syntactic transformation into: -.. code-block:: nimrod +.. code-block:: nim template m(s: stmt) = discard m: @@ -4171,7 +4171,7 @@ static[T] As their name suggests, static params must be known at compile-time: -.. code-block:: nimrod +.. code-block:: nim proc precompiledRegex(pattern: static[string]): TRegEx = var res {.global.} = re(pattern) @@ -4193,7 +4193,7 @@ 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 +.. 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: @@ -4206,7 +4206,7 @@ predicate: Static params can also appear in the signatures of generic types: -.. code-block:: nimrod +.. code-block:: nim type Matrix[M,N: static[int]; T: Number] = array[0..(M*N - 1), T] @@ -4231,7 +4231,7 @@ 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 +.. code-block:: nim proc new(T: typedesc): ref T = echo "allocating ", T.name @@ -4244,7 +4244,7 @@ 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 +.. code-block:: nim # `type1` and `type2` are aliases for typedesc available from system.nim proc acceptOnlyTypePairs(A, B: type1; C, D: type2) @@ -4252,7 +4252,7 @@ one can use a named alias or an explicit `typedesc` generic param: Once bound, typedesc params can appear in the rest of the proc signature: -.. code-block:: nimrod +.. code-block:: nim template declareVariableWithType(T: typedesc, value: T) = var x: T = value @@ -4266,7 +4266,7 @@ 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 +.. code-block:: nim macro safePrintF(formatString: string{lit}, args: varargs[expr]): expr = var i = 0 for c in formatChars(formatString): @@ -4295,7 +4295,7 @@ a type-safe wrapper for the unsafe `printf` function from C: Overload resolution can be further influenced by constraining the set of types that will match the typedesc param: -.. code-block:: nimrod +.. code-block:: nim template maxval(T: typedesc[int]): int = high(int) template maxval(T: typedesc[float]): float = Inf @@ -4326,14 +4326,14 @@ 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 +.. 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:: nimrod +.. code-block:: nim proc `.` (js: PJsonNode, field: string): JSON = js[field] var js = parseJson("{ x: 1, y: 2}") @@ -4357,7 +4357,7 @@ operator `.=` ------------- This operator will be matched against assignments to missing fields. -.. code-block:: nimrod +.. code-block:: nim a.b = c # becomes `.=`(a, "b", c) @@ -4408,7 +4408,7 @@ 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 +.. code-block:: nim type TMyObj = object x, y: int @@ -4460,7 +4460,7 @@ language may weaken this restriction.) The signature has to be: -.. code-block:: nimrod +.. code-block:: nim proc deepCopy(x: T): T {.override.} This mechanism is used by most data structures that support shared memory like @@ -4478,7 +4478,7 @@ 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 +.. code-block:: nim template optMul{`*`(a, 2)}(a: int): int = a+a let x = 3 @@ -4494,7 +4494,7 @@ needs to be used. Unfortunately optimizations are hard to get right and even the tiny example is **wrong**: -.. code-block:: nimrod +.. code-block:: nim template optMul{`*`(a, 2)}(a: int): int = a+a proc f(): int = @@ -4506,7 +4506,7 @@ is **wrong**: We cannot duplicate 'a' if it denotes an expression that has a side effect! Fortunately Nim supports side effect analysis: -.. code-block:: nimrod +.. code-block:: nim template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a proc f(): int = @@ -4519,12 +4519,12 @@ 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 +.. code-block:: nim template mulIsCommutative{`*`(a, b)}(a, b: int): int = b*a What optimizers really need to do is a *canonicalization*: -.. code-block:: nimrod +.. 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 @@ -4581,7 +4581,7 @@ 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 +.. 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 @@ -4600,7 +4600,7 @@ The ``|`` operator The ``|`` operator if used as infix operator creates an ordered choice: -.. code-block:: nimrod +.. code-block:: nim template t{0|1}(): expr = 3 let a = 1 # outputs 3: @@ -4609,7 +4609,7 @@ The ``|`` operator if used as infix operator creates an ordered choice: The matching is performed after the compiler performed some optimizations like constant folding, so the following does not work: -.. code-block:: nimrod +.. code-block:: nim template t{0|1}(): expr = 3 # outputs 1: echo 1 @@ -4626,7 +4626,7 @@ The ``{}`` operator A pattern expression can be bound to a pattern parameter via the ``expr{param}`` notation: -.. code-block:: nimrod +.. code-block:: nim template t{(0|1|2){x}}(x: expr): expr = x+1 let a = 1 # outputs 2: @@ -4638,7 +4638,7 @@ The ``~`` operator The ``~`` operator is the **not** operator in patterns: -.. code-block:: nimrod +.. code-block:: nim template t{x = (~x){y} and (~x){z}}(x, y, z: bool): stmt = x = y if x: x = z @@ -4657,7 +4657,7 @@ The ``*`` operator The ``*`` operator can *flatten* a nested binary expression like ``a & b & c`` to ``&(a, b, c)``: -.. code-block:: nimrod +.. code-block:: nim var calls = 0 @@ -4681,7 +4681,7 @@ 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 +.. code-block:: nim `&&`("my", space & "awe", "some ", "concat") @@ -4691,7 +4691,7 @@ 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 +.. code-block:: nim import macros type @@ -4735,7 +4735,7 @@ 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 +.. code-block:: nim template optWrite{ write(f, x) ((write|writeln){w})(f, y) @@ -4750,7 +4750,7 @@ Example: Partial evaluation The following example shows how some simple partial evaluation can be implemented with term rewriting: -.. code-block:: nimrod +.. code-block:: nim proc p(x, y: int; cond: bool): int = result = if cond: x + y else: x - y @@ -4763,7 +4763,7 @@ Example: Hoisting The following example shows how some form of hoisting can be implemented: -.. code-block:: nimrod +.. code-block:: nim import pegs template optPeg{peg(pattern)}(pattern: string{lit}): TPeg = @@ -4786,7 +4786,7 @@ AST based overloading Parameter constraints can also be used for ordinary routine parameters; these constraints affect ordinary overloading resolution then: -.. code-block:: nimrod +.. code-block:: nim proc optLit(a: string{lit|`const`}) = echo "string literal" proc optLit(a: string) = @@ -4812,7 +4812,7 @@ Move optimization The ``call`` constraint is particularly useful to implement a move optimization for types that have copying semantics: -.. code-block:: nimrod +.. 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: @@ -4852,7 +4852,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`` @@ -4864,7 +4864,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. @@ -4881,7 +4881,7 @@ 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 +.. code-block:: nim import strutils except `%` # doesn't work then: @@ -4893,7 +4893,7 @@ Module names in imports A module alias can be introduced via the ``as`` keyword: -.. code-block:: nimrod +.. code-block:: nim import strutils as su, sequtils as qu echo su.format("$1", "lalelu") @@ -4902,19 +4902,19 @@ 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 +.. 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:: nimrod +.. 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:: nimrod +.. code-block:: nim import lib.pure.strutils as strutils @@ -4925,7 +4925,7 @@ 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 +.. code-block:: nim from strutils import `%` echo "$1" % "abc" @@ -4943,11 +4943,11 @@ 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 +.. code-block:: nim # module B type TMyObject* = object -.. code-block:: nimrod +.. code-block:: nim # module A import B export B.TMyObject @@ -4955,7 +4955,7 @@ modules don't need to import a module's dependencies: proc `$`*(x: TMyObject): string = "my object" -.. code-block:: nimrod +.. code-block:: nim # module C import A @@ -5002,15 +5002,15 @@ 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 +.. 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 @@ -5056,7 +5056,7 @@ routines marked as ``noSideEffect``. **Future directions**: ``func`` may become a keyword and syntactic sugar for a proc with no side effects: -.. code-block:: nimrod +.. code-block:: nim func `+` (x, y: int): int @@ -5097,7 +5097,7 @@ 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 +.. code-block:: nim type PNode = ref TNode TNode {.acyclic, final.} = object @@ -5114,7 +5114,7 @@ memory, but nothing worse happens. **Future directions**: The ``acyclic`` pragma may become a property of a ``ref`` type: -.. code-block:: nimrod +.. code-block:: nim type PNode = acyclic ref TNode TNode = object @@ -5137,7 +5137,7 @@ 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:: nimrod +.. code-block:: nim type TNodeKind = enum nkLeaf, nkInner TNode {.final, shallow.} = object @@ -5177,7 +5177,7 @@ 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 +.. code-block:: nim ## check that underlying int values are compared and not the pointers: proc `==`(x, y: ptr int): bool {.error.} @@ -5188,7 +5188,7 @@ 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 +.. code-block:: nim when not defined(objc): {.fatal: "Compile this program with the objc command!".} @@ -5207,7 +5207,7 @@ line pragma The ``line`` pragma can be used to affect line information of the annotated statement as seen in stack backtraces: -.. code-block:: nimrod +.. code-block:: nim template myassert*(cond: expr, msg = "") = if not cond: @@ -5226,7 +5226,7 @@ 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:: nimrod +.. code-block:: nim case myInt of 0: echo "most common case" @@ -5254,7 +5254,7 @@ 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:: nimrod +.. code-block:: nim type MyEnum = enum @@ -5298,7 +5298,7 @@ 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 +.. code-block:: nim proc searchChar(s: string, c: char): int = for i in 0 .. s.high: {.unroll: 4.} @@ -5354,7 +5354,7 @@ callconv cdecl|... Specifies the default calling convention for Example: -.. code-block:: nimrod +.. code-block:: nim {.checks: off, optimization: speed.} # compile without runtime checks and optimize for speed @@ -5364,7 +5364,7 @@ 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 +.. code-block:: nim {.push checks: off.} # compile this section without runtime checks as it is # speed critical @@ -5389,7 +5389,7 @@ 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 +.. code-block:: nim proc isHexNumber(s: string): bool = var pattern {.global.} = re"[0-9a-fA-F]+" result = s.match(pattern) @@ -5413,7 +5413,7 @@ no matter if it is globally active or not. Example: -.. code-block:: nimrod +.. code-block:: nim {.deadCodeElim: on.} @@ -5448,11 +5448,11 @@ Example: 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. + ``nim check`` provides this option as well. Example: - .. code-block:: nimrod + .. code-block:: nim {.noforward: on.} @@ -5475,7 +5475,7 @@ They cannot be imported from a module. Example: -.. code-block:: nimrod +.. code-block:: nim when appType == "lib": {.pragma: rtl, exportc, dynlib, cdecl.} else: @@ -5522,9 +5522,9 @@ spelled*: 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 +the `ImportCpp pragma <nimc.html#importcpp-pragma>`_ and interfacing with Objective-C the `ImportObjC pragma -<nimrodc.html#importobjc-pragma>`_ can be used. +<nimc.html#importobjc-pragma>`_ can be used. Exportc pragma @@ -5559,7 +5559,7 @@ 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 +.. code-block:: nim type TVector {.bycopy, pure.} = object x, y, z: float @@ -5614,7 +5614,7 @@ 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 +.. code-block:: nim type ArrayPart{.unchecked.} = array[0..0, int] MySeq = object @@ -5658,7 +5658,7 @@ packages need to be installed. The ``dynlib`` import mechanism supports a versioning scheme: -.. code-block:: nimrod +.. 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)".} @@ -5676,7 +5676,7 @@ At runtime the dynamic library is searched for (in this order):: The ``dynlib`` pragma supports not only constant strings as argument but also string expressions in general: -.. code-block:: nimrod +.. code-block:: nim import os proc getDllName: string = @@ -5778,7 +5778,7 @@ Threadvar pragma A global variable can be marked with the ``threadvar`` pragma; it is a `thread-local`:idx: variable then: -.. code-block:: nimrod +.. code-block:: nim var checkpoints* {.threadvar.}: seq[string] Due to implementation restrictions thread local variables cannot be @@ -5801,7 +5801,7 @@ Nim 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 +.. code-block:: nim proc processLine(line: string) = # do some heavy lifting here: discard @@ -5836,7 +5836,7 @@ 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 +.. code-block:: nim echo "your name: " var name: TaintedString = stdin.readline # it is safe here to output the name without any input validation, so @@ -5845,4 +5845,3 @@ validation errors: If the taint mode is turned off, ``TaintedString`` is simply an alias for ``string``. - diff --git a/doc/pegdocs.txt b/doc/pegdocs.txt index eb7f4562f..e2f3cdf4b 100644 --- a/doc/pegdocs.txt +++ b/doc/pegdocs.txt @@ -180,7 +180,7 @@ 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 s =~ peg" y'while'" @@ -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/tut1.txt b/doc/tut1.txt index ee642ce17..73d90b008 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,30 +37,30 @@ 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 @@ -70,11 +70,11 @@ compiler knows that `readLine <system.html#readLine,TFile>`_ 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. @@ -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. @@ -115,7 +115,7 @@ 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 +.. code-block:: nim i = 0 # This is a single comment over multiple lines belonging to the # assignment statement. @@ -128,7 +128,7 @@ comments need to be aligned at the same column: The alignment requirement does not hold if the preceding comment piece ends in a backslash: -.. code-block:: nimrod +.. code-block:: nim type TMyObject {.final, pure, acyclic.} = object # comment continues: \ # we have lots of space here to comment 'TMyObject'. @@ -151,15 +151,15 @@ the syntax, watch their indentation: **Note**: To comment out a large piece of code, it is often better to use a ``when false:`` statement. -.. code-block:: nimrod +.. code-block:: nim when false: brokenCode() Another option is to 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 +204,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 +229,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 +277,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 +298,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 +317,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 +333,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}") @@ -355,7 +355,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 +375,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 +387,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 +397,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 +417,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 +426,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 +440,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 +461,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 +473,7 @@ When statement Example: -.. code-block:: nimrod +.. code-block:: nim when system.hostOS == "windows": echo("running on Windows!") @@ -504,17 +504,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 +535,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 +548,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) @@ -558,10 +558,10 @@ 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 +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 +597,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 +624,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 +633,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 +653,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 +681,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 +693,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 +706,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 +723,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 +735,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 +744,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 +764,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 +772,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 +783,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 +810,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 +818,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 +831,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 +868,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 +876,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 +885,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 +900,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 +929,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 +964,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 +972,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 +1001,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 +1013,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 +1023,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 +1041,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 +1050,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 +1066,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 +1104,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 +1119,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 +1134,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 +1149,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 +1175,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 +1200,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 +1239,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 +1261,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,7 +1299,7 @@ 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 +.. code-block:: nim proc myWriteln(f: TFile, a: varargs[string]) = for s in items(a): write(f, s) @@ -1313,7 +1313,7 @@ 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 +.. code-block:: nim proc myWriteln(f: TFile, a: varargs[string, `$`]) = for s in items(a): write(f, s) @@ -1336,10 +1336,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 +1366,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 +1411,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 +1431,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 +1449,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 +1464,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 +1489,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 +1513,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 +1554,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 +1565,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 +1581,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 +1602,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 +1627,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 +1638,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 +1660,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 +1672,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 +1683,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..8cd977a96 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,7 +126,7 @@ 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 @@ -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 @@ -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,7 +345,7 @@ evaluation or dead code elimination do not work with methods. Exceptions ========== -In Nimrod exceptions are objects. By convention, exception types are +In Nim exceptions are objects. By convention, exception types are prefixed with an 'E', not 'T'. 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. @@ -364,7 +364,7 @@ Raise statement --------------- Raising an exception is done with the ``raise`` statement: -.. code-block:: nimrod +.. code-block:: nim var e: ref EOS new(e) @@ -375,7 +375,7 @@ 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 +.. code-block:: nim raise newException(EOS, "the request to the OS failed") @@ -384,7 +384,7 @@ 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 @@ -428,7 +428,7 @@ If you need to *access* the actual exception object or message inside an <system.html#getCurrentExceptionMsg>`_ procs from the `system <system.html>`_ module. Example: -.. code-block:: nimrod +.. code-block:: nim try: doSomethingHere() except: @@ -460,7 +460,7 @@ 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 prevent that proc from compiling. Usage example: -.. code-block:: nimrod +.. code-block:: nim proc complexProc() {.raises: [EIO, EArithmetic].} = ... @@ -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,32 +618,11 @@ 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, body: stmt): stmt {.immediate.} = @@ -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,7 +763,7 @@ 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 @@ -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 = @@ -893,13 +872,13 @@ this limitation by using the ``slurp`` proc from the `system module ``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. +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/htmlrefs.nim b/examples/htmlrefs.nim index 8b668325f..6be28d1ca 100644 --- a/examples/htmlrefs.nim +++ b/examples/htmlrefs.nim @@ -15,7 +15,7 @@ var links = 0 # count the number of links 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: 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/lib/pure/actors.nim b/lib/pure/actors.nim index 2d902debe..8a8d8b51b 100644 --- a/lib/pure/actors.nim +++ b/lib/pure/actors.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,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/algorithm.nim b/lib/pure/algorithm.nim index df94c9eb5..b27ccb93c 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,9 +10,12 @@ ## This module implements some common generic algorithms. type - TSortOrder* = enum ## sort order + SortOrder* = enum ## sort order Descending, Ascending +{.deprecated: [TSortOrder: SortOrder].} + + proc `*`*(x: int, order: TSortOrder): int {.inline.} = ## flips `x` if ``order == Descending``; ## if ``order == Ascending`` then `x` is returned. diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 5dfcf4656..194c6ee1b 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,7 +13,7 @@ import os, oids, tables, strutils, macros, times import rawsockets, net -export TPort, TSocketFlags +export Port, SocketFlags #{.injectStmt: newGcInvariant().} @@ -36,21 +36,24 @@ export TPort, TSocketFlags # -- Futures type - PFutureBase* = ref object of PObject + FutureBase* = ref object of RootObj cb: proc () {.closure,gcsafe.} finished: bool - error*: ref EBase + error*: ref Exception errorStackTrace*: string when not defined(release): stackTrace: string ## For debugging purposes only. id: int fromProc: string - PFuture*[T] = ref object of PFutureBase + Future*[T] = ref object of FutureBase value: T +{.deprecated: [PFutureBase: FutureBase, PFuture: Future].} + + var currentID* = 0 -proc newFuture*[T](fromProc: string = "unspecified"): PFuture[T] = +proc newFuture*[T](fromProc: string = "unspecified"): Future[T] = ## Creates a new future. ## ## Specifying ``fromProc``, which is a string specifying the name of the proc @@ -63,7 +66,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) @@ -76,7 +79,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) @@ -86,7 +89,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) @@ -95,7 +98,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) @@ -111,8 +114,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. @@ -123,23 +127,23 @@ 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.") -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. ## @@ -154,22 +158,22 @@ proc read*[T](future: PFuture[T]): T = # TODO: Make a custom exception type for this? raise newException(EInvalidValue, "Future still in progress.") -proc readError*[T](future: PFuture[T]): ref EBase = +proc readError*[T](future: Future[T]): ref EBase = if future.error != nil: return future.error else: raise newException(EInvalidValue, "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 -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. ## @@ -180,7 +184,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]() @@ -192,7 +196,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]() @@ -203,7 +207,7 @@ proc `or`*[T, Y](fut1: PFuture[T], fut2: PFuture[Y]): PFuture[void] = type PDispatcherBase = ref object of PObject - timers: seq[tuple[finishAt: float, fut: PFuture[void]]] + timers: seq[tuple[finishAt: float, fut: Future[void]]] proc processTimers(p: PDispatcherBase) = var oldTimers = p.timers @@ -375,10 +379,10 @@ when defined(windows) or defined(nimdoc): RemoteSockaddr, RemoteSockaddrLength) proc connect*(socket: TAsyncFD, address: string, port: TPort, - af = AF_INET): PFuture[void] = + 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") @@ -437,7 +441,7 @@ when defined(windows) or defined(nimdoc): return retFuture proc recv*(socket: TAsyncFD, size: int, - flags = {TSocketFlags.SafeDisconn}): PFuture[string] = + flags = {TSocketFlags.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 @@ -525,7 +529,7 @@ when defined(windows) or defined(nimdoc): return retFuture proc send*(socket: TAsyncFD, data: string, - flags = {TSocketFlags.SafeDisconn}): PFuture[void] = + flags = {TSocketFlags.SafeDisconn}): Future[void] = ## Sends ``data`` to ``socket``. The returned future will complete once all ## data has been sent. verifyPresence(socket) @@ -568,7 +572,7 @@ when defined(windows) or defined(nimdoc): return retFuture proc acceptAddr*(socket: TAsyncFD, flags = {TSocketFlags.SafeDisconn}): - PFuture[tuple[address: string, client: TAsyncFD]] = + 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. @@ -789,7 +793,7 @@ else: 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 = @@ -824,7 +828,7 @@ 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) @@ -855,7 +859,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 @@ -887,7 +891,7 @@ 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 = @@ -912,7 +916,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") @@ -921,14 +925,14 @@ proc sleepAsync*(ms: int): PFuture[void] = return retFuture proc accept*(socket: TAsyncFD, - flags = {TSocketFlags.SafeDisconn}): PFuture[TAsyncFD] = + flags = {TSocketFlags.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) @@ -1111,12 +1115,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 @@ -1137,7 +1141,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) @@ -1153,7 +1157,7 @@ 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) @@ -1176,8 +1180,8 @@ 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 @@ -1185,7 +1189,7 @@ macro async*(prc: stmt): stmt {.immediate.} = #if prc[0].getName == "processClient": # 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. ## diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim index 26e3a2a7b..54d0b1b8e 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 @@ -13,7 +13,7 @@ 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 +22,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 +33,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 = diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim index 6b67bf4b5..54aa19079 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,29 +76,29 @@ 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, FD_SET, 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, FD_SET, FD_ISSET, select type - TDelegate* = object - fd*: TSocketHandle - deleVal*: PObject + DelegateObj* = object + fd*: SocketHandle + deleVal*: RootRef handleRead*: proc (h: PObject) {.nimcall, gcsafe.} handleWrite*: proc (h: PObject) {.nimcall, gcsafe.} @@ -107,18 +107,18 @@ type open*: bool task*: proc (h: PObject) {.nimcall, gcsafe.} - mode*: TFileMode + mode*: FileMode - PDelegate* = ref TDelegate + Delegate* = ref DelegateObj - PDispatcher* = ref TDispatcher - TDispatcher = object + Dispatcher* = ref DispatcherObj + DispatcherObj = object delegates: seq[PDelegate] - 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.} @@ -134,10 +134,17 @@ type proto: TProtocol deleg: PDelegate - TInfo* = enum + SocketStatus* = enum SockIdle, SockConnecting, SockConnected, SockListening, SockClosed, SockUDPBound +{.deprecated: [TDelegate: DelegateObj, PDelegate: Delegate, + TProcessOption: ProcessOption, + TInfo: SocketStatus, PAsyncSocket: AsyncSocket, TAsyncSocket: AsyncSocketObj, + TDispatcher: DispatcherObj, PDispatcher: Dispatcher, + ].} + + proc newDelegate*(): PDelegate = ## Creates a new delegate. new(result) diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim index 5095d9461..ecaf0b9f9 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 @@ -19,9 +19,9 @@ ## ## import asyncnet, asyncdispatch ## -## var clients: seq[PAsyncSocket] = @[] +## var clients: seq[AsyncSocket] = @[] ## -## proc processClient(client: PAsyncSocket) {.async.} = +## proc processClient(client: AsyncSocket) {.async.} = ## while true: ## let line = await client.recvLine() ## for c in clients: @@ -29,7 +29,7 @@ ## ## proc serve() {.async.} = ## var server = newAsyncSocket() -## server.bindAddr(TPort(12345)) +## server.bindAddr(Port(12345)) ## server.listen() ## ## while true: @@ -54,8 +54,10 @@ 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 {.borrow: `.`.} = distinct TSocketImpl + AsyncSocket* = ref AsyncSocketDesc + +{.deprecated: [PAsyncSocket: AsyncSocket].} # TODO: Save AF, domain etc info and reuse it in procs which need it like connect. diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim index 7b3b0e6f5..3d3cea25c 100644 --- a/lib/pure/base64.nim +++ b/lib/pure/base64.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/pure/basic2d.nim b/lib/pure/basic2d.nim index f8391a368..40f59db74 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 diff --git a/lib/pure/basic3d.nim b/lib/pure/basic3d.nim index 540d53fd9..47856e11d 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 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 0d3231b93..bb7934faa 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 ## @@ -93,12 +93,14 @@ proc XMLencode*(s: string): string = for i in 0..len(s)-1: addXmlChar(result, s[i]) type - ECgi* = object of IOError ## 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].} + proc cgiError*(msg: string) {.noreturn.} = ## raises an ECgi exception with message `msg`. var e: ref ECgi @@ -377,7 +379,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. diff --git a/lib/pure/collections/LockFreeHash.nim b/lib/pure/collections/LockFreeHash.nim index b94b542ff..57beb83c9 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 -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..678c428c1 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) diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim index b8f8d20b5..b7ca5a7af 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,58 @@ 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].} + +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 +105,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,33 +148,33 @@ 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() @@ -300,5 +306,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..9d22f0c3c 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"] @@ -69,7 +69,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 +104,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 +155,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 +169,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 +184,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 +202,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 +223,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 +254,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 +273,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 +292,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 +318,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 +354,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 +384,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 +401,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 +412,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 +503,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 +516,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 3adf21a25..1201241f1 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,17 +24,19 @@ 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 +{.deprecated: [TSet: HashSet].} + proc isValid*[A](s: TSet[A]): bool = ## Returns `true` if the set has been initialized with `initSet <#initSet>`_. ## @@ -43,7 +45,7 @@ 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! @@ -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] 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 @@ -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] + var options: HashSet[string] proc savePreferences(options: TSet[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] + var cards: OrderedSet[string] proc saveTarotCards(cards: TOrderedSet[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 diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim index 95caf9195..320d54111 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,13 +61,15 @@ 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.} @@ -158,12 +160,12 @@ 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 KeyValuePairSeq[A, B], key: A, val: B) = rawInsertImpl() proc enlarge[A, B](t: var TTable[A, B]) = - var n: TKeyValuePairSeq[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) @@ -347,14 +349,16 @@ 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.} = ## returns the number of keys in `t`. @@ -608,11 +612,13 @@ 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 = ## returns the number of keys in `t`. 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..d31d56f83 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,9 +25,11 @@ const type - TComplex* = tuple[re, im: float] + Complex* = tuple[re, im: float] ## a complex number, consisting of a real and an imaginary part +{.deprecated: [TComplex: Complex].} + proc `==` *(x, y: TComplex): bool = ## Compare two complex numbers `x` and `y` for equality. result = x.re == y.re and x.im == y.im 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..dfde610f2 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.".} diff --git a/lib/pure/cookies.nim b/lib/pure/cookies.nim index 54ca164c7..c85f60915 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 @@ -39,7 +39,7 @@ proc setCookie*(key, value: string, domain = "", path = "", if path != "": result.add("; Path=" & path) if expires != "": result.add("; Expires=" & expires) -proc setCookie*(key, value: string, expires: TTimeInfo, +proc setCookie*(key, value: string, expires: TimeInfo, domain = "", path = "", noName = false): string = ## Creates a command in the format of ## ``Set-Cookie: key=value; Domain=...; ...`` @@ -50,7 +50,7 @@ proc setCookie*(key, value: string, expires: TTimeInfo, format(expires, "ddd',' dd MMM yyyy HH:mm:ss 'UTC'"), noName) 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..77ef20ad9 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,7 +12,9 @@ ## Windows ``LoadLibrary``. type - TLibHandle* = pointer ## a handle to a dynamically loaded library + LibHandle* = pointer ## a handle to a dynamically loaded library + +{.deprecated: [TLibHandle: LibHandle].} proc loadLib*(path: string, global_symbols=false): TLibHandle ## loads a library from `path`. Returns nil if the library could not diff --git a/lib/pure/encodings.nim b/lib/pure/encodings.nim index 633ea6020..f10c4e40b 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 = @@ -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, 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..7868050d1 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,21 +27,24 @@ ## # 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 = ## Initializes an EventHandler with the specified name and returns it. diff --git a/lib/pure/fsmonitor.nim b/lib/pure/fsmonitor.nim index b35466771..cfee8d0ea 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.} = @@ -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 = @[] @@ -197,18 +200,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 d4922d1ab..ccb0929f6 100644 --- a/lib/pure/ftpclient.nim +++ b/lib/pure/ftpclient.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 # distribution, for details about the copyright. @@ -14,8 +14,8 @@ import sockets, strutils, parseutils, times, os, asyncio ## 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. ## @@ -24,64 +24,63 @@ import sockets, strutils, parseutils, times, os, asyncio ## ## 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 - TFTPClient* = object of TObject + FTPClientObj* = object of RootObj case isAsync: bool of false: - csock: TSocket # Command connection socket - dsock: TSocket # Data connection socket + csock: Socket # Command connection socket + dsock: Socket # Data connection socket else: dummyA, dummyB: pointer # workaround a Nimrod API issue - asyncCSock: PAsyncSocket - asyncDSock: PAsyncSocket - handleEvent*: proc (ftp: PAsyncFTPClient, ev: TFTPEvent){.closure,gcsafe.} - disp: PDispatcher - asyncDSockID: PDelegate + asyncCSock: AsyncSocket + asyncDSock: AsyncSocket + handleEvent*: proc (ftp: AsyncFTPClient, ev: FTPEvent){.closure,gcsafe.} + disp: Dispatcher + asyncDSockID: Delegate user, pass: string address: string - port: TPort + port: Port jobInProgress: bool - job: ref TFTPJob + job: ref FTPJob dsockConnected: bool - PFTPClient* = ref TFTPClient + FTPClient* = ref FTPClientObj FTPJobType* = enum JRetrText, JRetr, JStore - TFTPJob = object + FTPJob = object prc: proc (ftp: PFTPClient, 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 - PAsyncFTPClient* = ref TAsyncFTPClient ## Async alternative to TFTPClient. - TAsyncFTPClient* = object of TFTPClient + AsyncFTPClient* = ref AsyncFTPClientObj ## Async alternative to TFTPClient. + AsyncFTPClientObj* = object of FTPClientObj FTPEventType* = enum EvTransferProgress, EvLines, EvRetr, EvStore - TFTPEvent* = object ## Event + FTPEvent* = object ## Event filename*: string case typ*: FTPEventType of EvLines: @@ -89,13 +88,19 @@ 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 = diff --git a/lib/pure/future.nim b/lib/pure/future.nim index b7df05207..c467d2c73 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 diff --git a/lib/pure/gentabs.nim b/lib/pure/gentabs.nim index 617473c14..87a55ea1e 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 @@ -12,6 +12,8 @@ ## may be any Nimrod or user defined type. This module supports matching ## of keys in case-sensitive, case-insensitive and style-insensitive modes. +{.deprecated.} + import os, hashes, strutils 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..54e917110 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 diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 9bacc80d6..3fbb04fc8 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 @@ -54,7 +54,7 @@ ## 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 ## ======== @@ -80,34 +80,38 @@ import asyncnet, asyncdispatch import rawsockets 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 @@ -232,7 +236,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 +254,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 +294,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): @@ -431,16 +437,18 @@ 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 +{.deprecated: [PAsyncHttpClient: AsyncHttpClient].} + proc newAsyncHttpClient*(userAgent = defUserAgent, - maxRedirects = 5): PAsyncHttpClient = + maxRedirects = 5): AsyncHttpClient = ## Creates a new PAsyncHttpClient instance. ## ## ``userAgent`` specifies the user agent that will be used when making @@ -453,7 +461,7 @@ proc newAsyncHttpClient*(userAgent = defUserAgent, result.userAgent = defUserAgent result.maxRedirects = maxRedirects -proc close*(client: PAsyncHttpClient) = +proc close*(client: AsyncHttpClient) = ## Closes any connections held by the HTTP client. if client.connected: client.socket.close() diff --git a/lib/pure/httpserver.nim b/lib/pure/httpserver.nim index 885742b64..a41dc9450 100644 --- a/lib/pure/httpserver.nim +++ b/lib/pure/httpserver.nim @@ -145,7 +145,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) diff --git a/lib/pure/json.nim b/lib/pure/json.nim index 383f924ca..b2c0db3d1 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. @@ -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 TBaseLexer ## 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: PStream, 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 @@ -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 @@ -529,7 +532,10 @@ type of JArray: elems*: seq[PJsonNode] - EJsonParsingError* = object of ValueError ## is raised for a JSON error + JsonParsingError* = object of ValueError ## is raised for a JSON error + +{.deprecated: [EJsonParsingError: JsonParsingError, TJsonNode: JsonNodeObj, + PJsonNode: JsonNode, TJsonNodeKind: JsonNodeKind].} proc raiseParseErr*(p: TJsonParser, msg: string) {.noinline, noreturn.} = ## raises an `EJsonParsingError` exception. diff --git a/lib/pure/lexbase.nim b/lib/pure/lexbase.nim index 0e10b95e4..361374177 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 @@ -36,6 +36,8 @@ type lineStart: int # index of last line start in buffer fileOpened: bool +{.deprecated: [TBaseLexer: BaseLexer].} + proc open*(L: var TBaseLexer, input: PStream, bufLen: int = 8192) ## inits the TBaseLexer with a stream to read from diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim index 284384b37..a0773f40b 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 + Logger* = ref object of RootObj ## abstract logger; the base type of all loggers + levelThreshold*: Leve l ## 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 + FileLogger* = ref object of Logger ## logger that writes the messages to a file f: TFile - 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,7 +108,7 @@ 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, +method log*(logger: Logger, level: Level, frmt: string, args: varargs[string, `$`]) {.raises: [EBase], tags: [FTime, FWriteIO, FReadIO].} = ## Override this method in custom loggers. Default implementation does ## nothing. diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 789f6ad76..7857e9a94 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -1,20 +1,20 @@ # # -# 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. # ## This module contains procs for serialization and deseralization of -## arbitrary Nimrod data structures. The serialization format uses JSON. +## 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:: nimrod +## .. code-block:: nim ## ## type ## TA = object @@ -211,7 +211,7 @@ proc loadAny(p: var TJsonParser, a: TAny, t: var TTable[biggestInt, pointer]) = raiseParseErr(p, "float expected") of akRange: loadAny(p, a.skipRange, t) -proc loadAny(s: PStream, a: TAny, t: var TTable[biggestInt, pointer]) = +proc loadAny(s: PStream, a: TAny, t: var TTable[BiggestInt, pointer]) = var p: TJsonParser open(p, s, "unknown file") next(p) diff --git a/lib/pure/matchers.nim b/lib/pure/matchers.nim index 2db7fa660..c3ad7235f 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. @@ -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 99849d98e..c6a0305d2 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>`_. @@ -41,8 +41,8 @@ const ## for Nimrod'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: @@ -287,12 +287,14 @@ proc random[T](a: openArray[T]): T = 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..322dbbe1d 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 diff --git a/lib/pure/memfiles.nim b/lib/pure/memfiles.nim index 5577fa5cf..8712df7f6 100644 --- a/lib/pure/memfiles.nim +++ b/lib/pure/memfiles.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2014 Nimrod Contributors # # See the file "copying.txt", included in this @@ -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: FileMode = fmRead, +proc mapMem*(m: var MemFile, mode: FileMode = fmRead, mappedSize = -1, offset = 0): pointer = var readonly = mode == fmRead when defined(windows): @@ -60,27 +61,27 @@ proc mapMem*(m: var TMemFile, mode: FileMode = fmRead, osError(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: FileMode = fmRead, - mappedSize = -1, offset = 0, newFileSize = -1): TMemFile = + 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: FileMode = 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: FileMode = 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: FileMode = 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..1e17f1d7a 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,25 @@ 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 PSSLCTX - TSSLAcceptResult* = enum + SSLAcceptResult* = enum AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess 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,34 +57,40 @@ 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, ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode, + TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext, + TSSLAcceptResult: SSLAcceptResult].} + +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 diff --git a/lib/pure/nimprof.nim b/lib/pure/nimprof.nim index 6f94d0656..6b8fe1ce5 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! 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..c0bfb7c08 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,12 +81,12 @@ 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() diff --git a/lib/pure/os.nim b/lib/pure/os.nim index 483044d0a..0b4cf24c5 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 ReadIOEffect ## effect that denotes a read - ## from an environment variable - FWriteEnv* = object of WriteIOEffect ## effect that denotes a write - ## to an environment variable - - FReadDir* = object of ReadIOEffect ## effect that denotes a write operation to - ## the directory structure - FWriteDir* = object of WriteIOEffect ## 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 @@ -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 @@ -219,10 +225,12 @@ proc osError*(msg: string = "") {.noinline, rtl, extern: "nos$1", deprecated.} = raise newException(OSError, msg) {.pop.} -proc `==`*(err1, err2: TOSErrorCode): bool {.borrow.} -proc `$`*(err: TOSErrorCode): string {.borrow.} +{.deprecated: [osError: raiseOSError].} + +proc `==`*(err1, err2: OSErrorCode): bool {.borrow.} +proc `$`*(err: OSErrorCode): string {.borrow.} -proc osErrorMsg*(errorCode: TOSErrorCode): string = +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. @@ -249,10 +257,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. ## @@ -268,7 +276,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 @@ -285,7 +293,7 @@ proc osLastError*(): TOSErrorCode = when defined(windows): result = TOSErrorCode(getLastError()) else: - result = TOSErrorCode(errno) + result = OSErrorCode(errno) {.pop.} proc unixToNativePath*(path: string, drive=""): string {. @@ -371,7 +379,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 +392,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 +407,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): @@ -701,7 +709,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 @@ -800,7 +808,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. @@ -883,7 +891,7 @@ 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. @@ -915,7 +923,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``. @@ -1014,7 +1022,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. @@ -1076,7 +1084,7 @@ when defined(windows): while true: var eend = strEnd(e) add(environment, $e) - e = cast[WideCString](cast[ByteAddress](eend)+2) + e = cast[WideCString](cast[TAddress](eend)+2) if eend[1].int == 0: break discard freeEnvironmentStringsW(env) else: @@ -1130,7 +1138,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 +1152,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. @@ -1175,7 +1183,7 @@ proc putEnv*(key, val: string) {.tags: [FWriteEnv].} = else: if setEnvironmentVariableA(key, val) == 0'i32: osError(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 +1193,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 +1233,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. @@ -1278,7 +1286,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**: @@ -1318,7 +1326,7 @@ proc rawRemoveDir(dir: string) = if rmdir(dir) != 0'i32 and errno != ENOENT: osError(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). ## @@ -1345,7 +1353,7 @@ proc rawCreateDir(dir: string) = if res == 0'i32 and getLastError() != 183'i32: osError(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. @@ -1568,7 +1576,7 @@ 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 @@ -1577,14 +1585,14 @@ proc inclFilePermissions*(filename: string, 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 ## 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 +1600,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 +1613,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. ## @@ -1625,7 +1633,7 @@ when defined(nimdoc): ## 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` @@ -1826,7 +1834,7 @@ proc getFileSize*(file: string): BiggestInt {.rtl, extern: "nos$1", close(f) else: osError(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` @@ -1854,7 +1862,6 @@ proc expandTilde*(path: string): string = ## 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: @@ -1961,7 +1968,7 @@ proc getFileInfo*(handle: FileHandle): FileInfo = rawToFormalFileInfo(rawInfo, result) proc getFileInfo*(file: File): FileInfo = - result = getFileInfo(file.fileHandle()) + result = getFileInfo(file.getFileHandle()) proc getFileInfo*(path: string, followSymlink = true): FileInfo = ## Retrieves file information for the file object pointed to by `path`. diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim index d5ca2f5a5..25782d4f5 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,7 +24,7 @@ when defined(linux): import linux type - TProcess = object of RootObj + ProcessObj = object of RootObj when defined(windows): fProcessHandle: THandle inHandle, outHandle, errHandle: FileHandle @@ -35,9 +35,9 @@ type 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. @@ -125,7 +128,7 @@ proc startProcess*(command: string, args: openArray[string] = [], env: PStringTable = nil, options: set[TProcessOption] = {poStdErrToStdOut}): - PProcess {.rtl, extern: "nosp$1", tags: [ExecIOEffect, FReadEnv].} + PProcess {.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 @@ -150,7 +153,7 @@ proc startProcess*(command: string, proc startCmd*(command: string, options: set[TProcessOption] = { poStdErrToStdOut, poUsePath}): PProcess {. - tags: [ExecIOEffect, FReadEnv], deprecated.} = + tags: [ExecIOEffect, ReadEnvEffect], deprecated.} = ## Deprecated - use `startProcess` directly. result = startProcess(command=command, options=options + {poEvalCommand}) @@ -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: [ExecIOEffect, TimeEffect, 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. @@ -584,12 +587,12 @@ elif not defined(useNimRtl): when not defined(useFork): proc startProcessAuxSpawn(data: TStartProcessData): TPid {. - tags: [ExecIOEffect, FReadEnv], gcsafe.} + tags: [ExecIOEffect, ReadEnvEffect], gcsafe.} proc startProcessAuxFork(data: TStartProcessData): TPid {. - tags: [ExecIOEffect, FReadEnv], gcsafe.} + tags: [ExecIOEffect, ReadEnvEffect], gcsafe.} {.push stacktrace: off, profiler: off.} proc startProcessAfterFork(data: ptr TStartProcessData) {. - tags: [ExecIOEffect, FReadEnv], cdecl, gcsafe.} + tags: [ExecIOEffect, ReadEnvEffect], cdecl, gcsafe.} {.pop.} proc startProcess(command: string, diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim index 1d61a967b..c340bf98b 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 @@ -20,24 +20,24 @@ ## 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 + CfgEvent* = object of RootObj ## describes a parsing event case kind*: TCfgEventKind ## the kind of the event of cfgEof: nil of cfgSectionStart: @@ -53,28 +53,30 @@ 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: CharSet = {'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: PStream, 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 +87,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 +117,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 TToken) = inc(c.bufpos) # skip '\' case c.buf[c.bufpos] of 'n', 'N': @@ -169,13 +171,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 +223,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 +233,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 +249,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 +288,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 +311,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 +331,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..d267906a3 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) = +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. @@ -160,19 +162,19 @@ proc readRow*(my: var TCsvParser, columns = 0): bool = $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 d7379a9a9..b325bd1f5 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 cmdShortOption ## a short option ``-c`` detected - TOptParser* = + 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: CharSet = {'\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,14 +123,12 @@ 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: ## diff --git a/lib/pure/parseopt2.nim b/lib/pure/parseopt2.nim index 7638171d1..c283a5edf 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* = + OptParser* = object of TObject ## 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]) @@ -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..fcca0aa44 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,33 +38,35 @@ 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) -proc getLine(L: TSqlLexer): int = +proc getLine(L: SqlLexer): int = result = L.linenumber proc handleHexChar(c: var TSqlLexer, xi: var int) = @@ -137,10 +139,10 @@ proc getEscapedChar(c: var TSqlLexer, tok: var TToken) = else: tok.kind = tkInvalid else: tok.kind = tkInvalid -proc HandleCRLF(c: var TSqlLexer, pos: int): int = +proc handleCRLF(c: var TSqlLexer, 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) = @@ -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,13 +183,13 @@ 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) = +proc getString(c: var TSqlLexer, tok: var TToken, kind: TokKind) = var pos = c.bufPos + 1 var buf = c.buf tok.kind = kind @@ -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: TSqlNodeKind): 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,7 +1076,7 @@ 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: PStream, 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) @@ -1079,7 +1084,7 @@ proc open(p: var TSqlParser, input: PStream, filename: string) = 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) @@ -1090,24 +1095,24 @@ proc parse(p: var TSqlParser): PSqlNode = 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)) -proc parseSQL*(input: PStream, filename: string): PSqlNode = +proc parseSQL*(input: PStream, 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..2637a879d 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 = "" @@ -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 0c045bc5a..38a3cbc5e 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 @@ -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,7 +340,9 @@ 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. ## @@ -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] == '$': diff --git a/lib/pure/parsexml.nim b/lib/pure/parsexml.nim index 667b8aed6..2d944917f 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 @@ -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 TBaseLexer ## 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: XmlParseOptions, + TXmlError: XmlErrorKind, TXmlEventKind: XmlEventKind].} + const - errorMessages: array [TXmlError, string] = [ + errorMessages: array[XmlError, 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,7 +130,7 @@ 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) diff --git a/lib/pure/pegs.nim b/lib/pure/pegs.nim index efe169c1d..8bd307c7d 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,16 +67,16 @@ 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 @@ -84,11 +84,13 @@ type of pkNonTerminal: nt: PNonTerminal 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 -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: PNonTerminal): Peg {. nosideEffect, rtl, extern: "npegs$1".} = ## constructs a PEG that consists of the nonterminal symbol assert n != nil @@ -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, '.') @@ -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,12 +499,14 @@ proc `$` *(r: TPeg): string {.nosideEffect, rtl, extern: "npegsToString".} = # --------------------- core engine ------------------------------------------- type - TCaptures* {.final.} = object ## contains the captured substrings. + Captures* = object ## contains the captured substrings. matches: array[0..maxSubpatterns-1, tuple[first, last: int]] ml: int origStart: int -proc bounds*(c: TCaptures, +{.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 @@ -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: @@ -876,46 +868,46 @@ template `=~`*(s: string, pattern: TPeg): bool = # ------------------------- 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 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,13 +938,13 @@ 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 c: Captures var caps: array[0..maxSubpatterns-1, string] while i < s.len: block searchSubs: @@ -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,7 +1052,7 @@ 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 @@ -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) 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) 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.} = +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': @@ -1173,7 +1165,7 @@ proc getEscapedChar(c: var TPegLexer, tok: var TToken) = 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,7 +1184,7 @@ 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 buf = c.buf @@ -1214,7 +1206,7 @@ proc getString(c: var TPegLexer, tok: var TToken) = inc(pos) c.bufpos = pos -proc getDollar(c: var TPegLexer, tok: var TToken) = +proc getDollar(c: var PegLexer, tok: var TToken) = var pos = c.bufPos + 1 var buf = c.buf if buf[pos] in {'0'..'9'}: @@ -1227,7 +1219,7 @@ 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 @@ -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) @@ -1414,31 +1406,31 @@ proc arrowIsNextTok(c: TPegLexer): bool = type EInvalidPeg* = object of EInvalidValue ## 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] 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): PNonTerminal = 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,7 +1563,7 @@ 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 @@ -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): PNonTerminal = 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 = "" diff --git a/lib/pure/poly.nim b/lib/pure/poly.nim index 45e528604..19bed2aca 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,10 +12,11 @@ import strutils import numeric type - TPoly* = object - cofs:seq[float] + Poly* = object + cofs:seq[float] + +{.deprecated: [TPoly: Poly].} - proc degree*(p:TPoly):int= ## Returns the degree of the polynomial, ## that is the number of coefficients-1 @@ -104,7 +105,7 @@ proc `$` *(p:TPoly):string = result="0" -proc derivative*(p:TPoly):TPoly= +proc derivative*(p: TPoly): TPoly= ## Returns a new polynomial, which is the derivative of `p` newSeq[float](result.cofs,p.degree) for idx in 0..high(result.cofs): @@ -310,10 +311,10 @@ 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 diff --git a/lib/pure/rawsockets.nim b/lib/pure/rawsockets.nim index fea09dfa2..14a494ecf 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 @@ -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,22 +138,22 @@ 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 close*(socket: SocketHandle) = ## closes a socket. when useWinVersion: discard winlean.closeSocket(socket) @@ -159,10 +162,10 @@ proc close*(socket: TSocketHandle) = # 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: [FReadIO].} = ## Marks ``socket`` as accepting connections. ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. @@ -171,12 +174,12 @@ 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) @@ -184,11 +187,11 @@ proc getAddrInfo*(address: string, port: TPort, af: TDomain = AF_INET, typ: TTyp 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)) -proc dealloc*(ai: ptr TAddrInfo) = +proc dealloc*(ai: ptr AddrInfo) = freeaddrinfo(ai) proc ntohl*(x: int32): int32 = @@ -220,7 +223,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: [FReadIO].} = ## 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. @@ -233,10 +236,10 @@ proc getServByName*(name, proto: string): TServent {.tags: [FReadIO].} = if s == nil: raise newException(EOS, "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: [FReadIO].} = ## 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. @@ -249,28 +252,28 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} = if s == nil: raise newException(EOS, "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: [FReadIO].} = ## 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)) 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 @@ -281,17 +284,17 @@ proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} = 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: [FReadIO].} = ## 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 @@ -302,69 +305,69 @@ proc getHostByName*(name: string): Thostent {.tags: [FReadIO].} = 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 {. +proc getSockOptInt*(socket: SocketHandle, level, optname: int): int {. tags: [FReadIO].} = ## 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) {. +proc setSockOptInt*(socket: SocketHandle, level, optname, optval: int) {. tags: [FWriteIO].} = ## 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 FdSet, s: seq[SocketHandle], m: var int) = FD_ZERO(fd) for i in items(s): m = max(m, int(i)) FD_SET(i, fd) -proc pruneSocketSet(s: var seq[TSocketHandle], fd: var TFdSet) = +proc pruneSocketSet(s: var seq[SocketHandle], fd: var FdSet) = var i = 0 var L = s.len while i < L: @@ -375,7 +378,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. @@ -396,7 +399,7 @@ proc select*(readfds: var seq[TSocketHandle], timeout = 500): int = pruneSocketSet(readfds, (rd)) -proc selectWrite*(writefds: var seq[TSocketHandle], +proc selectWrite*(writefds: var seq[SocketHandle], timeout = 500): int {.tags: [FReadIO].} = ## 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 @@ -405,7 +408,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 +422,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..ab3b81f37 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,36 +20,40 @@ 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 + Redis* = object socket: TSocket 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: RedistList, 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: @@ -58,24 +62,24 @@ proc open*(host = "localhost", port = 6379.TPort): TRedis = 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) elif not pipelineEnabled and status != "OK": raise newException(EInvalidReply, "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" 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..8205203ba 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 @@ -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: TFile, 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. @@ -332,12 +334,12 @@ 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: TFile): 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) @@ -352,7 +354,7 @@ 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 diff --git a/lib/pure/scgi.nim b/lib/pure/scgi.nim index 45f837833..fa8605a69 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 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 + +{.deprected: [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.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) 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) @@ -132,17 +136,17 @@ proc next*(s: var TScgistate, timeout: int = -1): bool = s.client.close() return false if d notin strutils.digits: - if d != ':': scgiError("':' after length expected") + 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 -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: @@ -203,7 +207,7 @@ proc handleClientRead(client: PAsyncClient, s: PAsyncScgiState) = if ret == -1: return # No more data available if d[0] notin strutils.digits: - if d[0] != ':': scgiError("':' after length expected") + 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.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..33939537a 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 FdSet, fds: Table[SocketHandle, SelectorKey], m: var int) = FD_ZERO(rd); FD_ZERO(wr) for k, v in pairs(fds): @@ -229,22 +229,22 @@ 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 FdSet, 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 rd, wr: FdSet var m = 0 createFdSet(rd, wr, fds, m) @@ -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..83eb60807 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) ## @@ -31,18 +31,20 @@ import sockets, strutils, strtabs, base64, os 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 + +{.deprecated: [EInvalidReply: ReplyError, TMessage: Message, TSMTP: Smtp].} proc debugSend(smtp: TSMTP, cmd: string) = if smtp.debug: @@ -170,7 +172,7 @@ when isMainModule: #smtp.sendmail("root@localhost", @["dominik@localhost"], $msg) #echo(decode("a17sm3701420wbe.12")) - var msg = createMessage("Hello from Nimrod's SMTP!", + var msg = createMessage("Hello from Nim's SMTP!", "Hello!!!!.\n Is this awesome or what?", @["someone@yahoo.com", "someone@gmail.com"]) echo(msg) diff --git a/lib/pure/sockets.nim b/lib/pure/sockets.nim index b0cc67c70..6c2ec72f1 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,39 @@ 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 Exception + 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 + invalidSocket*: Socket = nil ## invalid socket when defined(windows): let @@ -143,7 +153,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 +163,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 +199,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 +214,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,13 +225,13 @@ 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, @@ -336,7 +346,7 @@ when defined(ssl): if SSLSetFd(socket.sslHandle, socket.fd) != 1: SSLError() -proc socketError*(socket: TSocket, err: int = -1, async = false) = +proc raiseSocketError*(socket: TSocket, 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 @@ -370,18 +380,18 @@ 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: [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(ValueError, "invalid ip4 address: " & s) @@ -420,7 +430,7 @@ 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(OSError, $gai_strerror(gaiResult)) @@ -440,7 +450,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {. 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()) + raiseOSError(osLastError()) else: var hints: Taddrinfo var aiList: ptr Taddrinfo = nil @@ -449,7 +459,7 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {. 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()) + raiseOSError(osLastError()) proc getSockName*(socket: TSocket): TPort = ## returns the socket's associated port number. @@ -463,7 +473,7 @@ proc getSockName*(socket: TSocket): TPort = var namelen = sizeof(name).TSocklen if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)), addr(namelen)) == -1'i32: - osError(osLastError()) + raiseOSError(osLastError()) result = TPort(sockets.ntohs(name.sin_port)) template acceptAddrPlain(noClientRet, successRet: expr, @@ -484,7 +494,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 +503,7 @@ template acceptAddrPlain(noClientRet, successRet: expr, return else: return noClientRet - else: osError(err) + else: raiseOSError(err) else: client.fd = sock client.isBuffered = server.isBuffered @@ -680,7 +690,7 @@ proc getHostByAddr*(ip: string): Thostent {.tags: [ReadIOEffect].} = 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, cint(posix.AF_INET)) @@ -707,7 +717,7 @@ proc getHostByName*(name: string): Thostent {.tags: [ReadIOEffect].} = 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): @@ -729,7 +739,7 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int {. var size = sizeof(res).TSocklen 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) {. @@ -738,7 +748,7 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {. var value = cint(optval) if setsockopt(socket.fd, cint(level), cint(optname), addr(value), sizeof(value).TSocklen) < 0'i32: - osError(osLastError()) + raiseOSError(osLastError()) proc toCInt(opt: TSOBool): cint = case opt @@ -757,7 +767,7 @@ proc getSockOpt*(socket: TSocket, opt: TSOBool, level = SOL_SOCKET): bool {. var size = sizeof(res).TSocklen 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) {. @@ -766,7 +776,7 @@ proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) 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()) + raiseOSError(osLastError()) proc connect*(socket: TSocket, address: string, port = TPort(0), af: TDomain = AF_INET) {.tags: [ReadIOEffect].} = @@ -784,7 +794,7 @@ proc connect*(socket: TSocket, address: string, port = TPort(0), 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: @@ -794,7 +804,7 @@ proc connect*(socket: TSocket, address: 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: @@ -847,7 +857,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0), 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) @@ -869,7 +879,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 @@ -1133,7 +1143,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,9 +1157,9 @@ 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 {. @@ -1185,7 +1195,7 @@ 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 = @@ -1199,7 +1209,7 @@ 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) @@ -1296,14 +1306,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': @@ -1357,7 +1367,7 @@ proc readLineAsync*(socket: TSocket, setLen(line.string, 0) template errorOrNone = - socket.socketError(async = true) + socket.raiseSocketError(async = true) return ReadNone while true: @@ -1390,7 +1400,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [ReadIOEffect], 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: @@ -1463,11 +1473,11 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {. 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 @@ -1516,11 +1526,11 @@ 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: [ReadIOEffect], deprecated.} = ## skips all the data that is pending for the socket @@ -1570,7 +1580,7 @@ proc send*(socket: TSocket, data: string) {.tags: [WriteIOEffect].} = if socket.isSSL: SSLError() - osError(osLastError()) + raiseOSError(osLastError()) if sent != data.len: raise newException(OSError, "Could not send all data.") @@ -1607,11 +1617,11 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [WriteIOEffect].} = 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: [WriteIOEffect].} = @@ -1667,15 +1677,15 @@ proc setBlocking(s: TSocket, 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) = @@ -1715,6 +1725,6 @@ proc isBlocking*(socket: TSocket): bool = not socket.nonblocking when defined(Windows): var wsa: TWSAData - if wsaStartup(0x0101'i16, addr wsa) != 0: osError(osLastError()) + if wsaStartup(0x0101'i16, addr wsa) != 0: raiseOSError(osLastError()) diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim index c4e969f21..bc0f1c540 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,8 +8,8 @@ # ## 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 Nimrod file objects (`File`) and strings. Other modules ## may provide other implementations for this standard stream interface. include "system/inclrtl" @@ -19,81 +19,83 @@ proc newEIO(msg: string): ref IOError = result.msg = msg type - PStream* = ref TStream - TStream* = 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: 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, + 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: PStream, buffer: pointer, bufLen: int) {.nimcall, + writeDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int) {.nimcall, tags: [WriteIOEffect], gcsafe.} - flushImpl*: proc (s: PStream) {.nimcall, tags: [WriteIOEffect], gcsafe.} + flushImpl*: proc (s: Stream) {.nimcall, tags: [WriteIOEffect], gcsafe.} -proc flush*(s: PStream) = +{.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 @@ -103,63 +105,63 @@ proc write*[T](s: PStream, x: 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 + FileStream* = ref FileStreamObj ## a stream that encapsulates a `TFile` + FileStreamObj* = object of Stream f: File - - 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: + {.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: File): PFileStream = + proc newFileStream*(f: File): FileStream = ## creates a new stream from the file `f`. new(result) result.f = f @@ -276,7 +281,7 @@ when not defined(js): result.writeDataImpl = fsWriteData result.flushImpl = fsFlush - proc newFileStream*(filename: string, mode: FileMode): 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. @@ -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 12621a0fc..71d16192f 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,20 +18,23 @@ 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 RootObj + 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 @@ -54,7 +57,7 @@ iterator values*(t: PStringTable): string = 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,6 +66,8 @@ type useKey ## do not replace ``$key`` if it is not found ## in the table (or in the environment) +{.deprecated: [TFormatFlag: FormatFlag].} + # implementation const diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim index cc62ad1ee..82516653c 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 @@ -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,7 +417,7 @@ 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(ValueError, "invalid integer: " & s) @@ -426,7 +426,7 @@ 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(ValueError, "invalid integer: " & s) @@ -434,7 +434,7 @@ proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar, 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: @@ -444,7 +444,7 @@ 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 @@ -471,7 +471,7 @@ 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 @@ -480,7 +480,7 @@ proc parseBool*(s: string): bool = 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: @@ -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,7 +762,7 @@ 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. @@ -827,9 +827,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 @@ -862,7 +862,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 @@ -899,7 +899,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 @@ -999,7 +999,7 @@ 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: @@ -1138,12 +1138,14 @@ 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".} = ## Converts a floating point value `f` to a string. @@ -1174,7 +1176,7 @@ 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".} = ## Converts a floating point value `f` to a string. @@ -1190,7 +1192,7 @@ proc formatFloat*(f: float, format: TFloatFormat = ffDefault, 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" @@ -1280,12 +1282,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 @@ -1294,7 +1296,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 @@ -1302,15 +1304,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) @@ -1350,7 +1352,7 @@ 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..452978c09 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.} @@ -291,14 +293,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 +316,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 +325,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..0ebe8a39e 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,11 +27,11 @@ 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()) + if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: raiseOSError(osLastError()) return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y)) proc getAttributes(): int16 = @@ -51,7 +51,7 @@ proc setCursorPos*(x, y: int) = var c: TCOORD c.x = int16(x) c.y = int16(y) - if SetConsoleCursorPosition(conHandle, c) == 0: osError(osLastError()) + if SetConsoleCursorPosition(conHandle, c) == 0: raiseOSError(osLastError()) else: stdout.write("\e[" & $y & ';' & $x & 'f') @@ -61,10 +61,10 @@ 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()) + if SetConsoleCursorPosition(conHandle, origin) == 0: raiseOSError(osLastError()) else: stdout.write("\e[" & $x & 'G') @@ -75,10 +75,10 @@ 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()) + if SetConsoleCursorPosition(conHandle, origin) == 0: raiseOSError(osLastError()) else: discard @@ -155,18 +155,18 @@ 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()) + 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 +178,14 @@ 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 +199,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,6 +208,8 @@ type styleReverse = 7, ## unknown styleHidden ## hidden text +{.deprecated: [TStyle: Style].} + when not defined(windows): var # XXX: These better be thread-local @@ -244,7 +246,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 +256,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 +266,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 +290,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 +311,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 c156a4479..2c09fcc4c 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 RootObj ## 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,55 +136,58 @@ type months*: int ## The number of months years*: int ## The number of years -proc getTime*(): TTime {.tags: [TimeEffect], gcsafe.} +{.deprecated: [TMonth: Month, TWeekDay: WeekDay, TTime: Time, TTimeval: Timeval, + 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: [TimeEffect], 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: [TimeEffect], 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 @@ -203,8 +206,8 @@ proc getStartMilsecs*(): int {.deprecated, tags: [TimeEffect], gcsafe.} ## 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 @@ -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 @@ -314,38 +317,36 @@ 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: [TimeEffect].} - 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), @@ -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,9 +448,9 @@ 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 = @@ -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,11 +527,11 @@ 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() @@ -546,20 +547,20 @@ proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [TimeEffect].} = 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 @@ -672,7 +673,7 @@ proc format_token(info: TTimeInfo, token: string, buf: var string) = 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..1180b98f0 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Nimrod Contributors # # See the file "copying.txt", included in this 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..f26d8c3e6 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -1,6 +1,6 @@ # # -# Nimrod's Runtime Library +# Nim's Runtime Library # (c) Copyright 2012 Nimrod Contributors # # See the file "copying.txt", included in this @@ -26,16 +26,19 @@ 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 @@ -53,7 +56,7 @@ template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} = body -proc testDone(name: string, s: TTestStatus) = +proc testDone(name: string, s: TestStatus) = if s == FAILED: program_result += 1 @@ -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..ed1059cc2 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) @@ -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..afd26a584 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,7 +9,8 @@ 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 diff --git a/lib/pure/xmldomparser.nim b/lib/pure/xmldomparser.nim index fda46bac0..b92a9600c 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 @@ -156,7 +156,7 @@ proc loadXMLFile*(path: string): PDocument = 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..83bd45e7d 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,9 +12,11 @@ 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 @@ -23,12 +25,12 @@ proc raiseInvalidXml(errors: seq[string]) = 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,14 +120,14 @@ 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) -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. @@ -133,7 +135,7 @@ proc loadXml*(path: string, errors: var seq[string]): PXmlNode = if s == nil: raise newException(EIO, "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. @@ -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 7392eb470..6007232c5 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,33 +12,36 @@ import macros, strtabs type - PXmlNode* = ref TXmlNode ## an XML tree consists of ``PXmlNode``'s. + XmlNode* = ref TXmlNode ## 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 @@ -304,10 +307,10 @@ proc findAll*(n: PXmlNode, tag: string, result: var seq[PXmlNode]) = ## 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) @@ -326,8 +329,8 @@ proc findAll*(n: PXmlNode, tag: string, result: var seq[PXmlNode]) = proc findAll*(n: PXmlNode, tag: string): seq[PXmlNode] = ## 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"): diff --git a/lib/system.nim b/lib/system.nim index ad1cbd423..0e9712c24 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2437,6 +2437,8 @@ when not defined(JS): #and not defined(NimrodVM): ## returns the OS file handle of the file ``f``. This is only useful for ## platform specific programming. + {.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``. diff --git a/todo.txt b/todo.txt index 68965584b..fef88efc2 100644 --- a/todo.txt +++ b/todo.txt @@ -49,7 +49,6 @@ Bugs - 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 ... |