diff options
Diffstat (limited to 'lib/system.nim')
-rw-r--r-- | lib/system.nim | 384 |
1 files changed, 278 insertions, 106 deletions
diff --git a/lib/system.nim b/lib/system.nim index 83f071717..91495f31a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -61,11 +61,15 @@ const on* = true ## alias for ``true`` off* = false ## alias for ``false`` -{.push warning[GcMem]: off.} +{.push warning[GcMem]: off, warning[Uninit]: off.} {.push hints: off.} type - Ordinal* {.magic: Ordinal.}[T] + Ordinal* {.magic: Ordinal.}[T] ## Generic ordinal type. Includes integer, + ## bool, character, and enumeration types + ## as well as their subtypes. Note `uint` + ## and `uint64` are not ordinal types for + ## implementation reasons `ptr`* {.magic: Pointer.}[T] ## built-in generic untraced pointer type `ref`* {.magic: Pointer.}[T] ## built-in generic traced pointer type @@ -74,8 +78,8 @@ type stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates) typedesc* {.magic: TypeDesc.} ## meta type to denote a type description void* {.magic: "VoidType".} ## meta type to denote the absence of any type - auto* = expr - any* = distinct auto + auto* = expr ## meta type for automatic type determination + any* = distinct auto ## meta type for any supported type untyped* {.magic: Expr.} ## meta type to denote an expression that ## is not resolved (for templates) typed* {.magic: Stmt.} ## meta type to denote an expression that @@ -249,18 +253,49 @@ when defined(nimNewShared): guarded* {.magic: "Guarded".} # comparison operators: -proc `==` *[TEnum: enum](x, y: TEnum): bool {.magic: "EqEnum", noSideEffect.} +proc `==` *[Enum: enum](x, y: Enum): bool {.magic: "EqEnum", noSideEffect.} + ## Checks whether values within the *same enum* have the same underlying value + ## + ## .. code-block:: nim + ## type + ## Enum1 = enum + ## Field1 = 3, Field2 + ## Enum2 = enum + ## Place1, Place2 = 3 + ## var + ## e1 = Field1 + ## e2 = Enum1(Place2) + ## echo (e1 == e2) # true + ## echo (e1 == Place2) # raises error proc `==` *(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} + ## .. code-block:: nim + ## var # this is a wildly dangerous example + ## a = cast[pointer](0) + ## b = cast[pointer](nil) + ## echo (a == b) # true due to the special meaning of `nil`/0 as a pointer proc `==` *(x, y: string): bool {.magic: "EqStr", noSideEffect.} + ## Checks for equality between two `string` variables proc `==` *(x, y: cstring): bool {.magic: "EqCString", noSideEffect.} + ## Checks for equality between two `cstring` variables proc `==` *(x, y: char): bool {.magic: "EqCh", noSideEffect.} + ## Checks for equality between two `char` variables proc `==` *(x, y: bool): bool {.magic: "EqB", noSideEffect.} + ## Checks for equality between two `bool` variables proc `==` *[T](x, y: set[T]): bool {.magic: "EqSet", noSideEffect.} + ## Checks for equality between two variables of type `set` + ## + ## .. code-block:: nim + ## var a = {1, 2, 2, 3} # duplication in sets is ignored + ## var b = {1, 2, 3} + ## echo (a == b) # true proc `==` *[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.} + ## Checks that two `ref` variables refer to the same item proc `==` *[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.} + ## Checks that two `ptr` variables refer to the same item proc `==` *[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.} + ## Checks that two `proc` variables refer to the same procedure -proc `<=` *[TEnum: enum](x, y: TEnum): bool {.magic: "LeEnum", noSideEffect.} +proc `<=` *[Enum: enum](x, y: Enum): bool {.magic: "LeEnum", noSideEffect.} proc `<=` *(x, y: string): bool {.magic: "LeStr", noSideEffect.} proc `<=` *(x, y: char): bool {.magic: "LeCh", noSideEffect.} proc `<=` *[T](x, y: set[T]): bool {.magic: "LeSet", noSideEffect.} @@ -268,7 +303,7 @@ proc `<=` *(x, y: bool): bool {.magic: "LeB", noSideEffect.} proc `<=` *[T](x, y: ref T): bool {.magic: "LePtr", noSideEffect.} proc `<=` *(x, y: pointer): bool {.magic: "LePtr", noSideEffect.} -proc `<` *[TEnum: enum](x, y: TEnum): bool {.magic: "LtEnum", noSideEffect.} +proc `<` *[Enum: enum](x, y: Enum): bool {.magic: "LtEnum", noSideEffect.} proc `<` *(x, y: string): bool {.magic: "LtStr", noSideEffect.} proc `<` *(x, y: char): bool {.magic: "LtCh", noSideEffect.} proc `<` *[T](x, y: set[T]): bool {.magic: "LtSet", noSideEffect.} @@ -305,6 +340,8 @@ when not defined(JS): type TGenericSeq {.compilerproc, pure, inheritable.} = object len, reserved: int + when defined(gogc): + elemSize: int PGenericSeq {.exportc.} = ptr TGenericSeq UncheckedCharArray {.unchecked.} = array[0..ArrayDummySize, char] # len and space without counting the terminating zero: @@ -332,7 +369,7 @@ type RootObj* {.exportc: "TNimObject", inheritable.} = object ## the root of Nim's object hierarchy. Objects should - ## inherit from TObject or one of its descendants. However, + ## inherit from RootObj or one of its descendants. However, ## objects that have no ancestor are allowed. RootRef* = ref RootObj ## reference to RootObj @@ -352,9 +389,9 @@ type ## Each exception has to inherit from `Exception`. See the full `exception ## hierarchy`_. parent*: ref Exception ## parent exception (can be used as a stack) - name: cstring ## The exception's name is its Nim identifier. - ## This field is filled automatically in the - ## ``raise`` statement. + name*: cstring ## The exception's name is its Nim identifier. + ## This field is filled automatically in the + ## ``raise`` statement. msg* {.exportc: "message".}: string ## the exception's message. Not ## providing an exception message ## is bad style. @@ -663,7 +700,7 @@ proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.} proc `+` *(x: int8): int8 {.magic: "UnaryPlusI", noSideEffect.} proc `+` *(x: int16): int16 {.magic: "UnaryPlusI", noSideEffect.} proc `+` *(x: int32): int32 {.magic: "UnaryPlusI", noSideEffect.} -proc `+` *(x: int64): int64 {.magic: "UnaryPlusI64", noSideEffect.} +proc `+` *(x: int64): int64 {.magic: "UnaryPlusI", noSideEffect.} ## Unary `+` operator for an integer. Has no effect. proc `-` *(x: int): int {.magic: "UnaryMinusI", noSideEffect.} @@ -677,35 +714,50 @@ proc `not` *(x: int): int {.magic: "BitnotI", noSideEffect.} proc `not` *(x: int8): int8 {.magic: "BitnotI", noSideEffect.} proc `not` *(x: int16): int16 {.magic: "BitnotI", noSideEffect.} proc `not` *(x: int32): int32 {.magic: "BitnotI", noSideEffect.} -proc `not` *(x: int64): int64 {.magic: "BitnotI64", noSideEffect.} ## computes the `bitwise complement` of the integer `x`. +when defined(nimnomagic64): + proc `not` *(x: int64): int64 {.magic: "BitnotI", noSideEffect.} +else: + proc `not` *(x: int64): int64 {.magic: "BitnotI64", noSideEffect.} + proc `+` *(x, y: int): int {.magic: "AddI", noSideEffect.} proc `+` *(x, y: int8): int8 {.magic: "AddI", noSideEffect.} proc `+` *(x, y: int16): int16 {.magic: "AddI", noSideEffect.} proc `+` *(x, y: int32): int32 {.magic: "AddI", noSideEffect.} -proc `+` *(x, y: int64): int64 {.magic: "AddI64", noSideEffect.} ## Binary `+` operator for an integer. +when defined(nimnomagic64): + proc `+` *(x, y: int64): int64 {.magic: "AddI", noSideEffect.} +else: + proc `+` *(x, y: int64): int64 {.magic: "AddI64", noSideEffect.} + proc `-` *(x, y: int): int {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int8): int8 {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int16): int16 {.magic: "SubI", noSideEffect.} proc `-` *(x, y: int32): int32 {.magic: "SubI", noSideEffect.} -proc `-` *(x, y: int64): int64 {.magic: "SubI64", noSideEffect.} ## Binary `-` operator for an integer. +when defined(nimnomagic64): + proc `-` *(x, y: int64): int64 {.magic: "SubI", noSideEffect.} +else: + proc `-` *(x, y: int64): int64 {.magic: "SubI64", noSideEffect.} + proc `*` *(x, y: int): int {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int8): int8 {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int16): int16 {.magic: "MulI", noSideEffect.} proc `*` *(x, y: int32): int32 {.magic: "MulI", noSideEffect.} -proc `*` *(x, y: int64): int64 {.magic: "MulI64", noSideEffect.} ## Binary `*` operator for an integer. +when defined(nimnomagic64): + proc `*` *(x, y: int64): int64 {.magic: "MulI", noSideEffect.} +else: + proc `*` *(x, y: int64): int64 {.magic: "MulI64", noSideEffect.} + proc `div` *(x, y: int): int {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int8): int8 {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int16): int16 {.magic: "DivI", noSideEffect.} proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.} -proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.} ## computes the integer division. This is roughly the same as ## ``floor(x/y)``. ## @@ -714,19 +766,28 @@ proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.} ## 2 div 2 == 1 ## 3 div 2 == 1 +when defined(nimnomagic64): + proc `div` *(x, y: int64): int64 {.magic: "DivI", noSideEffect.} +else: + proc `div` *(x, y: int64): int64 {.magic: "DivI64", noSideEffect.} + proc `mod` *(x, y: int): int {.magic: "ModI", noSideEffect.} proc `mod` *(x, y: int8): int8 {.magic: "ModI", noSideEffect.} proc `mod` *(x, y: int16): int16 {.magic: "ModI", noSideEffect.} proc `mod` *(x, y: int32): int32 {.magic: "ModI", noSideEffect.} -proc `mod` *(x, y: int64): int64 {.magic: "ModI64", noSideEffect.} ## computes the integer modulo operation. This is the same as ## ``x - (x div y) * y``. +when defined(nimnomagic64): + proc `mod` *(x, y: int64): int64 {.magic: "ModI", noSideEffect.} +else: + proc `mod` *(x, y: int64): int64 {.magic: "ModI64", noSideEffect.} + proc `shr` *(x, y: int): int {.magic: "ShrI", noSideEffect.} proc `shr` *(x, y: int8): int8 {.magic: "ShrI", noSideEffect.} proc `shr` *(x, y: int16): int16 {.magic: "ShrI", noSideEffect.} proc `shr` *(x, y: int32): int32 {.magic: "ShrI", noSideEffect.} -proc `shr` *(x, y: int64): int64 {.magic: "ShrI64", noSideEffect.} +proc `shr` *(x, y: int64): int64 {.magic: "ShrI", noSideEffect.} ## computes the `shift right` operation of `x` and `y`. ## ## .. code-block:: Nim @@ -738,49 +799,49 @@ proc `shl` *(x, y: int): int {.magic: "ShlI", noSideEffect.} proc `shl` *(x, y: int8): int8 {.magic: "ShlI", noSideEffect.} proc `shl` *(x, y: int16): int16 {.magic: "ShlI", noSideEffect.} proc `shl` *(x, y: int32): int32 {.magic: "ShlI", noSideEffect.} -proc `shl` *(x, y: int64): int64 {.magic: "ShlI64", noSideEffect.} +proc `shl` *(x, y: int64): int64 {.magic: "ShlI", noSideEffect.} ## computes the `shift left` operation of `x` and `y`. proc `and` *(x, y: int): int {.magic: "BitandI", noSideEffect.} proc `and` *(x, y: int8): int8 {.magic: "BitandI", noSideEffect.} proc `and` *(x, y: int16): int16 {.magic: "BitandI", noSideEffect.} proc `and` *(x, y: int32): int32 {.magic: "BitandI", noSideEffect.} -proc `and` *(x, y: int64): int64 {.magic: "BitandI64", noSideEffect.} +proc `and` *(x, y: int64): int64 {.magic: "BitandI", noSideEffect.} ## computes the `bitwise and` of numbers `x` and `y`. proc `or` *(x, y: int): int {.magic: "BitorI", noSideEffect.} proc `or` *(x, y: int8): int8 {.magic: "BitorI", noSideEffect.} proc `or` *(x, y: int16): int16 {.magic: "BitorI", noSideEffect.} proc `or` *(x, y: int32): int32 {.magic: "BitorI", noSideEffect.} -proc `or` *(x, y: int64): int64 {.magic: "BitorI64", noSideEffect.} +proc `or` *(x, y: int64): int64 {.magic: "BitorI", noSideEffect.} ## computes the `bitwise or` of numbers `x` and `y`. proc `xor` *(x, y: int): int {.magic: "BitxorI", noSideEffect.} proc `xor` *(x, y: int8): int8 {.magic: "BitxorI", noSideEffect.} proc `xor` *(x, y: int16): int16 {.magic: "BitxorI", noSideEffect.} proc `xor` *(x, y: int32): int32 {.magic: "BitxorI", noSideEffect.} -proc `xor` *(x, y: int64): int64 {.magic: "BitxorI64", noSideEffect.} +proc `xor` *(x, y: int64): int64 {.magic: "BitxorI", noSideEffect.} ## computes the `bitwise xor` of numbers `x` and `y`. proc `==` *(x, y: int): bool {.magic: "EqI", noSideEffect.} proc `==` *(x, y: int8): bool {.magic: "EqI", noSideEffect.} proc `==` *(x, y: int16): bool {.magic: "EqI", noSideEffect.} proc `==` *(x, y: int32): bool {.magic: "EqI", noSideEffect.} -proc `==` *(x, y: int64): bool {.magic: "EqI64", noSideEffect.} +proc `==` *(x, y: int64): bool {.magic: "EqI", noSideEffect.} ## Compares two integers for equality. proc `<=` *(x, y: int): bool {.magic: "LeI", noSideEffect.} proc `<=` *(x, y: int8): bool {.magic: "LeI", noSideEffect.} proc `<=` *(x, y: int16): bool {.magic: "LeI", noSideEffect.} proc `<=` *(x, y: int32): bool {.magic: "LeI", noSideEffect.} -proc `<=` *(x, y: int64): bool {.magic: "LeI64", noSideEffect.} +proc `<=` *(x, y: int64): bool {.magic: "LeI", noSideEffect.} ## Returns true iff `x` is less than or equal to `y`. proc `<` *(x, y: int): bool {.magic: "LtI", noSideEffect.} proc `<` *(x, y: int8): bool {.magic: "LtI", noSideEffect.} proc `<` *(x, y: int16): bool {.magic: "LtI", noSideEffect.} proc `<` *(x, y: int32): bool {.magic: "LtI", noSideEffect.} -proc `<` *(x, y: int64): bool {.magic: "LtI64", noSideEffect.} +proc `<` *(x, y: int64): bool {.magic: "LtI", noSideEffect.} ## Returns true iff `x` is less than `y`. type @@ -827,9 +888,52 @@ proc `<%` *(x, y: int64): bool {.magic: "LtU64", noSideEffect.} ## treats `x` and `y` as unsigned and compares them. ## Returns true iff ``unsigned(x) < unsigned(y)``. +# unsigned integer operations: +proc `not`*[T: SomeUnsignedInt](x: T): T {.magic: "BitnotI", noSideEffect.} + ## computes the `bitwise complement` of the integer `x`. -# floating point operations: +proc `shr`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShrI", noSideEffect.} + ## computes the `shift right` operation of `x` and `y`. +proc `shl`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ShlI", noSideEffect.} + ## computes the `shift left` operation of `x` and `y`. + +proc `and`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitandI", noSideEffect.} + ## computes the `bitwise and` of numbers `x` and `y`. + +proc `or`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitorI", noSideEffect.} + ## computes the `bitwise or` of numbers `x` and `y`. + +proc `xor`*[T: SomeUnsignedInt](x, y: T): T {.magic: "BitxorI", noSideEffect.} + ## computes the `bitwise xor` of numbers `x` and `y`. + +proc `==`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "EqI", noSideEffect.} + ## Compares two unsigned integers for equality. + +proc `+`*[T: SomeUnsignedInt](x, y: T): T {.magic: "AddU", noSideEffect.} + ## Binary `+` operator for unsigned integers. + +proc `-`*[T: SomeUnsignedInt](x, y: T): T {.magic: "SubU", noSideEffect.} + ## Binary `-` operator for unsigned integers. + +proc `*`*[T: SomeUnsignedInt](x, y: T): T {.magic: "MulU", noSideEffect.} + ## Binary `*` operator for unsigned integers. + +proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.} + ## computes the integer division. This is roughly the same as + ## ``floor(x/y)``. + +proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.} + ## computes the integer modulo operation. This is the same as + ## ``x - (x div y) * y``. + +proc `<=`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LeU", noSideEffect.} + ## Returns true iff ``x <= y``. + +proc `<`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LtU", noSideEffect.} + ## Returns true iff ``unsigned(x) < unsigned(y)``. + +# floating point operations: proc `+` *(x: float32): float32 {.magic: "UnaryPlusF64", noSideEffect.} proc `-` *(x: float32): float32 {.magic: "UnaryMinusF64", noSideEffect.} proc `+` *(x, y: float32): float32 {.magic: "AddF64", noSideEffect.} @@ -872,7 +976,7 @@ proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} ## ## .. code-block:: Nim ## var s: set[range['a'..'z']] = {'a'..'c'} - ## writeln(stdout, 'b' in s) + ## writeLine(stdout, 'b' in s) ## ## If ``in`` had been declared as ``[T](elem: T, s: set[T])`` then ``T`` would ## have been bound to ``char``. But ``s`` is not compatible to type @@ -978,7 +1082,7 @@ proc `&` * (x: string, y: char): string {. ## ## .. code-block:: Nim ## assert("ab" & 'c' == "abc") -proc `&` * (x: char, y: char): string {. +proc `&` * (x, y: char): string {. magic: "ConStrStr", noSideEffect, merge.} ## Concatenates `x` and `y` into a string ## @@ -1068,7 +1172,7 @@ proc compileOption*(option, arg: string): bool {. const hasThreadSupport = compileOption("threads") - hasSharedHeap = defined(boehmgc) # don't share heaps; every thread has its own + hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own taintMode = compileOption("taintmode") when taintMode: @@ -1110,7 +1214,7 @@ var programResult* {.exportc: "nim_program_result".}: int ## prematurely using ``quit``, this value is ignored. proc quit*(errorcode: int = QuitSuccess) {. - magic: "Exit", importc: "exit", header: "<stdlib.h>", noReturn.} + magic: "Exit", importc: "exit", header: "<stdlib.h>", noreturn.} ## Stops the program immediately with an exit code. ## ## Before stopping the program the "quit procedures" are called in the @@ -1135,8 +1239,13 @@ template sysAssert(cond: bool, msg: string) = echo "[SYSASSERT] ", msg quit 1 +const hasAlloc = hostOS != "standalone" or not defined(nogc) + when not defined(JS) and not defined(nimrodVm) and hostOS != "standalone": include "system/cgprocs" +when not defined(JS) and not defined(nimrodVm) and hasAlloc: + proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline, benign.} + proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.} proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.} proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = @@ -1343,7 +1452,7 @@ when not defined(nimrodVM): ## otherwise. Like any procedure dealing with raw memory this is ## *unsafe*. - when hostOS != "standalone": + when hasAlloc: proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign.} ## allocates a new memory block with at least ``size`` bytes. The ## block has to be freed with ``realloc(block, 0)`` or @@ -1400,8 +1509,7 @@ when not defined(nimrodVM): ## or other memory may be corrupted. ## The freed memory must belong to its allocating thread! ## Use `deallocShared` to deallocate from a shared heap. - proc free*[T](p: ptr T) {.inline, benign.} = - dealloc(p) + proc allocShared*(size: Natural): pointer {.noconv, rtl, benign.} ## allocates a new memory block on the shared heap with at ## least ``size`` bytes. The block has to be freed with @@ -1479,7 +1587,7 @@ proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} ## converted to a decimal string. when not defined(NimrodVM): - when not defined(JS) and hostOS != "standalone": + when not defined(JS) and hasAlloc: proc `$` *(x: uint64): string {.noSideEffect.} ## The stringify operator for an unsigned integer argument. Returns `x` ## converted to a decimal string. @@ -1505,7 +1613,7 @@ proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.} ## as it is. This operator is useful for generic code, so ## that ``$expr`` also works if ``expr`` is already a string. -proc `$` *[TEnum: enum](x: TEnum): string {.magic: "EnumToStr", noSideEffect.} +proc `$` *[Enum: enum](x: Enum): string {.magic: "EnumToStr", noSideEffect.} ## The stringify operator for an enumeration argument. This works for ## any enumeration type thanks to compiler magic. If ## a ``$`` operator for a concrete enumeration is provided, this is @@ -1532,7 +1640,7 @@ const NimMajor*: int = 0 ## is the major number of Nim's version. - NimMinor*: int = 10 + NimMinor*: int = 11 ## is the minor number of Nim's version. NimPatch*: int = 3 @@ -1546,7 +1654,7 @@ const # GC interface: -when not defined(nimrodVM) and hostOS != "standalone": +when not defined(nimrodVM) and hasAlloc: proc getOccupiedMem*(): int {.rtl.} ## returns the number of bytes that are owned by the process and hold data. @@ -1578,7 +1686,7 @@ else: type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16|enum iterator countdown*[T](a, b: T, step = 1): T {.inline.} = - ## Counts from ordinal value `a` down to `b` with the given + ## Counts from ordinal value `a` down to `b` (inclusive) with the given ## step count. `T` may be any ordinal type, `step` may only ## be positive. **Note**: This fails to count to ``low(int)`` if T = int for ## efficiency reasons. @@ -1606,7 +1714,7 @@ template countupImpl(incr: stmt) {.immediate, dirty.} = incr iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} = - ## Counts from ordinal value `a` up to `b` with the given + ## Counts from ordinal value `a` up to `b` (inclusive) with the given ## step count. `S`, `T` may be any ordinal type, `step` may only ## be positive. **Note**: This fails to count to ``high(int)`` if T = int for ## efficiency reasons. @@ -1638,7 +1746,7 @@ proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} = if x <= y: x else: y proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} = if x <= y: x else: y -proc min*(x, y: int64): int64 {.magic: "MinI64", noSideEffect.} = +proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} = ## The minimum value of two integers. if x <= y: x else: y @@ -1656,7 +1764,7 @@ proc max*(x, y: int16): int16 {.magic: "MaxI", noSideEffect.} = if y <= x: x else: y proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} = if y <= x: x else: y -proc max*(x, y: int64): int64 {.magic: "MaxI64", noSideEffect.} = +proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} = ## The maximum value of two integers. if y <= x: x else: y @@ -1744,6 +1852,12 @@ iterator items*(E: typedesc[enum]): E = for v in low(E)..high(E): yield v +iterator items*[T](s: Slice[T]): T = + ## iterates over the slice `s`, yielding each value between `s.a` and `s.b` + ## (inclusively). + for x in s.a..s.b: + yield x + iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} = ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. var i = 0 @@ -2059,7 +2173,11 @@ proc `$`*[T: tuple|object](x: T): string = if not firstElement: result.add(", ") result.add(name) result.add(": ") - result.add($value) + when compiles(value.isNil): + if value.isNil: result.add "nil" + else: result.add($value) + else: + result.add($value) firstElement = false result.add(")") @@ -2096,7 +2214,7 @@ when false: # ----------------- GC interface --------------------------------------------- -when not defined(nimrodVM) and hostOS != "standalone": +when not defined(nimrodVM) and hasAlloc: proc GC_disable*() {.rtl, inl, benign.} ## disables the GC. If called n-times, n calls to `GC_enable` are needed to ## reactivate the GC. Note that in most circumstances one should only disable @@ -2207,6 +2325,7 @@ type filename*: cstring ## filename of the proc that is currently executing len*: int16 ## length of the inspectable slots calldepth*: int16 ## used for max call depth checking +#{.deprecated: [TFrame: Frame].} when defined(JS): proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = @@ -2220,7 +2339,7 @@ when defined(JS): """ proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} -elif hostOS != "standalone": +elif hasAlloc: {.push stack_trace:off, profiler:off.} proc add*(x: var string, y: cstring) = var i = 0 @@ -2229,27 +2348,33 @@ elif hostOS != "standalone": inc(i) {.pop.} -proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], - benign, sideEffect.} - ## Writes and flushes the parameters to the standard output. - ## - ## Special built-in that takes a variable number of arguments. Each argument - ## is converted to a string via ``$``, so it works for user-defined - ## types that have an overloaded ``$`` operator. - ## It is roughly equivalent to ``writeln(stdout, x); flushFile(stdout)``, but - ## available for the JavaScript target too. - ## - ## Unlike other IO operations this is guaranteed to be thread-safe as - ## ``echo`` is very often used for debugging convenience. If you want to use - ## ``echo`` inside a `proc without side effects - ## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_ - ## instead. - -proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect, - tags: [], raises: [].} - ## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho`` - ## pretends to be free of side effects, so that it can be used for debugging - ## routines marked as `noSideEffect <manual.html#nosideeffect-pragma>`_. +when defined(nimvarargstyped): + proc echo*(x: varargs[typed, `$`]) {.magic: "Echo", tags: [WriteIOEffect], + benign, sideEffect.} + ## Writes and flushes the parameters to the standard output. + ## + ## Special built-in that takes a variable number of arguments. Each argument + ## is converted to a string via ``$``, so it works for user-defined + ## types that have an overloaded ``$`` operator. + ## It is roughly equivalent to ``writeLine(stdout, x); flushFile(stdout)``, but + ## available for the JavaScript target too. + ## + ## Unlike other IO operations this is guaranteed to be thread-safe as + ## ``echo`` is very often used for debugging convenience. If you want to use + ## ``echo`` inside a `proc without side effects + ## <manual.html#pragmas-nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_ + ## instead. + + proc debugEcho*(x: varargs[typed, `$`]) {.magic: "Echo", noSideEffect, + tags: [], raises: [].} + ## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho`` + ## pretends to be free of side effects, so that it can be used for debugging + ## routines marked as `noSideEffect <manual.html#pragmas-nosideeffect-pragma>`_. +else: + proc echo*(x: varargs[expr, `$`]) {.magic: "Echo", tags: [WriteIOEffect], + benign, sideEffect.} + proc debugEcho*(x: varargs[expr, `$`]) {.magic: "Echo", noSideEffect, + tags: [], raises: [].} template newException*(exceptn: typedesc, message: string): expr = ## creates an exception object of type ``exceptn`` and sets its ``msg`` field @@ -2264,20 +2389,21 @@ when hostOS == "standalone": include panicoverride when not declared(sysFatal): - template sysFatal(exceptn: typedesc, message: string) = - when hostOS == "standalone": + when hostOS == "standalone": + proc sysFatal(exceptn: typedesc, message: string) {.inline.} = panic(message) - else: + + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline.} = + rawoutput(message) + panic(arg) + else: + proc sysFatal(exceptn: typedesc, message: string) {.inline, noReturn.} = var e: ref exceptn new(e) e.msg = message raise e - template sysFatal(exceptn: typedesc, message, arg: string) = - when hostOS == "standalone": - rawoutput(message) - panic(arg) - else: + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = var e: ref exceptn new(e) e.msg = message & arg @@ -2296,19 +2422,26 @@ proc abs*(x: int16): int16 {.magic: "AbsI", noSideEffect.} = if x < 0: -x else: x proc abs*(x: int32): int32 {.magic: "AbsI", noSideEffect.} = if x < 0: -x else: x -proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} = - ## returns the absolute value of `x`. If `x` is ``low(x)`` (that - ## is -MININT for its type), an overflow exception is thrown (if overflow - ## checking is turned on). - if x < 0: -x else: x +when defined(nimnomagic64): + proc abs*(x: int64): int64 {.magic: "AbsI", noSideEffect.} = + ## returns the absolute value of `x`. If `x` is ``low(x)`` (that + ## is -MININT for its type), an overflow exception is thrown (if overflow + ## checking is turned on). + if x < 0: -x else: x +else: + proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.} = + ## returns the absolute value of `x`. If `x` is ``low(x)`` (that + ## is -MININT for its type), an overflow exception is thrown (if overflow + ## checking is turned on). + if x < 0: -x else: x {.pop.} when not defined(JS): #and not defined(NimrodVM): {.push stack_trace: off, profiler:off.} - when not defined(NimrodVM) and hostOS != "standalone": + when not defined(NimrodVM) and not defined(nogc): proc initGC() - when not defined(boehmgc) and not defined(useMalloc): + when not defined(boehmgc) and not defined(useMalloc) and not defined(gogc): proc initAllocator() {.inline.} proc initStackBottom() {.inline, compilerproc.} = @@ -2326,6 +2459,7 @@ when not defined(JS): #and not defined(NimrodVM): when declared(setStackBottom): setStackBottom(locals) + when hasAlloc: var strDesc: TNimType @@ -2407,7 +2541,7 @@ when not defined(JS): #and not defined(NimrodVM): proc open*(f: var File, filehandle: FileHandle, mode: FileMode = fmRead): bool {.tags: [], benign.} - ## Creates a ``TFile`` from a `filehandle` with given `mode`. + ## Creates a ``File`` from a `filehandle` with given `mode`. ## ## Default mode is readonly. Returns true iff the file could be opened. @@ -2485,7 +2619,11 @@ when not defined(JS): #and not defined(NimrodVM): ## Returns ``false`` if the end of the file has been reached, ``true`` ## otherwise. If ``false`` is returned `line` contains no new data. - proc writeln*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, + proc writeLn*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, + tags: [WriteIOEffect], benign, deprecated.} + ## **Deprecated since version 0.11.4:** Use **writeLine** instead. + + proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, tags: [WriteIOEffect], benign.} ## writes the values `x` to `f` and then writes "\n". ## May throw an IO exception. @@ -2545,6 +2683,7 @@ when not defined(JS): #and not defined(NimrodVM): when not defined(nimfix): {.deprecated: [fileHandle: getFileHandle].} + when declared(newSeq): proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] = ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be ## of length ``len``. @@ -2560,12 +2699,12 @@ when not defined(JS): #and not defined(NimrodVM): # ------------------------------------------------------------------------- - when not defined(NimrodVM) and hostOS != "standalone": + when declared(alloc0) and declared(dealloc): proc allocCStringArray*(a: openArray[string]): cstringArray = ## creates a NULL terminated cstringArray from `a`. The result has to ## be freed with `deallocCStringArray` after it's not needed anymore. result = cast[cstringArray](alloc0((a.len+1) * sizeof(cstring))) - let x = cast[ptr array[0..20_000, string]](a) + let x = cast[ptr array[0..ArrayDummySize, string]](a) for i in 0 .. a.high: result[i] = cast[cstring](alloc0(x[i].len+1)) copyMem(result[i], addr(x[i][0]), x[i].len) @@ -2597,15 +2736,17 @@ when not defined(JS): #and not defined(NimrodVM): context: C_JmpBuf hasRaiseAction: bool raiseAction: proc (e: ref Exception): bool {.closure.} + SafePoint = TSafePoint +# {.deprecated: [TSafePoint: SafePoint].} when declared(initAllocator): initAllocator() when hasThreadSupport: include "system/syslocks" when hostOS != "standalone": include "system/threads" - elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone": + elif not defined(nogc) and not defined(NimrodVM): when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom() - initGC() + when declared(initGC): initGC() when not defined(NimrodVM): proc setControlCHook*(hook: proc () {.noconv.} not nil) @@ -2641,8 +2782,10 @@ when not defined(JS): #and not defined(NimrodVM): when not defined(NimrodVM): include "system/sets" - const - GenericSeqSize = (2 * sizeof(int)) + when defined(gogc): + const GenericSeqSize = (3 * sizeof(int)) + else: + const GenericSeqSize = (2 * sizeof(int)) proc getDiscriminant(aa: pointer, n: ptr TNimNode): int = sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") @@ -2664,9 +2807,9 @@ when not defined(JS): #and not defined(NimrodVM): else: result = n.sons[n.len] - when hostOS != "standalone": include "system/mmdisp" + when hasAlloc: include "system/mmdisp" {.push stack_trace: off, profiler:off.} - when hostOS != "standalone": include "system/sysstr" + when hasAlloc: include "system/sysstr" {.pop.} when hostOS != "standalone": include "system/sysio" @@ -2675,7 +2818,7 @@ when not defined(JS): #and not defined(NimrodVM): else: include "system/sysio" - when hostOS != "standalone": + when declared(open) and declared(close) and declared(readline): iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} = ## Iterates over any line in the file named `filename`. ## @@ -2711,10 +2854,11 @@ when not defined(JS): #and not defined(NimrodVM): var res = TaintedString(newStringOfCap(80)) while f.readLine(res): yield res - when hostOS != "standalone" and not defined(NimrodVM): + when not defined(NimrodVM) and hasAlloc: include "system/assign" include "system/repr" + when hostOS != "standalone" and not defined(NimrodVM): proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} = ## retrieves the current exception; if there is none, nil is returned. result = currException @@ -2849,9 +2993,6 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} = ## integer division that results in a float. result = toFloat(x) / toFloat(y) -template `-|`*(b, s: expr): expr = - (if b >= 0: b else: s.len + b) - template spliceImpl(s, a, L, b: expr): stmt {.immediate.} = # make room for additional elements or cut: var slen = s.len @@ -2868,7 +3009,7 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} = # fill the hole: for i in 0 .. <b.len: s[i+a] = b[i] -when hostOS != "standalone": +when hasAlloc: proc `[]`*(s: string, x: Slice[int]): string {.inline.} = ## slice operation for strings. result = s.substr(x.a, x.b) @@ -2953,11 +3094,11 @@ proc staticRead*(filename: string): string {.magic: "Slurp".} ## ## `slurp <#slurp>`_ is an alias for ``staticRead``. -proc gorge*(command: string, input = ""): string {. +proc gorge*(command: string, input = "", cache = ""): string {. magic: "StaticExec".} = discard ## This is an alias for `staticExec <#staticExec>`_. -proc staticExec*(command: string, input = ""): string {. +proc staticExec*(command: string, input = "", cache = ""): string {. magic: "StaticExec".} = discard ## Executes an external process at compile-time. ## if `input` is not an empty string, it will be passed as a standard input @@ -2970,6 +3111,15 @@ proc staticExec*(command: string, input = ""): string {. ## `gorge <#gorge>`_ is an alias for ``staticExec``. Note that you can use ## this proc inside a pragma like `passC <nimc.html#passc-pragma>`_ or `passL ## <nimc.html#passl-pragma>`_. + ## + ## If ``cache`` is not empty, the results of ``staticExec`` are cached within + ## the ``nimcache`` directory. Use ``--forceBuild`` to get rid of this caching + ## behaviour then. ``command & input & cache`` (the concatenated string) is + ## used to determine wether the entry in the cache is still valid. You can + ## use versioning information for ``cache``: + ## + ## .. code-block:: nim + ## const stateMachine = staticExec("dfaoptimizer", "input", "0.8.0") proc `+=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.magic: "Inc", noSideEffect.} ## Increments an ordinal @@ -3047,9 +3197,10 @@ proc raiseAssert*(msg: string) {.noinline.} = proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} = # trick the compiler to not list ``AssertionError`` when called # by ``assert``. - type THide = proc (msg: string) {.noinline, raises: [], noSideEffect, + type Hide = proc (msg: string) {.noinline, raises: [], noSideEffect, tags: [].} - THide(raiseAssert)(msg) + {.deprecated: [THide: Hide].} + Hide(raiseAssert)(msg) template assert*(cond: bool, msg = "") = ## Raises ``AssertionError`` with `msg` if `cond` is false. Note @@ -3160,7 +3311,7 @@ when false: macro payload: stmt {.gensym.} = blk payload() -when hostOS != "standalone": +when hasAlloc: proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} = ## inserts `item` into `x` at position `i`. var xl = x.len @@ -3187,21 +3338,26 @@ proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} = when declared(initDebugger): initDebugger() -when hostOS != "standalone": +when hasAlloc: # XXX: make these the default (or implement the NilObject optimization) proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect.} = + ## Adds ``y`` to ``x`` unless ``x`` is not yet initialized; in that case, + ## ``x`` becomes ``@[y]`` if x == nil: x = @[y] else: x.add(y) proc safeAdd*(x: var string, y: char) = + ## Adds ``y`` to ``x``. If ``x`` is ``nil`` it is initialized to ``""`` if x == nil: x = "" x.add(y) proc safeAdd*(x: var string, y: string) = + ## Adds ``y`` to ``x`` unless ``x`` is not yet initalized; in that case, ``x`` + ## becomes ``y`` if x == nil: x = y else: x.add(y) -proc locals*(): RootObj {.magic: "Locals", noSideEffect.} = +proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = ## generates a tuple constructor expression listing all the local variables ## in the current scope. This is quite fast as it does not rely ## on any debug or runtime information. Note that in constrast to what @@ -3225,7 +3381,7 @@ proc locals*(): RootObj {.magic: "Locals", noSideEffect.} = ## # -> B is 1 discard -when hostOS != "standalone" and not defined(NimrodVM) and not defined(JS): +when hasAlloc and not defined(NimrodVM) and not defined(JS): proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} = ## performs a deep copy of `x`. This is also used by the code generator ## for the implementation of ``spawn``. @@ -3250,4 +3406,20 @@ proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} = ## overloaded ``[]`` or ``[]=`` accessors. discard -{.pop.} #{.push warning[GcMem]: off.} +template `..^`*(a, b: expr): expr = + ## a shortcut for '.. ^' to avoid the common gotcha that a space between + ## '..' and '^' is required. + a .. ^b + +template `..<`*(a, b: expr): expr = + ## a shortcut for '.. <' to avoid the common gotcha that a space between + ## '..' and '<' is required. + a .. <b + +proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard +proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} = + ## returns the length of a sequence or a string without testing for 'nil'. + ## This is an optimization that rarely makes sense. + discard + +{.pop.} #{.push warning[GcMem]: off, warning[Uninit]: off.} |