diff options
Diffstat (limited to 'lib/system.nim')
-rw-r--r-- | lib/system.nim | 3276 |
1 files changed, 3276 insertions, 0 deletions
diff --git a/lib/system.nim b/lib/system.nim new file mode 100644 index 000000000..a4b053ca7 --- /dev/null +++ b/lib/system.nim @@ -0,0 +1,3276 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## The compiler depends on the System module to work properly and the System +## module depends on the compiler. Most of the routines listed here use +## special compiler magic. +## Each module implicitly imports the System module; it must not be listed +## explicitly. Because of this there cannot be a user-defined module named +## ``system``. +## +## Exception hierarchy +## =================== +## +## For visual convenience here is the exception inheritance hierarchy +## represented as a tree: +## +## .. include:: ../doc/exception_hierarchy_fragment.txt +## +## Module system +## ============= +## + +# That lonesome header above is to prevent :idx: entries from being mentioned +# in the global index as part of the previous header (Exception hierarchy). + +type + int* {.magic: Int.} ## default integer type; bitwidth depends on + ## architecture, but is always the same as a pointer + int8* {.magic: Int8.} ## signed 8 bit integer type + int16* {.magic: Int16.} ## signed 16 bit integer type + int32* {.magic: Int32.} ## signed 32 bit integer type + int64* {.magic: Int64.} ## signed 64 bit integer type + uint* {.magic: UInt.} ## unsigned default integer type + uint8* {.magic: UInt8.} ## unsigned 8 bit integer type + uint16* {.magic: UInt16.} ## unsigned 16 bit integer type + uint32* {.magic: UInt32.} ## unsigned 32 bit integer type + uint64* {.magic: UInt64.} ## unsigned 64 bit integer type + float* {.magic: Float.} ## default floating point type + float32* {.magic: Float32.} ## 32 bit floating point type + float64* {.magic: Float.} ## 64 bit floating point type + +# 'float64' is now an alias to 'float'; this solves many problems + +type # we need to start a new type section here, so that ``0`` can have a type + bool* {.magic: Bool.} = enum ## built-in boolean type + false = 0, true = 1 + +type + char* {.magic: Char.} ## built-in 8 bit character type (unsigned) + string* {.magic: String.} ## built-in string type + cstring* {.magic: Cstring.} ## built-in cstring (*compatible string*) type + pointer* {.magic: Pointer.} ## built-in pointer type, use the ``addr`` + ## operator to get a pointer to a variable +const + on* = true ## alias for ``true`` + off* = false ## alias for ``false`` + +{.push warning[GcMem]: off, warning[Uninit]: off.} +{.push hints: off.} + +type + Ordinal* {.magic: Ordinal.}[T] + `ptr`* {.magic: Pointer.}[T] ## built-in generic untraced pointer type + `ref`* {.magic: Pointer.}[T] ## built-in generic traced pointer type + + `nil` {.magic: "Nil".} + expr* {.magic: Expr.} ## meta type to denote an expression (for templates) + stmt* {.magic: Stmt.} ## meta type to denote a statement (for templates) + typedesc* {.magic: TypeDesc.} ## meta type to denote a type description + void* {.magic: "VoidType".} ## meta type to denote the absence of any type + auto* = expr + any* = distinct auto + 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 + ## is resolved (for templates) + + SomeSignedInt* = int|int8|int16|int32|int64 + ## type class matching all signed integer types + + SomeUnsignedInt* = uint|uint8|uint16|uint32|uint64 + ## type class matching all unsigned integer types + + SomeInteger* = SomeSignedInt|SomeUnsignedInt + ## type class matching all integer types + + SomeOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32 + ## type class matching all ordinal types; however this includes enums with + ## holes. + + SomeReal* = float|float32|float64 + ## type class matching all floating point number types + + SomeNumber* = SomeInteger|SomeReal + ## type class matching all number types + +proc defined*(x: expr): bool {.magic: "Defined", noSideEffect.} + ## Special compile-time procedure that checks whether `x` is + ## defined. + ## `x` is an external symbol introduced through the compiler's + ## `-d:x switch <nimc.html#compile-time-symbols>`_ to enable build time + ## conditionals: + ## + ## .. code-block:: Nim + ## when not defined(release): + ## # Do here programmer friendly expensive sanity checks. + ## # Put here the normal code + +when defined(nimalias): + {.deprecated: [ + TSignedInt: SomeSignedInt, + TUnsignedInt: SomeUnsignedInt, + TInteger: SomeInteger, + TReal: SomeReal, + TNumber: SomeNumber, + TOrdinal: SomeOrdinal].} + +proc declared*(x: expr): bool {.magic: "Defined", noSideEffect.} + ## Special compile-time procedure that checks whether `x` is + ## declared. `x` has to be an identifier or a qualified identifier. + ## This can be used to check whether a library provides a certain + ## feature or not: + ## + ## .. code-block:: Nim + ## when not declared(strutils.toUpper): + ## # provide our own toUpper proc here, because strutils is + ## # missing it. + +when defined(useNimRtl): + {.deadCodeElim: on.} + +proc definedInScope*(x: expr): bool {. + magic: "DefinedInScope", noSideEffect, deprecated.} + ## **Deprecated since version 0.9.6**: Use ``declaredInScope`` instead. + +proc declaredInScope*(x: expr): bool {. + magic: "DefinedInScope", noSideEffect.} + ## Special compile-time procedure that checks whether `x` is + ## declared in the current scope. `x` has to be an identifier. + +proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} = + ## Builtin 'addr' operator for taking the address of a memory location. + ## Cannot be overloaded. + discard + +proc `type`*(x: expr): typeDesc {.magic: "TypeOf", noSideEffect.} = + ## Builtin 'type' operator for accessing the type of an expression. + ## Cannot be overloaded. + discard + +proc `not` *(x: bool): bool {.magic: "Not", noSideEffect.} + ## Boolean not; returns true iff ``x == false``. + +proc `and`*(x, y: bool): bool {.magic: "And", noSideEffect.} + ## Boolean ``and``; returns true iff ``x == y == true``. + ## Evaluation is lazy: if ``x`` is false, + ## ``y`` will not even be evaluated. +proc `or`*(x, y: bool): bool {.magic: "Or", noSideEffect.} + ## Boolean ``or``; returns true iff ``not (not x and not y)``. + ## Evaluation is lazy: if ``x`` is true, + ## ``y`` will not even be evaluated. +proc `xor`*(x, y: bool): bool {.magic: "Xor", noSideEffect.} + ## Boolean `exclusive or`; returns true iff ``x != y``. + +proc new*[T](a: var ref T) {.magic: "New", noSideEffect.} + ## creates a new object of type ``T`` and returns a safe (traced) + ## reference to it in ``a``. + +proc new*(T: typedesc): ref T = + ## creates a new object of type ``T`` and returns a safe (traced) + ## reference to it as result value + new(result) + +proc internalNew*[T](a: var ref T) {.magic: "New", noSideEffect.} + ## leaked implementation detail. Do not use. + +proc new*[T](a: var ref T, finalizer: proc (x: ref T) {.nimcall.}) {. + magic: "NewFinalize", noSideEffect.} + ## creates a new object of type ``T`` and returns a safe (traced) + ## reference to it in ``a``. When the garbage collector frees the object, + ## `finalizer` is called. The `finalizer` may not keep a reference to the + ## object pointed to by `x`. The `finalizer` cannot prevent the GC from + ## freeing the object. Note: The `finalizer` refers to the type `T`, not to + ## the object! This means that for each object of type `T` the finalizer + ## will be called! + +proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.} + ## resets an object `obj` to its initial (binary zero) value. This needs to + ## be called before any possible `object branch transition`:idx:. + +# for low and high the return type T may not be correct, but +# we handle that with compiler magic in semLowHigh() +proc high*[T](x: T): T {.magic: "High", noSideEffect.} + ## returns the highest possible index of an array, a sequence, a string or + ## the highest possible value of an ordinal value `x`. As a special + ## semantic rule, `x` may also be a type identifier. + ## ``high(int)`` is Nim's way of writing `INT_MAX`:idx: or `MAX_INT`:idx:. + +proc low*[T](x: T): T {.magic: "Low", noSideEffect.} + ## returns the lowest possible index of an array, a sequence, a string or + ## the lowest possible value of an ordinal value `x`. As a special + ## semantic rule, `x` may also be a type identifier. + +type + range*{.magic: "Range".}[T] ## Generic type to construct range types. + array*{.magic: "Array".}[I, T] ## Generic type to construct + ## fixed-length arrays. + openArray*{.magic: "OpenArray".}[T] ## Generic type to construct open arrays. + ## Open arrays are implemented as a + ## pointer to the array data and a + ## length field. + varargs*{.magic: "Varargs".}[T] ## Generic type to construct a varargs type. + seq*{.magic: "Seq".}[T] ## Generic type to construct sequences. + set*{.magic: "Set".}[T] ## Generic type to construct bit sets. + +type + Slice*[T] = object ## builtin slice type + a*, b*: T ## the bounds + +when defined(nimalias): + {.deprecated: [TSlice: Slice].} + +proc `..`*[T](a, b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} = + ## `slice`:idx: operator that constructs an interval ``[a, b]``, both `a` + ## and `b` are inclusive. Slices can also be used in the set constructor + ## and in ordinal case statements, but then they are special-cased by the + ## compiler. + result.a = a + result.b = b + +proc `..`*[T](b: T): Slice[T] {.noSideEffect, inline, magic: "DotDot".} = + ## `slice`:idx: operator that constructs an interval ``[default(T), b]`` + result.b = b + +when not defined(niminheritable): + {.pragma: inheritable.} +when not defined(nimunion): + {.pragma: unchecked.} + +when defined(nimNewShared): + type + `shared`* {.magic: "Shared".} + guarded* {.magic: "Guarded".} + +# comparison operators: +proc `==` *[TEnum: enum](x, y: TEnum): bool {.magic: "EqEnum", noSideEffect.} +proc `==` *(x, y: pointer): bool {.magic: "EqRef", noSideEffect.} +proc `==` *(x, y: string): bool {.magic: "EqStr", noSideEffect.} +proc `==` *(x, y: cstring): bool {.magic: "EqCString", noSideEffect.} +proc `==` *(x, y: char): bool {.magic: "EqCh", noSideEffect.} +proc `==` *(x, y: bool): bool {.magic: "EqB", noSideEffect.} +proc `==` *[T](x, y: set[T]): bool {.magic: "EqSet", noSideEffect.} +proc `==` *[T](x, y: ref T): bool {.magic: "EqRef", noSideEffect.} +proc `==` *[T](x, y: ptr T): bool {.magic: "EqRef", noSideEffect.} +proc `==` *[T: proc](x, y: T): bool {.magic: "EqProc", noSideEffect.} + +proc `<=` *[TEnum: enum](x, y: TEnum): 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.} +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 `<` *(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.} +proc `<` *(x, y: bool): bool {.magic: "LtB", noSideEffect.} +proc `<` *[T](x, y: ref T): bool {.magic: "LtPtr", noSideEffect.} +proc `<` *[T](x, y: ptr T): bool {.magic: "LtPtr", noSideEffect.} +proc `<` *(x, y: pointer): bool {.magic: "LtPtr", noSideEffect.} + +template `!=` * (x, y: expr): expr {.immediate.} = + ## unequals operator. This is a shorthand for ``not (x == y)``. + not (x == y) + +template `>=` * (x, y: expr): expr {.immediate.} = + ## "is greater or equals" operator. This is the same as ``y <= x``. + y <= x + +template `>` * (x, y: expr): expr {.immediate.} = + ## "is greater" operator. This is the same as ``y < x``. + y < x + +const + appType* {.magic: "AppType"}: string = "" + ## a string that describes the application type. Possible values: + ## "console", "gui", "lib". + +include "system/inclrtl" + +const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \ + ## "fake variables" like 'var EBADF {.importc.}: cint'. + +const ArrayDummySize = when defined(cpu16): 10_000 else: 100_000_000 + +when not defined(JS): + type + TGenericSeq {.compilerproc, pure, inheritable.} = object + len, reserved: int + PGenericSeq {.exportc.} = ptr TGenericSeq + UncheckedCharArray {.unchecked.} = array[0..ArrayDummySize, char] + # len and space without counting the terminating zero: + NimStringDesc {.compilerproc, final.} = object of TGenericSeq + data: UncheckedCharArray + NimString = ptr NimStringDesc + +when not defined(JS) and not defined(NimrodVM): + template space(s: PGenericSeq): int {.dirty.} = + s.reserved and not seqShallowFlag + + include "system/hti" + +type + byte* = uint8 ## this is an alias for ``uint8``, that is an unsigned + ## int 8 bits wide. + + Natural* = range[0..high(int)] + ## is an int type ranging from zero to the maximum value + ## of an int. This type is often useful for documentation and debugging. + + Positive* = range[1..high(int)] + ## is an int type ranging from one to the maximum value + ## of an int. This type is often useful for documentation and debugging. + + RootObj* {.exportc: "TNimObject", inheritable.} = + object ## the root of Nim's object hierarchy. Objects should + ## inherit from TObject or one of its descendants. However, + ## objects that have no ancestor are allowed. + RootRef* = ref RootObj ## reference to RootObj + + RootEffect* {.compilerproc.} = object of RootObj ## \ + ## base effect class; each effect should + ## inherit from `TEffect` unless you know what + ## you doing. + TimeEffect* = object of RootEffect ## Time effect. + IOEffect* = object of RootEffect ## IO effect. + ReadIOEffect* = object of IOEffect ## Effect describing a read IO operation. + WriteIOEffect* = object of IOEffect ## Effect describing a write IO operation. + ExecIOEffect* = object of IOEffect ## Effect describing an executing IO operation. + + Exception* {.compilerproc.} = object of RootObj ## \ + ## Base exception class. + ## + ## 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. + msg* {.exportc: "message".}: string ## the exception's message. Not + ## providing an exception message + ## is bad style. + trace: string + + SystemError* = object of Exception ## \ + ## Abstract class for exceptions that the runtime system raises. + ## + ## See the full `exception hierarchy`_. + IOError* = object of SystemError ## \ + ## Raised if an IO error occurred. + ## + ## See the full `exception hierarchy`_. + OSError* = object of SystemError ## \ + ## Raised if an operating system service failed. + ## + ## See the full `exception hierarchy`_. + errorCode*: int32 ## OS-defined error code describing this error. + LibraryError* = object of OSError ## \ + ## Raised if a dynamic library could not be loaded. + ## + ## See the full `exception hierarchy`_. + ResourceExhaustedError* = object of SystemError ## \ + ## Raised if a resource request could not be fulfilled. + ## + ## See the full `exception hierarchy`_. + ArithmeticError* = object of Exception ## \ + ## Raised if any kind of arithmetic error occurred. + ## + ## See the full `exception hierarchy`_. + DivByZeroError* = object of ArithmeticError ## \ + ## Raised for runtime integer divide-by-zero errors. + ## + ## See the full `exception hierarchy`_. + + OverflowError* = object of ArithmeticError ## \ + ## Raised for runtime integer overflows. + ## + ## This happens for calculations whose results are too large to fit in the + ## provided bits. See the full `exception hierarchy`_. + AccessViolationError* = object of Exception ## \ + ## Raised for invalid memory access errors + ## + ## See the full `exception hierarchy`_. + AssertionError* = object of Exception ## \ + ## Raised when assertion is proved wrong. + ## + ## Usually the result of using the `assert() template <#assert>`_. See the + ## full `exception hierarchy`_. + ValueError* = object of Exception ## \ + ## Raised for string and object conversion errors. + KeyError* = object of ValueError ## \ + ## Raised if a key cannot be found in a table. + ## + ## Mostly used by the `tables <tables.html>`_ module, it can also be raised + ## by other collection modules like `sets <sets.html>`_ or `strtabs + ## <strtabs.html>`_. See the full `exception hierarchy`_. + OutOfMemError* = object of SystemError ## \ + ## Raised for unsuccessful attempts to allocate memory. + ## + ## See the full `exception hierarchy`_. + IndexError* = object of Exception ## \ + ## Raised if an array index is out of bounds. + ## + ## See the full `exception hierarchy`_. + + FieldError* = object of Exception ## \ + ## Raised if a record field is not accessible because its dicriminant's + ## value does not fit. + ## + ## See the full `exception hierarchy`_. + RangeError* = object of Exception ## \ + ## Raised if a range check error occurred. + ## + ## See the full `exception hierarchy`_. + StackOverflowError* = object of SystemError ## \ + ## Raised if the hardware stack used for subroutine calls overflowed. + ## + ## See the full `exception hierarchy`_. + ReraiseError* = object of Exception ## \ + ## Raised if there is no exception to reraise. + ## + ## See the full `exception hierarchy`_. + ObjectAssignmentError* = object of Exception ## \ + ## Raised if an object gets assigned to its parent's object. + ## + ## See the full `exception hierarchy`_. + ObjectConversionError* = object of Exception ## \ + ## Raised if an object is converted to an incompatible object type. + ## + ## See the full `exception hierarchy`_. + FloatingPointError* = object of Exception ## \ + ## Base class for floating point exceptions. + ## + ## See the full `exception hierarchy`_. + FloatInvalidOpError* = object of FloatingPointError ## \ + ## Raised by invalid operations according to IEEE. + ## + ## Raised by ``0.0/0.0``, for example. See the full `exception + ## hierarchy`_. + FloatDivByZeroError* = object of FloatingPointError ## \ + ## Raised by division by zero. + ## + ## Divisor is zero and dividend is a finite nonzero number. See the full + ## `exception hierarchy`_. + FloatOverflowError* = object of FloatingPointError ## \ + ## Raised for overflows. + ## + ## The operation produced a result that exceeds the range of the exponent. + ## See the full `exception hierarchy`_. + FloatUnderflowError* = object of FloatingPointError ## \ + ## Raised for underflows. + ## + ## The operation produced a result that is too small to be represented as a + ## normal number. See the full `exception hierarchy`_. + FloatInexactError* = object of FloatingPointError ## \ + ## Raised for inexact results. + ## + ## The operation produced a result that cannot be represented with infinite + ## precision -- for example: ``2.0 / 3.0, log(1.1)`` + ## + ## **NOTE**: Nim currently does not detect these! See the full + ## `exception hierarchy`_. + DeadThreadError* = object of Exception ## \ + ## Raised if it is attempted to send a message to a dead thread. + ## + ## See the full `exception hierarchy`_. + + TResult* {.deprecated.} = enum Failure, Success + +{.deprecated: [TObject: RootObj, PObject: RootRef, TEffect: RootEffect, + FTime: TimeEffect, FIO: IOEffect, FReadIO: ReadIOEffect, + FWriteIO: WriteIOEffect, FExecIO: ExecIOEffect, + + E_Base: Exception, ESystem: SystemError, EIO: IOError, + EOS: OSError, EInvalidLibrary: LibraryError, + EResourceExhausted: ResourceExhaustedError, + EArithmetic: ArithmeticError, EDivByZero: DivByZeroError, + EOverflow: OverflowError, EAccessViolation: AccessViolationError, + EAssertionFailed: AssertionError, EInvalidValue: ValueError, + EInvalidKey: KeyError, EOutOfMemory: OutOfMemError, + EInvalidIndex: IndexError, EInvalidField: FieldError, + EOutOfRange: RangeError, EStackOverflow: StackOverflowError, + ENoExceptionToReraise: ReraiseError, + EInvalidObjectAssignment: ObjectAssignmentError, + EInvalidObjectConversion: ObjectConversionError, + EDeadThread: DeadThreadError, + EFloatInexact: FloatInexactError, + EFloatUnderflow: FloatUnderflowError, + EFloatingPoint: FloatingPointError, + EFloatInvalidOp: FloatInvalidOpError, + EFloatDivByZero: FloatDivByZeroError, + EFloatOverflow: FloatOverflowError, + ESynch: Exception +].} + +proc unsafeNew*[T](a: var ref T, size: Natural) {.magic: "New", noSideEffect.} + ## creates a new object of type ``T`` and returns a safe (traced) + ## reference to it in ``a``. This is **unsafe** as it allocates an object + ## of the passed ``size``. This should only be used for optimization + ## purposes when you know what you're doing! + +proc sizeof*[T](x: T): int {.magic: "SizeOf", noSideEffect.} + ## returns the size of ``x`` in bytes. Since this is a low-level proc, + ## its usage is discouraged - using ``new`` for the most cases suffices + ## that one never needs to know ``x``'s size. As a special semantic rule, + ## ``x`` may also be a type identifier (``sizeof(int)`` is valid). + +proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.} + ## unary ``<`` that can be used for nice looking excluding ranges: + ## + ## .. code-block:: nim + ## for i in 0 .. <10: echo i + ## + ## Semantically this is the same as ``pred``. + +proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.} + ## returns the ``y``-th successor of the value ``x``. ``T`` has to be + ## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised + ## or a compile time error occurs. + +proc pred*[T](x: Ordinal[T], y = 1): T {.magic: "Pred", noSideEffect.} + ## returns the ``y``-th predecessor of the value ``x``. ``T`` has to be + ## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised + ## or a compile time error occurs. + +proc inc*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Inc", noSideEffect.} + ## increments the ordinal ``x`` by ``y``. If such a value does not + ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a + ## short notation for: ``x = succ(x, y)``. + +proc dec*[T: Ordinal|uint|uint64](x: var T, y = 1) {.magic: "Dec", noSideEffect.} + ## decrements the ordinal ``x`` by ``y``. If such a value does not + ## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a + ## short notation for: ``x = pred(x, y)``. + +proc newSeq*[T](s: var seq[T], len: Natural) {.magic: "NewSeq", noSideEffect.} + ## creates a new sequence of type ``seq[T]`` with length ``len``. + ## This is equivalent to ``s = @[]; setlen(s, len)``, but more + ## efficient since no reallocation is needed. + ## + ## Note that the sequence will be filled with zeroed entries, which can be a + ## problem for sequences containing strings since their value will be + ## ``nil``. After the creation of the sequence you should assign entries to + ## the sequence instead of adding them. Example: + ## + ## .. code-block:: nim + ## var inputStrings : seq[string] + ## newSeq(inputStrings, 3) + ## inputStrings[0] = "The fourth" + ## inputStrings[1] = "assignment" + ## inputStrings[2] = "would crash" + ## #inputStrings[3] = "out of bounds" + +proc newSeq*[T](len = 0.Natural): seq[T] = + ## creates a new sequence of type ``seq[T]`` with length ``len``. + ## + ## Note that the sequence will be filled with zeroed entries, which can be a + ## problem for sequences containing strings since their value will be + ## ``nil``. After the creation of the sequence you should assign entries to + ## the sequence instead of adding them. Example: + ## + ## .. code-block:: nim + ## var inputStrings = newSeq[string](3) + ## inputStrings[0] = "The fourth" + ## inputStrings[1] = "assignment" + ## inputStrings[2] = "would crash" + ## #inputStrings[3] = "out of bounds" + newSeq(result, len) + +proc len*[TOpenArray: openArray|varargs](x: TOpenArray): int {. + magic: "LengthOpenArray", noSideEffect.} +proc len*(x: string): int {.magic: "LengthStr", noSideEffect.} +proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.} +proc len*[I, T](x: array[I, T]): int {.magic: "LengthArray", noSideEffect.} +proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.} + ## returns the length of an array, an openarray, a sequence or a string. + ## This is roughly the same as ``high(T)-low(T)+1``, but its resulting type is + ## always an int. + +# set routines: +proc incl*[T](x: var set[T], y: T) {.magic: "Incl", noSideEffect.} + ## includes element ``y`` to the set ``x``. This is the same as + ## ``x = x + {y}``, but it might be more efficient. + +template incl*[T](s: var set[T], flags: set[T]) = + ## includes the set of flags to the set ``x``. + s = s + flags + +proc excl*[T](x: var set[T], y: T) {.magic: "Excl", noSideEffect.} + ## excludes element ``y`` to the set ``x``. This is the same as + ## ``x = x - {y}``, but it might be more efficient. + +template excl*[T](s: var set[T], flags: set[T]) = + ## excludes the set of flags to ``x``. + s = s - flags + +proc card*[T](x: set[T]): int {.magic: "Card", noSideEffect.} + ## returns the cardinality of the set ``x``, i.e. the number of elements + ## in the set. + +proc ord*[T](x: T): int {.magic: "Ord", noSideEffect.} + ## returns the internal int value of an ordinal value ``x``. + +proc chr*(u: range[0..255]): char {.magic: "Chr", noSideEffect.} + ## converts an int in the range 0..255 to a character. + +# -------------------------------------------------------------------------- +# built-in operators + +when not defined(JS): + proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.} + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.} + ## zero extends a smaller integer type to ``int``. This treats `x` as + ## unsigned. + + proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + + proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. + proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect.} + ## zero extends a smaller integer type to ``int64``. This treats `x` as + ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``. + ## (This is the case on 64 bit processors.) + + proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.} + ## treats `x` as unsigned and converts it to a byte by taking the last 8 bits + ## from `x`. + proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.} + ## treats `x` as unsigned and converts it to an ``int16`` by taking the last + ## 16 bits from `x`. + proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect.} + ## treats `x` as unsigned and converts it to an ``int32`` by taking the + ## last 32 bits from `x`. + +# integer calculations: +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: "UnaryPlusI", noSideEffect.} + ## Unary `+` operator for an integer. Has no effect. + +proc `-` *(x: int): int {.magic: "UnaryMinusI", noSideEffect.} +proc `-` *(x: int8): int8 {.magic: "UnaryMinusI", noSideEffect.} +proc `-` *(x: int16): int16 {.magic: "UnaryMinusI", noSideEffect.} +proc `-` *(x: int32): int32 {.magic: "UnaryMinusI", noSideEffect.} +proc `-` *(x: int64): int64 {.magic: "UnaryMinusI64", noSideEffect.} + ## Unary `-` operator for an integer. Negates `x`. + +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`. + +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. + +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. + +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. + +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)``. + ## + ## .. code-block:: Nim + ## 1 div 2 == 0 + ## 2 div 2 == 1 + ## 3 div 2 == 1 + +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``. + +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.} + ## computes the `shift right` operation of `x` and `y`. + ## + ## .. code-block:: Nim + ## 0b0001_0000'i8 shr 2 == 0b0100_0000'i8 + ## 0b1000_0000'i8 shr 2 == 0b0000_0000'i8 + ## 0b0000_0001'i8 shr 9 == 0b0000_0000'i8 + +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.} + ## 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.} + ## 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.} + ## 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.} + ## 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.} + ## 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.} + ## 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.} + ## Returns true iff `x` is less than `y`. + +type + IntMax32 = int|int8|int16|int32 + +proc `+%` *(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.} +proc `+%` *(x, y: int64): int64 {.magic: "AddU", noSideEffect.} + ## treats `x` and `y` as unsigned and adds them. The result is truncated to + ## fit into the result. This implements modulo arithmetic. No overflow + ## errors are possible. + +proc `-%` *(x, y: IntMax32): IntMax32 {.magic: "SubU", noSideEffect.} +proc `-%` *(x, y: int64): int64 {.magic: "SubU", noSideEffect.} + ## treats `x` and `y` as unsigned and subtracts them. The result is + ## truncated to fit into the result. This implements modulo arithmetic. + ## No overflow errors are possible. + +proc `*%` *(x, y: IntMax32): IntMax32 {.magic: "MulU", noSideEffect.} +proc `*%` *(x, y: int64): int64 {.magic: "MulU", noSideEffect.} + ## treats `x` and `y` as unsigned and multiplies them. The result is + ## truncated to fit into the result. This implements modulo arithmetic. + ## No overflow errors are possible. + +proc `/%` *(x, y: IntMax32): IntMax32 {.magic: "DivU", noSideEffect.} +proc `/%` *(x, y: int64): int64 {.magic: "DivU", noSideEffect.} + ## treats `x` and `y` as unsigned and divides them. The result is + ## truncated to fit into the result. This implements modulo arithmetic. + ## No overflow errors are possible. + +proc `%%` *(x, y: IntMax32): IntMax32 {.magic: "ModU", noSideEffect.} +proc `%%` *(x, y: int64): int64 {.magic: "ModU", noSideEffect.} + ## treats `x` and `y` as unsigned and compute the modulo of `x` and `y`. + ## The result is truncated to fit into the result. + ## This implements modulo arithmetic. + ## No overflow errors are possible. + +proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.} +proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.} + ## treats `x` and `y` as unsigned and compares them. + ## Returns true iff ``unsigned(x) <= unsigned(y)``. + +proc `<%` *(x, y: IntMax32): bool {.magic: "LtU", noSideEffect.} +proc `<%` *(x, y: int64): bool {.magic: "LtU64", noSideEffect.} + ## treats `x` and `y` as unsigned and compares them. + ## 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.} +proc `-` *(x, y: float32): float32 {.magic: "SubF64", noSideEffect.} +proc `*` *(x, y: float32): float32 {.magic: "MulF64", noSideEffect.} +proc `/` *(x, y: float32): float32 {.magic: "DivF64", noSideEffect.} + +proc `+` *(x: float): float {.magic: "UnaryPlusF64", noSideEffect.} +proc `-` *(x: float): float {.magic: "UnaryMinusF64", noSideEffect.} +proc `+` *(x, y: float): float {.magic: "AddF64", noSideEffect.} +proc `-` *(x, y: float): float {.magic: "SubF64", noSideEffect.} +proc `*` *(x, y: float): float {.magic: "MulF64", noSideEffect.} +proc `/` *(x, y: float): float {.magic: "DivF64", noSideEffect.} + ## computes the floating point division + +proc `==` *(x, y: float32): bool {.magic: "EqF64", noSideEffect.} +proc `<=` *(x, y: float32): bool {.magic: "LeF64", noSideEffect.} +proc `<` *(x, y: float32): bool {.magic: "LtF64", noSideEffect.} + +proc `==` *(x, y: float): bool {.magic: "EqF64", noSideEffect.} +proc `<=` *(x, y: float): bool {.magic: "LeF64", noSideEffect.} +proc `<` *(x, y: float): bool {.magic: "LtF64", noSideEffect.} + +# set operators +proc `*` *[T](x, y: set[T]): set[T] {.magic: "MulSet", noSideEffect.} + ## This operator computes the intersection of two sets. +proc `+` *[T](x, y: set[T]): set[T] {.magic: "PlusSet", noSideEffect.} + ## This operator computes the union of two sets. +proc `-` *[T](x, y: set[T]): set[T] {.magic: "MinusSet", noSideEffect.} + ## This operator computes the difference of two sets. + +proc contains*[T](x: set[T], y: T): bool {.magic: "InSet", noSideEffect.} + ## One should overload this proc if one wants to overload the ``in`` operator. + ## The parameters are in reverse order! ``a in b`` is a template for + ## ``contains(b, a)``. + ## This is because the unification algorithm that Nim uses for overload + ## resolution works from left to right. + ## But for the ``in`` operator that would be the wrong direction for this + ## piece of code: + ## + ## .. code-block:: Nim + ## var s: set[range['a'..'z']] = {'a'..'c'} + ## writeln(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 + ## ``set[char]``! The solution is to bind ``T`` to ``range['a'..'z']``. This + ## is achieved by reversing the parameters for ``contains``; ``in`` then + ## passes its arguments in reverse order. + +proc contains*[T](s: Slice[T], value: T): bool {.noSideEffect, inline.} = + ## Checks if `value` is within the range of `s`; returns true iff + ## `value >= s.a and value <= s.b` + ## + ## .. code-block:: Nim + ## assert((1..3).contains(1) == true) + ## assert((1..3).contains(2) == true) + ## assert((1..3).contains(4) == false) + result = s.a <= value and value <= s.b + +template `in` * (x, y: expr): expr {.immediate, dirty.} = contains(y, x) + ## Sugar for contains + ## + ## .. code-block:: Nim + ## assert(1 in (1..3) == true) + ## assert(5 in (1..3) == false) +template `notin` * (x, y: expr): expr {.immediate, dirty.} = not contains(y, x) + ## Sugar for not containing + ## + ## .. code-block:: Nim + ## assert(1 notin (1..3) == false) + ## assert(5 notin (1..3) == true) + +proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.} + ## Checks if T is of the same type as S + ## + ## .. code-block:: Nim + ## proc test[T](a: T): int = + ## when (T is int): + ## return a + ## else: + ## return 0 + ## + ## assert(test[int](3) == 3) + ## assert(test[string]("xyz") == 0) +template `isnot` *(x, y: expr): expr {.immediate.} = not (x is y) + ## Negated version of `is`. Equivalent to ``not(x is y)``. + +proc `of` *[T, S](x: T, y: S): bool {.magic: "Of", noSideEffect.} + ## Checks if `x` has a type of `y` + ## + ## .. code-block:: Nim + ## assert(FloatingPointError of Exception) + ## assert(DivByZeroError of Exception) + +proc cmp*[T](x, y: T): int {.procvar.} = + ## Generic compare proc. Returns a value < 0 iff x < y, a value > 0 iff x > y + ## and 0 iff x == y. This is useful for writing generic algorithms without + ## performance loss. This generic implementation uses the `==` and `<` + ## operators. + if x == y: return 0 + if x < y: return -1 + return 1 + +proc cmp*(x, y: string): int {.noSideEffect, procvar.} + ## Compare proc for strings. More efficient than the generic version. + +proc `@` * [IDX, T](a: array[IDX, T]): seq[T] {. + magic: "ArrToSeq", nosideeffect.} + ## turns an array into a sequence. This most often useful for constructing + ## sequences with the array constructor: ``@[1, 2, 3]`` has the type + ## ``seq[int]``, while ``[1, 2, 3]`` has the type ``array[0..2, int]``. + +proc setLen*[T](s: var seq[T], newlen: Natural) {. + magic: "SetLengthSeq", noSideEffect.} + ## sets the length of `s` to `newlen`. + ## ``T`` may be any sequence type. + ## If the current length is greater than the new length, + ## ``s`` will be truncated. `s` cannot be nil! To initialize a sequence with + ## a size, use ``newSeq`` instead. + +proc setLen*(s: var string, newlen: Natural) {. + magic: "SetLengthStr", noSideEffect.} + ## sets the length of `s` to `newlen`. + ## If the current length is greater than the new length, + ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with + ## a size, use ``newString`` instead. + +proc newString*(len: Natural): string {. + magic: "NewString", importc: "mnewString", noSideEffect.} + ## returns a new string of length ``len`` but with uninitialized + ## content. One needs to fill the string character after character + ## with the index operator ``s[i]``. This procedure exists only for + ## optimization purposes; the same effect can be achieved with the + ## ``&`` operator or with ``add``. + +proc newStringOfCap*(cap: Natural): string {. + magic: "NewStringOfCap", importc: "rawNewString", noSideEffect.} + ## returns a new string of length ``0`` but with capacity `cap`.This + ## procedure exists only for optimization purposes; the same effect can + ## be achieved with the ``&`` operator or with ``add``. + +proc `&` * (x: string, y: char): string {. + magic: "ConStrStr", noSideEffect, merge.} + ## Concatenates `x` with `y` + ## + ## .. code-block:: Nim + ## assert("ab" & 'c' == "abc") +proc `&` * (x: char, y: char): string {. + magic: "ConStrStr", noSideEffect, merge.} + ## Concatenates `x` and `y` into a string + ## + ## .. code-block:: Nim + ## assert('a' & 'b' == "ab") +proc `&` * (x, y: string): string {. + magic: "ConStrStr", noSideEffect, merge.} + ## Concatenates `x` and `y` + ## + ## .. code-block:: Nim + ## assert("ab" & "cd" == "abcd") +proc `&` * (x: char, y: string): string {. + magic: "ConStrStr", noSideEffect, merge.} + ## Concatenates `x` with `y` + ## + ## .. code-block:: Nim + ## assert('a' & "bc" == "abc") + +# implementation note: These must all have the same magic value "ConStrStr" so +# that the merge optimization works properly. + +proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.} + ## Appends `y` to `x` in place + ## + ## .. code-block:: Nim + ## var tmp = "" + ## tmp.add('a') + ## tmp.add('b') + ## assert(tmp == "ab") +proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} + ## Concatenates `x` and `y` in place + ## + ## .. code-block:: Nim + ## var tmp = "" + ## tmp.add("ab") + ## tmp.add("cd") + ## assert(tmp == "abcd") + +type + Endianness* = enum ## is a type describing the endianness of a processor. + littleEndian, bigEndian + +const + isMainModule* {.magic: "IsMainModule".}: bool = false + ## is true only when accessed in the main module. This works thanks to + ## compiler magic. It is useful to embed testing code in a module. + + CompileDate* {.magic: "CompileDate"}: string = "0000-00-00" + ## is the date of compilation as a string of the form + ## ``YYYY-MM-DD``. This works thanks to compiler magic. + + CompileTime* {.magic: "CompileTime"}: string = "00:00:00" + ## is the time of compilation as a string of the form + ## ``HH:MM:SS``. This works thanks to compiler magic. + + cpuEndian* {.magic: "CpuEndian"}: Endianness = littleEndian + ## is the endianness of the target CPU. This is a valuable piece of + ## information for low-level code only. This works thanks to compiler + ## magic. + + hostOS* {.magic: "HostOS".}: string = "" + ## a string that describes the host operating system. Possible values: + ## "windows", "macosx", "linux", "netbsd", "freebsd", "openbsd", "solaris", + ## "aix", "standalone". + + hostCPU* {.magic: "HostCPU".}: string = "" + ## a string that describes the host CPU. Possible values: + ## "i386", "alpha", "powerpc", "powerpc64", "sparc", "amd64", "mips", "arm". + + seqShallowFlag = low(int) + +proc compileOption*(option: string): bool {. + magic: "CompileOption", noSideEffect.} + ## can be used to determine an on|off compile-time option. Example: + ## + ## .. code-block:: nim + ## when compileOption("floatchecks"): + ## echo "compiled with floating point NaN and Inf checks" + +proc compileOption*(option, arg: string): bool {. + magic: "CompileOptionArg", noSideEffect.} + ## can be used to determine an enum compile-time option. Example: + ## + ## .. code-block:: nim + ## when compileOption("opt", "size") and compileOption("gc", "boehm"): + ## echo "compiled with optimization for size and uses Boehm's GC" + +const + hasThreadSupport = compileOption("threads") + hasSharedHeap = defined(boehmgc) # don't share heaps; every thread has its own + taintMode = compileOption("taintmode") + +when taintMode: + type TaintedString* = distinct string ## a distinct string type that + ## is `tainted`:idx:. It is an alias for + ## ``string`` if the taint mode is not + ## turned on. Use the ``-d:taintMode`` + ## command line switch to turn the taint + ## mode on. + + proc len*(s: TaintedString): int {.borrow.} +else: + type TaintedString* = string ## a distinct string type that + ## is `tainted`:idx:. It is an alias for + ## ``string`` if the taint mode is not + ## turned on. Use the ``-d:taintMode`` + ## command line switch to turn the taint + ## mode on. + +when defined(profiler): + proc nimProfile() {.compilerProc, noinline.} +when hasThreadSupport: + {.pragma: rtlThreadVar, threadvar.} +else: + {.pragma: rtlThreadVar.} + +const + QuitSuccess* = 0 + ## is the value that should be passed to `quit <#quit>`_ to indicate + ## success. + + QuitFailure* = 1 + ## is the value that should be passed to `quit <#quit>`_ to indicate + ## failure. + +var programResult* {.exportc: "nim_program_result".}: int + ## modify this variable to specify the exit code of the program + ## under normal circumstances. When the program is terminated + ## prematurely using ``quit``, this value is ignored. + +proc quit*(errorcode: int = QuitSuccess) {. + 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 + ## opposite order they were added with `addQuitProc <#addQuitProc>`_. + ## ``quit`` never returns and ignores any exception that may have been raised + ## by the quit procedures. It does *not* call the garbage collector to free + ## all the memory, unless a quit procedure calls `GC_fullCollect + ## <#GC_fullCollect>`_. + ## + ## The proc ``quit(QuitSuccess)`` is called implicitly when your nim + ## program finishes without incident. A raised unhandled exception is + ## equivalent to calling ``quit(QuitFailure)``. + ## + ## Note that this is a *runtime* call and using ``quit`` inside a macro won't + ## have any compile time effect. If you need to stop the compiler inside a + ## macro, use the `error <manual.html#error-pragma>`_ or `fatal + ## <manual.html#fatal-pragma>`_ pragmas. + +template sysAssert(cond: bool, msg: string) = + when defined(useSysAssert): + if not cond: + echo "[SYSASSERT] ", msg + quit 1 + +when not defined(JS) and not defined(nimrodVm) and hostOS != "standalone": + include "system/cgprocs" + +proc add *[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.} +proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} = + ## Generic proc for adding a data item `y` to a container `x`. + ## For containers that have an order, `add` means *append*. New generic + ## containers should also call their adding proc `add` for consistency. + ## Generic code becomes much easier to write if the Nim naming scheme is + ## respected. + let xl = x.len + setLen(x, xl + y.len) + for i in 0..high(y): x[xl+i] = y[i] + +proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".} + ## use this instead of `=` for a `shallow copy`:idx:. The shallow copy + ## only changes the semantics for sequences and strings (and types which + ## contain those). Be careful with the changed semantics though! There + ## is a reason why the default assignment does a deep copy of sequences + ## and strings. + +proc del*[T](x: var seq[T], i: Natural) {.noSideEffect.} = + ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`. + ## This is an O(1) operation. + let xl = x.len + shallowCopy(x[i], x[xl-1]) + setLen(x, xl-1) + +proc delete*[T](x: var seq[T], i: Natural) {.noSideEffect.} = + ## deletes the item at index `i` by moving ``x[i+1..]`` by one position. + ## This is an O(n) operation. + let xl = x.len + for j in i..xl-2: shallowCopy(x[j], x[j+1]) + setLen(x, xl-1) + +proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} = + ## inserts `item` into `x` at position `i`. + let xl = x.len + setLen(x, xl+1) + var j = xl-1 + while j >= i: + shallowCopy(x[j+1], x[j]) + dec(j) + x[i] = item + +proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.} + ## takes any Nim variable and returns its string representation. It + ## works even for complex data graphs with cycles. This is a great + ## debugging tool. + +type + ByteAddress* = int + ## is the signed integer type that should be used for converting + ## pointers to integer addresses for readability. + + BiggestInt* = int64 + ## is an alias for the biggest signed integer type the Nim compiler + ## supports. Currently this is ``int64``, but it is platform-dependant + ## in general. + + BiggestFloat* = float64 + ## is an alias for the biggest floating point type the Nim + ## compiler supports. Currently this is ``float64``, but it is + ## platform-dependant in general. + +{.deprecated: [TAddress: ByteAddress].} + +when defined(windows): + type + clong* {.importc: "long", nodecl.} = int32 + ## This is the same as the type ``long`` in *C*. + culong* {.importc: "unsigned long", nodecl.} = uint32 + ## This is the same as the type ``unsigned long`` in *C*. +else: + type + clong* {.importc: "long", nodecl.} = int + ## This is the same as the type ``long`` in *C*. + culong* {.importc: "unsigned long", nodecl.} = uint + ## This is the same as the type ``unsigned long`` in *C*. + +type # these work for most platforms: + cchar* {.importc: "char", nodecl.} = char + ## This is the same as the type ``char`` in *C*. + cschar* {.importc: "signed char", nodecl.} = int8 + ## This is the same as the type ``signed char`` in *C*. + cshort* {.importc: "short", nodecl.} = int16 + ## This is the same as the type ``short`` in *C*. + cint* {.importc: "int", nodecl.} = int32 + ## This is the same as the type ``int`` in *C*. + csize* {.importc: "size_t", nodecl.} = int + ## This is the same as the type ``size_t`` in *C*. + clonglong* {.importc: "long long", nodecl.} = int64 + ## This is the same as the type ``long long`` in *C*. + cfloat* {.importc: "float", nodecl.} = float32 + ## This is the same as the type ``float`` in *C*. + cdouble* {.importc: "double", nodecl.} = float64 + ## This is the same as the type ``double`` in *C*. + clongdouble* {.importc: "long double", nodecl.} = BiggestFloat + ## This is the same as the type ``long double`` in *C*. + ## This C type is not supported by Nim's code generator + + cuchar* {.importc: "unsigned char", nodecl.} = char + ## This is the same as the type ``unsigned char`` in *C*. + cushort* {.importc: "unsigned short", nodecl.} = uint16 + ## This is the same as the type ``unsigned short`` in *C*. + cuint* {.importc: "unsigned int", nodecl.} = uint32 + ## This is the same as the type ``unsigned int`` in *C*. + culonglong* {.importc: "unsigned long long", nodecl.} = uint64 + ## This is the same as the type ``unsigned long long`` in *C*. + + cstringArray* {.importc: "char**", nodecl.} = ptr array [0..ArrayDummySize, cstring] + ## This is binary compatible to the type ``char**`` in *C*. The array's + ## high value is large enough to disable bounds checking in practice. + ## Use `cstringArrayToSeq` to convert it into a ``seq[string]``. + + PFloat32* = ptr float32 ## an alias for ``ptr float32`` + PFloat64* = ptr float64 ## an alias for ``ptr float64`` + PInt64* = ptr int64 ## an alias for ``ptr int64`` + PInt32* = ptr int32 ## an alias for ``ptr int32`` + +proc toFloat*(i: int): float {. + magic: "ToFloat", noSideEffect, importc: "toFloat".} + ## converts an integer `i` into a ``float``. If the conversion + ## fails, `EInvalidValue` is raised. However, on most platforms the + ## conversion cannot fail. + +proc toBiggestFloat*(i: BiggestInt): BiggestFloat {. + magic: "ToBiggestFloat", noSideEffect, importc: "toBiggestFloat".} + ## converts an biggestint `i` into a ``biggestfloat``. If the conversion + ## fails, `EInvalidValue` is raised. However, on most platforms the + ## conversion cannot fail. + +proc toInt*(f: float): int {. + magic: "ToInt", noSideEffect, importc: "toInt".} + ## converts a floating point number `f` into an ``int``. Conversion + ## rounds `f` if it does not contain an integer value. If the conversion + ## fails (because `f` is infinite for example), `EInvalidValue` is raised. + +proc toBiggestInt*(f: BiggestFloat): BiggestInt {. + magic: "ToBiggestInt", noSideEffect, importc: "toBiggestInt".} + ## converts a biggestfloat `f` into a ``biggestint``. Conversion + ## rounds `f` if it does not contain an integer value. If the conversion + ## fails (because `f` is infinite for example), `EInvalidValue` is raised. + +proc addQuitProc*(QuitProc: proc() {.noconv.}) {. + importc: "atexit", header: "<stdlib.h>".} + ## Adds/registers a quit procedure. + ## + ## Each call to ``addQuitProc`` registers another quit procedure. Up to 30 + ## procedures can be registered. They are executed on a last-in, first-out + ## basis (that is, the last function registered is the first to be executed). + ## ``addQuitProc`` raises an EOutOfIndex exception if ``QuitProc`` cannot be + ## registered. + +# Support for addQuitProc() is done by Ansi C's facilities here. +# In case of an unhandled exeption the exit handlers should +# not be called explicitly! The user may decide to do this manually though. + +proc copy*(s: string, first = 0): string {. + magic: "CopyStr", importc: "copyStr", noSideEffect, deprecated.} +proc copy*(s: string, first, last: int): string {. + magic: "CopyStrLast", importc: "copyStrLast", noSideEffect, + deprecated.} + ## copies a slice of `s` into a new string and returns this new + ## string. The bounds `first` and `last` denote the indices of + ## the first and last characters that shall be copied. If ``last`` + ## is omitted, it is treated as ``high(s)``. + ## **Deprecated since version 0.8.12**: Use ``substr`` instead. + +proc substr*(s: string, first = 0): string {. + magic: "CopyStr", importc: "copyStr", noSideEffect.} +proc substr*(s: string, first, last: int): string {. + magic: "CopyStrLast", importc: "copyStrLast", noSideEffect.} + ## copies a slice of `s` into a new string and returns this new + ## string. The bounds `first` and `last` denote the indices of + ## the first and last characters that shall be copied. If ``last`` + ## is omitted, it is treated as ``high(s)``. If ``last >= s.len``, ``s.len`` + ## is used instead: This means ``substr`` can also be used to `cut`:idx: + ## or `limit`:idx: a string's length. + +when not defined(nimrodVM): + proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.} + ## overwrites the contents of the memory at ``p`` with the value 0. + ## Exactly ``size`` bytes will be overwritten. Like any procedure + ## dealing with raw memory this is *unsafe*. + + proc copyMem*(dest, source: pointer, size: Natural) {. + importc: "memcpy", header: "<string.h>", benign.} + ## copies the contents from the memory at ``source`` to the memory + ## at ``dest``. Exactly ``size`` bytes will be copied. The memory + ## regions may not overlap. Like any procedure dealing with raw + ## memory this is *unsafe*. + + proc moveMem*(dest, source: pointer, size: Natural) {. + importc: "memmove", header: "<string.h>", benign.} + ## copies the contents from the memory at ``source`` to the memory + ## at ``dest``. Exactly ``size`` bytes will be copied. The memory + ## regions may overlap, ``moveMem`` handles this case appropriately + ## and is thus somewhat more safe than ``copyMem``. Like any procedure + ## dealing with raw memory this is still *unsafe*, though. + + proc equalMem*(a, b: pointer, size: Natural): bool {. + importc: "equalMem", noDecl, noSideEffect.} + ## compares the memory blocks ``a`` and ``b``. ``size`` bytes will + ## be compared. If the blocks are equal, true is returned, false + ## otherwise. Like any procedure dealing with raw memory this is + ## *unsafe*. + + when hostOS != "standalone": + 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 + ## ``dealloc(block)``. The block is not initialized, so reading + ## from it before writing to it is undefined behaviour! + ## The allocated memory belongs to its allocating thread! + ## Use `allocShared` to allocate from a shared heap. + proc createU*(T: typedesc, size = 1.Positive): ptr T {.inline, benign.} = + ## allocates a new memory block with at least ``T.sizeof * size`` + ## bytes. The block has to be freed with ``resize(block, 0)`` or + ## ``free(block)``. The block is not initialized, so reading + ## from it before writing to it is undefined behaviour! + ## The allocated memory belongs to its allocating thread! + ## Use `createSharedU` to allocate from a shared heap. + cast[ptr T](alloc(T.sizeof * size)) + proc alloc0*(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 + ## ``dealloc(block)``. The block is initialized with all bytes + ## containing zero, so it is somewhat safer than ``alloc``. + ## The allocated memory belongs to its allocating thread! + ## Use `allocShared0` to allocate from a shared heap. + proc create*(T: typedesc, size = 1.Positive): ptr T {.inline, benign.} = + ## allocates a new memory block with at least ``T.sizeof * size`` + ## bytes. The block has to be freed with ``resize(block, 0)`` or + ## ``free(block)``. The block is initialized with all bytes + ## containing zero, so it is somewhat safer than ``createU``. + ## The allocated memory belongs to its allocating thread! + ## Use `createShared` to allocate from a shared heap. + cast[ptr T](alloc0(T.sizeof * size)) + proc realloc*(p: pointer, newSize: Natural): pointer {.noconv, rtl, tags: [], + benign.} + ## grows or shrinks a given memory block. If p is **nil** then a new + ## memory block is returned. In either way the block has at least + ## ``newSize`` bytes. If ``newSize == 0`` and p is not **nil** + ## ``realloc`` calls ``dealloc(p)``. In other cases the block has to + ## be freed with ``dealloc``. + ## The allocated memory belongs to its allocating thread! + ## Use `reallocShared` to reallocate from a shared heap. + proc resize*[T](p: ptr T, newSize: Natural): ptr T {.inline, benign.} = + ## grows or shrinks a given memory block. If p is **nil** then a new + ## memory block is returned. In either way the block has at least + ## ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is not + ## **nil** ``resize`` calls ``free(p)``. In other cases the block + ## has to be freed with ``free``. The allocated memory belongs to + ## its allocating thread! + ## Use `resizeShared` to reallocate from a shared heap. + cast[ptr T](realloc(p, T.sizeof * newSize)) + proc dealloc*(p: pointer) {.noconv, rtl, tags: [], benign.} + ## frees the memory allocated with ``alloc``, ``alloc0`` or + ## ``realloc``. This procedure is dangerous! If one forgets to + ## free the memory a leak occurs; if one tries to access freed + ## memory (or just freeing it twice!) a core dump may happen + ## 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 + ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. The block + ## is not initialized, so reading from it before writing to it is + ## undefined behaviour! + proc createSharedU*(T: typedesc, size = 1.Positive): ptr T {.inline, + benign.} = + ## allocates a new memory block on the shared heap with at + ## least ``T.sizeof * size`` bytes. The block has to be freed with + ## ``resizeShared(block, 0)`` or ``freeShared(block)``. The block + ## is not initialized, so reading from it before writing to it is + ## undefined behaviour! + cast[ptr T](allocShared(T.sizeof * size)) + proc allocShared0*(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 + ## ``reallocShared(block, 0)`` or ``deallocShared(block)``. + ## The block is initialized with all bytes + ## containing zero, so it is somewhat safer than ``allocShared``. + proc createShared*(T: typedesc, size = 1.Positive): ptr T {.inline.} = + ## allocates a new memory block on the shared heap with at + ## least ``T.sizeof * size`` bytes. The block has to be freed with + ## ``resizeShared(block, 0)`` or ``freeShared(block)``. + ## The block is initialized with all bytes + ## containing zero, so it is somewhat safer than ``createSharedU``. + cast[ptr T](allocShared0(T.sizeof * size)) + proc reallocShared*(p: pointer, newSize: Natural): pointer {.noconv, rtl, + benign.} + ## grows or shrinks a given memory block on the heap. If p is **nil** + ## then a new memory block is returned. In either way the block has at + ## least ``newSize`` bytes. If ``newSize == 0`` and p is not **nil** + ## ``reallocShared`` calls ``deallocShared(p)``. In other cases the + ## block has to be freed with ``deallocShared``. + proc resizeShared*[T](p: ptr T, newSize: Natural): ptr T {.inline.} = + ## grows or shrinks a given memory block on the heap. If p is **nil** + ## then a new memory block is returned. In either way the block has at + ## least ``T.sizeof * newSize`` bytes. If ``newSize == 0`` and p is + ## not **nil** ``resizeShared`` calls ``freeShared(p)``. In other + ## cases the block has to be freed with ``freeShared``. + cast[ptr T](reallocShared(p, T.sizeof * newSize)) + proc deallocShared*(p: pointer) {.noconv, rtl, benign.} + ## frees the memory allocated with ``allocShared``, ``allocShared0`` or + ## ``reallocShared``. This procedure is dangerous! If one forgets to + ## free the memory a leak occurs; if one tries to access freed + ## memory (or just freeing it twice!) a core dump may happen + ## or other memory may be corrupted. + proc freeShared*[T](p: ptr T) {.inline, benign.} = + ## frees the memory allocated with ``createShared``, ``createSharedU`` or + ## ``resizeShared``. This procedure is dangerous! If one forgets to + ## free the memory a leak occurs; if one tries to access freed + ## memory (or just freeing it twice!) a core dump may happen + ## or other memory may be corrupted. + deallocShared(p) + +proc swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} + ## swaps the values `a` and `b`. This is often more efficient than + ## ``tmp = a; a = b; b = tmp``. Particularly useful for sorting algorithms. + +template `>=%` *(x, y: expr): expr {.immediate.} = y <=% x + ## treats `x` and `y` as unsigned and compares them. + ## Returns true iff ``unsigned(x) >= unsigned(y)``. + +template `>%` *(x, y: expr): expr {.immediate.} = y <% x + ## treats `x` and `y` as unsigned and compares them. + ## Returns true iff ``unsigned(x) > unsigned(y)``. + +proc `$`*(x: int): string {.magic: "IntToStr", noSideEffect.} + ## The stringify operator for an integer argument. Returns `x` + ## converted to a decimal string. ``$`` is Nim's general way of + ## spelling `toString`:idx:. + +proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} + ## The stringify operator for an integer argument. Returns `x` + ## converted to a decimal string. + +when not defined(NimrodVM): + when not defined(JS) and hostOS != "standalone": + proc `$` *(x: uint64): string {.noSideEffect.} + ## The stringify operator for an unsigned integer argument. Returns `x` + ## converted to a decimal string. + +proc `$` *(x: float): string {.magic: "FloatToStr", noSideEffect.} + ## The stringify operator for a float argument. Returns `x` + ## converted to a decimal string. + +proc `$` *(x: bool): string {.magic: "BoolToStr", noSideEffect.} + ## The stringify operator for a boolean argument. Returns `x` + ## converted to the string "false" or "true". + +proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.} + ## The stringify operator for a character argument. Returns `x` + ## converted to a string. + +proc `$` *(x: cstring): string {.magic: "CStrToStr", noSideEffect.} + ## The stringify operator for a CString argument. Returns `x` + ## converted to a string. + +proc `$` *(x: string): string {.magic: "StrToStr", noSideEffect.} + ## The stringify operator for a string argument. Returns `x` + ## 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.} + ## 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 + ## used instead. (In other words: *Overwriting* is possible.) + +# undocumented: +proc getRefcount*[T](x: ref T): int {.importc: "getRefcount", noSideEffect.} +proc getRefcount*(x: string): int {.importc: "getRefcount", noSideEffect.} +proc getRefcount*[T](x: seq[T]): int {.importc: "getRefcount", noSideEffect.} + ## retrieves the reference count of an heap-allocated object. The + ## value is implementation-dependent. + + +const + Inf* {.magic: "Inf".} = 1.0 / 0.0 + ## contains the IEEE floating point value of positive infinity. + NegInf* {.magic: "NegInf".} = -Inf + ## contains the IEEE floating point value of negative infinity. + NaN* {.magic: "NaN".} = 0.0 / 0.0 + ## contains an IEEE floating point value of *Not A Number*. Note + ## that you cannot compare a floating point value to this value + ## and expect a reasonable result - use the `classify` procedure + ## in the module ``math`` for checking for NaN. + NimMajor*: int = 0 + ## is the major number of Nim's version. + + NimMinor*: int = 11 + ## is the minor number of Nim's version. + + NimPatch*: int = 2 + ## is the patch number of Nim's version. + + NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch + ## is the version of Nim as a string. + +{.deprecated: [TEndian: Endianness, NimrodVersion: NimVersion, + NimrodMajor: NimMajor, NimrodMinor: NimMinor, NimrodPatch: NimPatch].} + +# GC interface: + +when not defined(nimrodVM) and hostOS != "standalone": + proc getOccupiedMem*(): int {.rtl.} + ## returns the number of bytes that are owned by the process and hold data. + + proc getFreeMem*(): int {.rtl.} + ## returns the number of bytes that are owned by the process, but do not + ## hold any meaningful data. + + proc getTotalMem*(): int {.rtl.} + ## returns the number of bytes that are owned by the process. + + when hasThreadSupport: + proc getOccupiedSharedMem*(): int {.rtl.} + ## returns the number of bytes that are owned by the process + ## on the shared heap and hold data. This is only available when + ## threads are enabled. + + proc getFreeSharedMem*(): int {.rtl.} + ## returns the number of bytes that are owned by the + ## process on the shared heap, but do not hold any meaningful data. + ## This is only available when threads are enabled. + + proc getTotalSharedMem*(): int {.rtl.} + ## returns the number of bytes on the shared heap that are owned by the + ## process. This is only available when threads are enabled. + +when sizeof(int) <= 2: + type IntLikeForCount = int|int8|int16|char|bool|uint8|enum +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 + ## 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. + when T is IntLikeForCount: + var res = int(a) + while res >= int(b): + yield T(res) + dec(res, step) + else: + var res = a + while res >= b: + yield res + dec(res, step) + +template countupImpl(incr: stmt) {.immediate, dirty.} = + when T is IntLikeForCount: + var res = int(a) + while res <= int(b): + yield T(res) + incr + else: + var res: T = T(a) + while res <= b: + yield res + incr + +iterator countup*[S, T](a: S, b: T, step = 1): T {.inline.} = + ## Counts from ordinal value `a` up to `b` 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. + countupImpl: + inc(res, step) + +iterator `..`*[S, T](a: S, b: T): T {.inline.} = + ## An alias for `countup`. + countupImpl: + inc(res) + +iterator `||`*[S, T](a: S, b: T, annotation=""): T {. + inline, magic: "OmpParFor", sideEffect.} = + ## parallel loop iterator. Same as `..` but the loop may run in parallel. + ## `annotation` is an additional annotation for the code generator to use. + ## Note that the compiler maps that to + ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as + ## such isn't aware of the parallelism in your code! Be careful! Later + ## versions of ``||`` will get proper support by Nim's code generator + ## and GC. + discard + +{.push stackTrace:off.} +proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} = + if x <= y: x else: y +proc min*(x, y: int8): int8 {.magic: "MinI", noSideEffect.} = + if x <= y: x else: y +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: "MinI", noSideEffect.} = + ## The minimum value of two integers. + if x <= y: x else: y + +proc min*[T](x: varargs[T]): T = + ## The minimum value of `x`. ``T`` needs to have a ``<`` operator. + result = x[0] + for i in 1..high(x): + if x[i] < result: result = x[i] + +proc max*(x, y: int): int {.magic: "MaxI", noSideEffect.} = + if y <= x: x else: y +proc max*(x, y: int8): int8 {.magic: "MaxI", noSideEffect.} = + if y <= x: x else: y +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: "MaxI", noSideEffect.} = + ## The maximum value of two integers. + if y <= x: x else: y + +proc max*[T](x: varargs[T]): T = + ## The maximum value of `x`. ``T`` needs to have a ``<`` operator. + result = x[0] + for i in 1..high(x): + if result < x[i]: result = x[i] + +proc abs*(x: float): float {.magic: "AbsF64", noSideEffect.} = + if x < 0.0: -x else: x +proc min*(x, y: float): float {.magic: "MinF64", noSideEffect.} = + if x <= y: x else: y +proc max*(x, y: float): float {.magic: "MaxF64", noSideEffect.} = + if y <= x: x else: y +{.pop.} + +proc clamp*[T](x, a, b: T): T = + ## limits the value ``x`` within the interval [a, b] + ## + ## .. code-block:: Nim + ## assert((1.4).clamp(0.0, 1.0) == 1.0) + ## assert((0.5).clamp(0.0, 1.0) == 0.5) + if x < a: return a + if x > b: return b + return x + +iterator items*[T](a: openArray[T]): T {.inline.} = + ## iterates over each item of `a`. + var i = 0 + while i < len(a): + yield a[i] + inc(i) + +iterator mitems*[T](a: var openArray[T]): var T {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = 0 + while i < len(a): + yield a[i] + inc(i) + +iterator items*[IX, T](a: array[IX, T]): T {.inline.} = + ## iterates over each item of `a`. + var i = low(IX) + if i <= high(IX): + while true: + yield a[i] + if i >= high(IX): break + inc(i) + +iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = low(IX) + if i <= high(IX): + while true: + yield a[i] + if i >= high(IX): break + inc(i) + +iterator items*[T](a: set[T]): T {.inline.} = + ## iterates over each element of `a`. `items` iterates only over the + ## elements that are really in the set (and not over the ones the set is + ## able to hold). + var i = low(T).int + while i <= high(T).int: + if T(i) in a: yield T(i) + inc(i) + +iterator items*(a: cstring): char {.inline.} = + ## iterates over each item of `a`. + var i = 0 + while a[i] != '\0': + yield a[i] + inc(i) + +iterator mitems*(a: var cstring): var char {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = 0 + while a[i] != '\0': + yield a[i] + inc(i) + +iterator items*(E: typedesc[enum]): E = + ## iterates over the values of the 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 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator mpairs*[T](a: var openArray[T]): tuple[key: int, val: var T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator pairs*[IX, T](a: array[IX, T]): tuple[key: IX, val: T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = low(IX) + if i <= high(IX): + while true: + yield (i, a[i]) + if i >= high(IX): break + inc(i) + +iterator mpairs*[IX, T](a: var array[IX, T]): tuple[key: IX, val: var T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = low(IX) + if i <= high(IX): + while true: + yield (i, a[i]) + if i >= high(IX): break + inc(i) + +iterator pairs*[T](a: seq[T]): tuple[key: int, val: T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator mpairs*[T](a: var seq[T]): tuple[key: int, val: var T] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator pairs*(a: string): tuple[key: int, val: char] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator mpairs*(a: var string): tuple[key: int, val: var char] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = 0 + while i < len(a): + yield (i, a[i]) + inc(i) + +iterator pairs*(a: cstring): tuple[key: int, val: char] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + var i = 0 + while a[i] != '\0': + yield (i, a[i]) + inc(i) + +iterator mpairs*(a: var cstring): tuple[key: int, val: var char] {.inline.} = + ## iterates over each item of `a`. Yields ``(index, a[index])`` pairs. + ## ``a[index]`` can be modified. + var i = 0 + while a[i] != '\0': + yield (i, a[i]) + inc(i) + + +proc isNil*[T](x: seq[T]): bool {.noSideEffect, magic: "IsNil".} +proc isNil*[T](x: ref T): bool {.noSideEffect, magic: "IsNil".} +proc isNil*(x: string): bool {.noSideEffect, magic: "IsNil".} +proc isNil*[T](x: ptr T): bool {.noSideEffect, magic: "IsNil".} +proc isNil*(x: pointer): bool {.noSideEffect, magic: "IsNil".} +proc isNil*(x: cstring): bool {.noSideEffect, magic: "IsNil".} +proc isNil*[T: proc](x: T): bool {.noSideEffect, magic: "IsNil".} + ## Fast check whether `x` is nil. This is sometimes more efficient than + ## ``== nil``. + +proc `==` *[I, T](x, y: array[I, T]): bool = + for f in low(x)..high(x): + if x[f] != y[f]: + return + result = true + +proc `@`*[T](a: openArray[T]): seq[T] = + ## turns an openarray into a sequence. This is not as efficient as turning + ## a fixed length array into a sequence as it always copies every element + ## of `a`. + newSeq(result, a.len) + for i in 0..a.len-1: result[i] = a[i] + +proc `&` *[T](x, y: seq[T]): seq[T] {.noSideEffect.} = + ## Concatenates two sequences. + ## Requires copying of the sequences. + ## + ## .. code-block:: Nim + ## assert(@[1, 2, 3, 4] & @[5, 6] == @[1, 2, 3, 4, 5, 6]) + newSeq(result, x.len + y.len) + for i in 0..x.len-1: + result[i] = x[i] + for i in 0..y.len-1: + result[i+x.len] = y[i] + +proc `&` *[T](x: seq[T], y: T): seq[T] {.noSideEffect.} = + ## Appends element y to the end of the sequence. + ## Requires copying of the sequence + ## + ## .. code-block:: Nim + ## assert(@[1, 2, 3] & 4 == @[1, 2, 3, 4]) + newSeq(result, x.len + 1) + for i in 0..x.len-1: + result[i] = x[i] + result[x.len] = y + +proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} = + ## Prepends the element x to the beginning of the sequence. + ## Requires copying of the sequence + ## + ## .. code-block:: Nim + ## assert(1 & @[2, 3, 4] == @[1, 2, 3, 4]) + newSeq(result, y.len + 1) + result[0] = x + for i in 0..y.len-1: + result[i+1] = y[i] + +when not defined(NimrodVM): + when not defined(JS): + proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} = + result = cast[pointer](x) + else: + proc seqToPtr[T](x: seq[T]): pointer {.asmNoStackFrame, nosideeffect.} = + asm """return `x`""" + + proc `==` *[T](x, y: seq[T]): bool {.noSideEffect.} = + ## Generic equals operator for sequences: relies on a equals operator for + ## the element type `T`. + if seqToPtr(x) == seqToPtr(y): + result = true + elif seqToPtr(x) == nil or seqToPtr(y) == nil: + result = false + elif x.len == y.len: + for i in 0..x.len-1: + if x[i] != y[i]: return false + result = true + +proc find*[T, S](a: T, item: S): int {.inline.}= + ## Returns the first index of `item` in `a` or -1 if not found. This requires + ## appropriate `items` and `==` operations to work. + for i in items(a): + if i == item: return + inc(result) + result = -1 + +proc contains*[T](a: openArray[T], item: T): bool {.inline.}= + ## Returns true if `item` is in `a` or false if not found. This is a shortcut + ## for ``find(a, item) >= 0``. + return find(a, item) >= 0 + +proc pop*[T](s: var seq[T]): T {.inline, noSideEffect.} = + ## returns the last item of `s` and decreases ``s.len`` by one. This treats + ## `s` as a stack and implements the common *pop* operation. + var L = s.len-1 + result = s[L] + setLen(s, L) + +proc each*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] {. + deprecated.} = + ## The well-known ``map`` operation from functional programming. Applies + ## `op` to every item in `data` and returns the result as a sequence. + ## + ## **Deprecated since version 0.9:** Use the ``map`` proc instead. + newSeq(result, data.len) + for i in 0..data.len-1: result[i] = op(data[i]) + +proc each*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) {. + deprecated.} = + ## The well-known ``map`` operation from functional programming. Applies + ## `op` to every item in `data` modifying it directly. + ## + ## **Deprecated since version 0.9:** Use the ``map`` proc instead. + for i in 0..data.len-1: op(data[i]) + +proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}): seq[S] = + ## Returns a new sequence with the results of `op` applied to every item in + ## `data`. + ## + ## Since the input is not modified you can use this version of ``map`` to + ## transform the type of the elements in the input sequence. Example: + ## + ## .. code-block:: nim + ## let + ## a = @[1, 2, 3, 4] + ## b = map(a, proc(x: int): string = $x) + ## assert b == @["1", "2", "3", "4"] + newSeq(result, data.len) + for i in 0..data.len-1: result[i] = op(data[i]) + +proc map*[T](data: var openArray[T], op: proc (x: var T) {.closure.}) = + ## Applies `op` to every item in `data` modifying it directly. + ## + ## Note that this version of ``map`` requires your input and output types to + ## be the same, since they are modified in-place. Example: + ## + ## .. code-block:: nim + ## var a = @["1", "2", "3", "4"] + ## echo repr(a) + ## # --> ["1", "2", "3", "4"] + ## map(a, proc(x: var string) = x &= "42") + ## echo repr(a) + ## # --> ["142", "242", "342", "442"] + for i in 0..data.len-1: op(data[i]) + +iterator fields*[T: tuple|object](x: T): RootObj {. + magic: "Fields", noSideEffect.} + ## iterates over every field of `x`. Warning: This really transforms + ## the 'for' and unrolls the loop. The current implementation also has a bug + ## that affects symbol binding in the loop body. +iterator fields*[S:tuple|object, T:tuple|object](x: S, y: T): tuple[a,b: expr] {. + magic: "Fields", noSideEffect.} + ## iterates over every field of `x` and `y`. + ## Warning: This is really transforms the 'for' and unrolls the loop. + ## The current implementation also has a bug that affects symbol binding + ## in the loop body. +iterator fieldPairs*[T: tuple|object](x: T): RootObj {. + magic: "FieldPairs", noSideEffect.} + ## Iterates over every field of `x` returning their name and value. + ## + ## When you iterate over objects with different field types you have to use + ## the compile time ``when`` instead of a runtime ``if`` to select the code + ## you want to run for each type. To perform the comparison use the `is + ## operator <manual.html#is-operator>`_. Example: + ## + ## .. code-block:: Nim + ## + ## type + ## Custom = object + ## foo: string + ## bar: bool + ## + ## proc `$`(x: Custom): string = + ## result = "Custom:" + ## for name, value in x.fieldPairs: + ## when value is bool: + ## result.add("\n\t" & name & " is " & $value) + ## else: + ## if value.isNil: + ## result.add("\n\t" & name & " (nil)") + ## else: + ## result.add("\n\t" & name & " '" & value & "'") + ## + ## Another way to do the same without ``when`` is to leave the task of + ## picking the appropriate code to a secondary proc which you overload for + ## each field type and pass the `value` to. + ## + ## Warning: This really transforms the 'for' and unrolls the loop. The + ## current implementation also has a bug that affects symbol binding in the + ## loop body. +iterator fieldPairs*[S: tuple|object, T: tuple|object](x: S, y: T): tuple[ + a, b: expr] {. + magic: "FieldPairs", noSideEffect.} + ## iterates over every field of `x` and `y`. + ## Warning: This really transforms the 'for' and unrolls the loop. + ## The current implementation also has a bug that affects symbol binding + ## in the loop body. + +proc `==`*[T: tuple|object](x, y: T): bool = + ## generic ``==`` operator for tuples that is lifted from the components + ## of `x` and `y`. + for a, b in fields(x, y): + if a != b: return false + return true + +proc `<=`*[T: tuple](x, y: T): bool = + ## generic ``<=`` operator for tuples that is lifted from the components + ## of `x` and `y`. This implementation uses `cmp`. + for a, b in fields(x, y): + var c = cmp(a, b) + if c < 0: return true + if c > 0: return false + return true + +proc `<`*[T: tuple](x, y: T): bool = + ## generic ``<`` operator for tuples that is lifted from the components + ## of `x` and `y`. This implementation uses `cmp`. + for a, b in fields(x, y): + var c = cmp(a, b) + if c < 0: return true + if c > 0: return false + return false + +proc `$`*[T: tuple|object](x: T): string = + ## generic ``$`` operator for tuples that is lifted from the components + ## of `x`. Example: + ## + ## .. code-block:: nim + ## $(23, 45) == "(23, 45)" + ## $() == "()" + result = "(" + var firstElement = true + for name, value in fieldPairs(x): + if not firstElement: result.add(", ") + result.add(name) + result.add(": ") + result.add($value) + firstElement = false + result.add(")") + +proc collectionToString[T](x: T, b, e: string): string = + result = b + var firstElement = true + for value in items(x): + if not firstElement: result.add(", ") + result.add($value) + firstElement = false + result.add(e) + +proc `$`*[T](x: set[T]): string = + ## generic ``$`` operator for sets that is lifted from the components + ## of `x`. Example: + ## + ## .. code-block:: nim + ## ${23, 45} == "{23, 45}" + collectionToString(x, "{", "}") + +proc `$`*[T](x: seq[T]): string = + ## generic ``$`` operator for seqs that is lifted from the components + ## of `x`. Example: + ## + ## .. code-block:: nim + ## $(@[23, 45]) == "@[23, 45]" + collectionToString(x, "@[", "]") + +when false: + # causes bootstrapping to fail as we use array of chars and cstring should + # match better ... + proc `$`*[T, IDX](x: array[IDX, T]): string = + collectionToString(x, "[", "]") + +# ----------------- GC interface --------------------------------------------- + +when not defined(nimrodVM) and hostOS != "standalone": + 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 + ## the mark and sweep phase with `GC_disableMarkAndSweep`. + + proc GC_enable*() {.rtl, inl, benign.} + ## enables the GC again. + + proc GC_fullCollect*() {.rtl, benign.} + ## forces a full garbage collection pass. + ## Ordinary code does not need to call this (and should not). + + type + GC_Strategy* = enum ## the strategy the GC should use for the application + gcThroughput, ## optimize for throughput + gcResponsiveness, ## optimize for responsiveness (default) + gcOptimizeTime, ## optimize for speed + gcOptimizeSpace ## optimize for memory footprint + + {.deprecated: [TGC_Strategy: GC_Strategy].} + + proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.} + ## tells the GC the desired strategy for the application. + ## **Deprecated** since version 0.8.14. This has always been a nop. + + proc GC_enableMarkAndSweep*() {.rtl, benign.} + proc GC_disableMarkAndSweep*() {.rtl, benign.} + ## the current implementation uses a reference counting garbage collector + ## with a seldomly run mark and sweep phase to free cycles. The mark and + ## sweep phase may take a long time and is not needed if the application + ## does not create cycles. Thus the mark and sweep phase can be deactivated + ## and activated separately from the rest of the GC. + + proc GC_getStatistics*(): string {.rtl, benign.} + ## returns an informative string about the GC's activity. This may be useful + ## for tweaking. + + proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.} + proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.} + proc GC_ref*(x: string) {.magic: "GCref", benign.} + ## marks the object `x` as referenced, so that it will not be freed until + ## it is unmarked via `GC_unref`. If called n-times for the same object `x`, + ## n calls to `GC_unref` are needed to unmark `x`. + + proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.} + proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.} + proc GC_unref*(x: string) {.magic: "GCunref", benign.} + ## see the documentation of `GC_ref`. + +template accumulateResult*(iter: expr) = + ## helps to convert an iterator to a proc. + result = @[] + for x in iter: add(result, x) + +# we have to compute this here before turning it off in except.nim anyway ... +const NimStackTrace = compileOption("stacktrace") + +{.push checks: off.} +# obviously we cannot generate checking operations here :-) +# because it would yield into an endless recursion +# however, stack-traces are available for most parts +# of the code + +var + globalRaiseHook*: proc (e: ref Exception): bool {.nimcall, benign.} + ## with this hook you can influence exception handling on a global level. + ## If not nil, every 'raise' statement ends up calling this hook. Ordinary + ## application code should never set this hook! You better know what you + ## do when setting this. If ``globalRaiseHook`` returns false, the + ## exception is caught and does not propagate further through the call + ## stack. + + localRaiseHook* {.threadvar.}: proc (e: ref Exception): bool {.nimcall, benign.} + ## with this hook you can influence exception handling on a + ## thread local level. + ## If not nil, every 'raise' statement ends up calling this hook. Ordinary + ## application code should never set this hook! You better know what you + ## do when setting this. If ``localRaiseHook`` returns false, the exception + ## is caught and does not propagate further through the call stack. + + outOfMemHook*: proc () {.nimcall, tags: [], benign.} + ## set this variable to provide a procedure that should be called + ## in case of an `out of memory`:idx: event. The standard handler + ## writes an error message and terminates the program. `outOfMemHook` can + ## be used to raise an exception in case of OOM like so: + ## + ## .. code-block:: nim + ## + ## var gOutOfMem: ref EOutOfMemory + ## new(gOutOfMem) # need to be allocated *before* OOM really happened! + ## gOutOfMem.msg = "out of memory" + ## + ## proc handleOOM() = + ## raise gOutOfMem + ## + ## system.outOfMemHook = handleOOM + ## + ## If the handler does not raise an exception, ordinary control flow + ## continues and the program is terminated. + +type + PFrame* = ptr TFrame ## represents a runtime frame of the call stack; + ## part of the debugger API. + TFrame* {.importc, nodecl, final.} = object ## the frame itself + prev*: PFrame ## previous frame; used for chaining the call stack + procname*: cstring ## name of the proc that is currently executing + line*: int ## line number of the proc that is currently executing + 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 + +when defined(JS): + proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = + asm """ + var len = `x`[0].length-1; + for (var i = 0; i < `y`.length; ++i) { + `x`[0][len] = `y`.charCodeAt(i); + ++len; + } + `x`[0][len] = 0 + """ + proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} + +elif hostOS != "standalone": + {.push stack_trace:off, profiler:off.} + proc add*(x: var string, y: cstring) = + var i = 0 + while y[i] != '\0': + add(x, y[i]) + 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#pragmas-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#pragmas-nosideeffect-pragma>`_. + +template newException*(exceptn: typedesc, message: string): expr = + ## creates an exception object of type ``exceptn`` and sets its ``msg`` field + ## to `message`. Returns the new exception object. + var + e: ref exceptn + new(e) + e.msg = message + e + +when hostOS == "standalone": + include panicoverride + +when not declared(sysFatal): + when hostOS == "standalone": + proc sysFatal(exceptn: typedesc, message: string) {.inline.} = + panic(message) + + 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 + + proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} = + var e: ref exceptn + new(e) + e.msg = message & arg + raise e + +proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo", benign.} + ## get type information for `x`. Ordinary code should not use this, but + ## the `typeinfo` module instead. + +{.push stackTrace: off.} +proc abs*(x: int): int {.magic: "AbsI", noSideEffect.} = + if x < 0: -x else: x +proc abs*(x: int8): int8 {.magic: "AbsI", noSideEffect.} = + if x < 0: -x else: x +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 +{.pop.} + +when not defined(JS): #and not defined(NimrodVM): + {.push stack_trace: off, profiler:off.} + + when not defined(NimrodVM) and hostOS != "standalone": + proc initGC() + when not defined(boehmgc) and not defined(useMalloc): + proc initAllocator() {.inline.} + + proc initStackBottom() {.inline, compilerproc.} = + # WARNING: This is very fragile! An array size of 8 does not work on my + # Linux 64bit system. -- That's because the stack direction is the other + # way round. + when declared(setStackBottom): + var locals {.volatile.}: pointer + locals = addr(locals) + setStackBottom(locals) + + proc initStackBottomWith(locals: pointer) {.inline, compilerproc.} = + # We need to keep initStackBottom around for now to avoid + # bootstrapping problems. + when declared(setStackBottom): + setStackBottom(locals) + + var + strDesc: TNimType + + strDesc.size = sizeof(string) + strDesc.kind = tyString + strDesc.flags = {ntfAcyclic} + + include "system/ansi_c" + + proc cmp(x, y: string): int = + result = int(c_strcmp(x, y)) + + const pccHack = if defined(pcc): "_" else: "" # Hack for PCC + when not defined(NimrodVM): + when defined(windows): + # work-around C's sucking abstraction: + # BUGFIX: stdin and stdout should be binary files! + proc setmode(handle, mode: int) {.importc: pccHack & "setmode", + header: "<io.h>".} + proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno", + header: "<fcntl.h>".} + var + O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int + + # we use binary mode in Windows: + setmode(fileno(c_stdin), O_BINARY) + setmode(fileno(c_stdout), O_BINARY) + + when defined(endb): + proc endbStep() + + # ----------------- IO Part ------------------------------------------------ + when hostOS != "standalone": + type + CFile {.importc: "FILE", header: "<stdio.h>", + final, incompletestruct.} = object + File* = ptr CFile ## The type representing a file handle. + + FileMode* = enum ## The file mode when opening a file. + fmRead, ## Open the file for read access only. + fmWrite, ## Open the file for write access only. + fmReadWrite, ## Open the file for read and write access. + ## If the file does not exist, it will be + ## created. + fmReadWriteExisting, ## Open the file for read and write access. + ## If the file does not exist, it will not be + ## created. + fmAppend ## Open the file for writing only; append data + ## at the end. + + FileHandle* = cint ## type that represents an OS file handle; this is + ## useful for low-level file access + + {.deprecated: [TFile: File, TFileHandle: FileHandle, TFileMode: FileMode].} + + # text file handling: + var + stdin* {.importc: "stdin", header: "<stdio.h>".}: File + ## The standard input stream. + stdout* {.importc: "stdout", header: "<stdio.h>".}: File + ## The standard output stream. + stderr* {.importc: "stderr", header: "<stdio.h>".}: File + ## The standard error stream. + + when defined(useStdoutAsStdmsg): + template stdmsg*: File = stdout + else: + template stdmsg*: File = stderr + ## Template which expands to either stdout or stderr depending on + ## `useStdoutAsStdmsg` compile-time switch. + + proc open*(f: var File, filename: string, + mode: FileMode = fmRead, bufSize: int = -1): bool {.tags: [], + benign.} + ## Opens a file named `filename` with given `mode`. + ## + ## Default mode is readonly. Returns true iff the file could be opened. + ## This throws no exception if the file could not be opened. + + proc open*(f: var File, filehandle: FileHandle, + mode: FileMode = fmRead): bool {.tags: [], benign.} + ## Creates a ``TFile`` from a `filehandle` with given `mode`. + ## + ## Default mode is readonly. Returns true iff the file could be opened. + + proc open*(filename: string, + mode: FileMode = fmRead, bufSize: int = -1): File = + ## Opens a file named `filename` with given `mode`. + ## + ## Default mode is readonly. Raises an ``IO`` exception if the file + ## could not be opened. + if not open(result, filename, mode, bufSize): + sysFatal(IOError, "cannot open: ", filename) + + proc reopen*(f: File, filename: string, mode: FileMode = fmRead): bool {. + tags: [], benign.} + ## reopens the file `f` with given `filename` and `mode`. This + ## is often used to redirect the `stdin`, `stdout` or `stderr` + ## file variables. + ## + ## Default mode is readonly. Returns true iff the file could be reopened. + + proc close*(f: File) {.importc: "fclose", header: "<stdio.h>", tags: [].} + ## Closes the file. + + proc endOfFile*(f: File): bool {.tags: [], benign.} + ## Returns true iff `f` is at the end. + + proc readChar*(f: File): char {. + importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].} + ## Reads a single character from the stream `f`. + proc flushFile*(f: File) {. + importc: "fflush", header: "<stdio.h>", tags: [WriteIOEffect].} + ## Flushes `f`'s buffer. + + proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.} + ## Reads all data from the stream `file`. + ## + ## Raises an IO exception in case of an error. It is an error if the + ## current file position is not at the beginning of the file. + + proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.} + ## Opens a file named `filename` for reading. + ## + ## Then calls `readAll <#readAll>`_ and closes the file afterwards. + ## Returns the string. Raises an IO exception in case of an error. If + ## you need to call this inside a compile time macro you can use + ## `staticRead <#staticRead>`_. + + proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} + ## Opens a file named `filename` for writing. Then writes the + ## `content` completely to the file and closes the file afterwards. + ## Raises an IO exception in case of an error. + + proc write*(f: File, r: float32) {.tags: [WriteIOEffect], benign.} + proc write*(f: File, i: int) {.tags: [WriteIOEffect], benign.} + proc write*(f: File, i: BiggestInt) {.tags: [WriteIOEffect], benign.} + proc write*(f: File, r: BiggestFloat) {.tags: [WriteIOEffect], benign.} + proc write*(f: File, s: string) {.tags: [WriteIOEffect], benign.} + proc write*(f: File, b: bool) {.tags: [WriteIOEffect], benign.} + proc write*(f: File, c: char) {.tags: [WriteIOEffect], benign.} + proc write*(f: File, c: cstring) {.tags: [WriteIOEffect], benign.} + proc write*(f: File, a: varargs[string, `$`]) {.tags: [WriteIOEffect], benign.} + ## Writes a value to the file `f`. May throw an IO exception. + + proc readLine*(f: File): TaintedString {.tags: [ReadIOEffect], benign.} + ## reads a line of text from the file `f`. May throw an IO exception. + ## A line of text may be delimited by ``CR``, ``LF`` or + ## ``CRLF``. The newline character(s) are not part of the returned string. + + proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], + benign.} + ## reads a line of text from the file `f` into `line`. `line` must not be + ## ``nil``! May throw an IO exception. + ## A line of text may be delimited by ``CR``, ``LF`` or + ## ``CRLF``. The newline character(s) are not part of the returned string. + ## 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, + tags: [WriteIOEffect], benign.} + ## writes the values `x` to `f` and then writes "\n". + ## May throw an IO exception. + + proc getFileSize*(f: File): int64 {.tags: [ReadIOEffect], benign.} + ## retrieves the file size (in bytes) of `f`. + + proc readBytes*(f: File, a: var openArray[int8|uint8], start, len: Natural): int {. + tags: [ReadIOEffect], benign.} + ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns + ## the actual number of bytes that have been read which may be less than + ## `len` (if not as many bytes are remaining), but not greater. + + proc readChars*(f: File, a: var openArray[char], start, len: Natural): int {. + tags: [ReadIOEffect], benign.} + ## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns + ## the actual number of bytes that have been read which may be less than + ## `len` (if not as many bytes are remaining), but not greater. + + proc readBuffer*(f: File, buffer: pointer, len: Natural): int {. + tags: [ReadIOEffect], benign.} + ## reads `len` bytes into the buffer pointed to by `buffer`. Returns + ## the actual number of bytes that have been read which may be less than + ## `len` (if not as many bytes are remaining), but not greater. + + proc writeBytes*(f: File, a: openArray[int8|uint8], start, len: Natural): int {. + tags: [WriteIOEffect], benign.} + ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns + ## the number of actual written bytes, which may be less than `len` in case + ## of an error. + + proc writeChars*(f: File, a: openArray[char], start, len: Natural): int {. + tags: [WriteIOEffect], benign.} + ## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns + ## the number of actual written bytes, which may be less than `len` in case + ## of an error. + + proc writeBuffer*(f: File, buffer: pointer, len: Natural): int {. + tags: [WriteIOEffect], benign.} + ## writes the bytes of buffer pointed to by the parameter `buffer` to the + ## file `f`. Returns the number of actual written bytes, which may be less + ## than `len` in case of an error. + + proc setFilePos*(f: File, pos: int64) {.benign.} + ## sets the position of the file pointer that is used for read/write + ## operations. The file's first byte has the index zero. + + proc getFilePos*(f: File): int64 {.benign.} + ## retrieves the current position of the file pointer that is used to + ## read from the file `f`. The file's first byte has the index zero. + + proc getFileHandle*(f: File): FileHandle {.importc: "fileno", + header: "<stdio.h>"} + ## returns the OS file handle of the file ``f``. This is only useful for + ## platform specific programming. + + when not defined(nimfix): + {.deprecated: [fileHandle: getFileHandle].} + + proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] = + ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be + ## of length ``len``. + newSeq(result, len) + for i in 0..len-1: result[i] = $a[i] + + proc cstringArrayToSeq*(a: cstringArray): seq[string] = + ## converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be + ## terminated by ``nil``. + var L = 0 + while a[L] != nil: inc(L) + result = cstringArrayToSeq(a, L) + + # ------------------------------------------------------------------------- + + when not defined(NimrodVM) and hostOS != "standalone": + 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) + 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) + + proc deallocCStringArray*(a: cstringArray) = + ## frees a NULL terminated cstringArray. + var i = 0 + while a[i] != nil: + dealloc(a[i]) + inc(i) + dealloc(a) + + when not defined(NimrodVM): + proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, + discardable, benign.} + ## atomic increment of `memLoc`. Returns the value after the operation. + + proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, + discardable, benign.} + ## atomic decrement of `memLoc`. Returns the value after the operation. + + include "system/atomics" + + type + PSafePoint = ptr TSafePoint + TSafePoint {.compilerproc, final.} = object + prev: PSafePoint # points to next safe point ON THE STACK + status: int + context: C_JmpBuf + hasRaiseAction: bool + raiseAction: proc (e: ref Exception): bool {.closure.} + + 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": + when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom() + initGC() + + when not defined(NimrodVM): + proc setControlCHook*(hook: proc () {.noconv.} not nil) + ## allows you to override the behaviour of your application when CTRL+C + ## is pressed. Only one such hook is supported. + + proc writeStackTrace*() {.tags: [WriteIOEffect].} + ## writes the current stack trace to ``stderr``. This is only works + ## for debug builds. + when hostOS != "standalone": + proc getStackTrace*(): string + ## gets the current stack trace. This only works for debug builds. + + proc getStackTrace*(e: ref Exception): string + ## gets the stack trace associated with `e`, which is the stack that + ## lead to the ``raise`` statement. This only works for debug builds. + + {.push stack_trace: off, profiler:off.} + when hostOS == "standalone": + include "system/embedded" + else: + include "system/excpt" + include "system/chcks" + + # we cannot compile this with stack tracing on + # as it would recurse endlessly! + include "system/arithm" + {.pop.} # stack trace + {.pop.} # stack trace + + when hostOS != "standalone" and not defined(NimrodVM): + include "system/dyncalls" + when not defined(NimrodVM): + include "system/sets" + + const + GenericSeqSize = (2 * sizeof(int)) + + proc getDiscriminant(aa: pointer, n: ptr TNimNode): int = + sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase") + var d: int + var a = cast[ByteAddress](aa) + case n.typ.size + of 1: d = ze(cast[ptr int8](a +% n.offset)[]) + of 2: d = ze(cast[ptr int16](a +% n.offset)[]) + of 4: d = int(cast[ptr int32](a +% n.offset)[]) + else: sysAssert(false, "getDiscriminant: invalid n.typ.size") + return d + + proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode = + var discr = getDiscriminant(aa, n) + if discr <% n.len: + result = n.sons[discr] + if result == nil: result = n.sons[n.len] + # n.sons[n.len] contains the ``else`` part (but may be nil) + else: + result = n.sons[n.len] + + when hostOS != "standalone": include "system/mmdisp" + {.push stack_trace: off, profiler:off.} + when hostOS != "standalone": include "system/sysstr" + {.pop.} + + when hostOS != "standalone": include "system/sysio" + when hasThreadSupport: + when hostOS != "standalone": include "system/channels" + else: + include "system/sysio" + + when hostOS != "standalone": + iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} = + ## Iterates over any line in the file named `filename`. + ## + ## If the file does not exist `EIO` is raised. The trailing newline + ## character(s) are removed from the iterated lines. Example: + ## + ## .. code-block:: nim + ## import strutils + ## + ## proc transformLetters(filename: string) = + ## var buffer = "" + ## for line in filename.lines: + ## buffer.add(line.replace("a", "0") & '\x0A') + ## writeFile(filename, buffer) + var f = open(filename, bufSize=8000) + var res = TaintedString(newStringOfCap(80)) + while f.readLine(res): yield res + close(f) + + iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} = + ## Iterate over any line in the file `f`. + ## + ## The trailing newline character(s) are removed from the iterated lines. + ## Example: + ## + ## .. code-block:: nim + ## proc countZeros(filename: File): tuple[lines, zeros: int] = + ## for line in filename.lines: + ## for letter in line: + ## if letter == '0': + ## result.zeros += 1 + ## result.lines += 1 + var res = TaintedString(newStringOfCap(80)) + while f.readLine(res): yield res + + when hostOS != "standalone" and not defined(NimrodVM): + include "system/assign" + include "system/repr" + + proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} = + ## retrieves the current exception; if there is none, nil is returned. + result = currException + + proc getCurrentExceptionMsg*(): string {.inline, benign.} = + ## retrieves the error message that was attached to the current + ## exception; if there is none, "" is returned. + var e = getCurrentException() + return if e == nil: "" else: e.msg + + proc onRaise*(action: proc(e: ref Exception): bool{.closure.}) = + ## can be used in a ``try`` statement to setup a Lisp-like + ## `condition system`:idx:\: This prevents the 'raise' statement to + ## raise an exception but instead calls ``action``. + ## If ``action`` returns false, the exception has been handled and + ## does not propagate further through the call stack. + if not isNil(excHandler): + excHandler.hasRaiseAction = true + excHandler.raiseAction = action + + proc setCurrentException*(exc: ref Exception) {.inline, benign.} = + ## sets the current exception. + ## + ## **Warning**: Only use this if you know what you are doing. + currException = exc + + {.push stack_trace: off, profiler:off.} + when defined(endb) and not defined(NimrodVM): + include "system/debugger" + + when defined(profiler) or defined(memProfiler): + include "system/profiler" + {.pop.} # stacktrace + + when not defined(NimrodVM): + proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.} + ## Hints the optimizer that `val` is likely going to be true. + ## + ## You can use this proc to decorate a branch condition. On certain + ## platforms this can help the processor predict better which branch is + ## going to be run. Example: + ## + ## .. code-block:: nim + ## for value in inputValues: + ## if likely(value <= 100): + ## process(value) + ## else: + ## echo "Value too big!" + + proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.} + ## Hints the optimizer that `val` is likely going to be false. + ## + ## You can use this proc to decorate a branch condition. On certain + ## platforms this can help the processor predict better which branch is + ## going to be run. Example: + ## + ## .. code-block:: nim + ## for value in inputValues: + ## if unlikely(value > 100): + ## echo "Value too big!" + ## else: + ## process(value) + + proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = + ## retrieves the raw proc pointer of the closure `x`. This is + ## useful for interfacing closures with C. + {.emit: """ + `result` = `x`.ClPrc; + """.} + + proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} = + ## retrieves the raw environment pointer of the closure `x`. This is + ## useful for interfacing closures with C. + {.emit: """ + `result` = `x`.ClEnv; + """.} + + proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} = + ## can be used to determine if a first class iterator has finished. + {.emit: """ + `result` = *((NI*) `x`.ClEnv) < 0; + """.} + +elif defined(JS): + # Stubs: + proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard + + proc GC_disable() = discard + proc GC_enable() = discard + proc GC_fullCollect() = discard + proc GC_setStrategy(strategy: GC_Strategy) = discard + proc GC_enableMarkAndSweep() = discard + proc GC_disableMarkAndSweep() = discard + proc GC_getStatistics(): string = return "" + + proc getOccupiedMem(): int = return -1 + proc getFreeMem(): int = return -1 + proc getTotalMem(): int = return -1 + + proc dealloc(p: pointer) = discard + proc alloc(size: Natural): pointer = discard + proc alloc0(size: Natural): pointer = discard + proc realloc(p: pointer, newsize: Natural): pointer = discard + + proc allocShared(size: Natural): pointer = discard + proc allocShared0(size: Natural): pointer = discard + proc deallocShared(p: pointer) = discard + proc reallocShared(p: pointer, newsize: Natural): pointer = discard + + when defined(JS): + include "system/jssys" + include "system/reprjs" + elif defined(NimrodVM): + proc cmp(x, y: string): int = + if x == y: return 0 + if x < y: return -1 + return 1 + + when defined(nimffi): + include "system/sysio" + + +proc quit*(errormsg: string, errorcode = QuitFailure) {.noReturn.} = + ## a shorthand for ``echo(errormsg); quit(errorcode)``. + echo(errormsg) + quit(errorcode) + +{.pop.} # checks +{.pop.} # hints + +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 + var shift = b.len - L + var newLen = slen + shift + if shift > 0: + # enlarge: + setLen(s, newLen) + for i in countdown(newLen-1, a+shift+1): shallowCopy(s[i], s[i-shift]) + else: + for i in countup(a+b.len, s.len-1+shift): shallowCopy(s[i], s[i-shift]) + # cut down: + setLen(s, newLen) + # fill the hole: + for i in 0 .. <b.len: s[i+a] = b[i] + +when hostOS != "standalone": + proc `[]`*(s: string, x: Slice[int]): string {.inline.} = + ## slice operation for strings. + result = s.substr(x.a, x.b) + + proc `[]=`*(s: var string, x: Slice[int], b: string) = + ## slice assignment for strings. If + ## ``b.len`` is not exactly the number of elements that are referred to + ## by `x`, a `splice`:idx: is performed: + ## + ## .. code-block:: nim + ## var s = "abcdef" + ## s[1 .. ^2] = "xyz" + ## assert s == "axyzf" + var a = x.a + var L = x.b - a + 1 + if L == b.len: + for i in 0 .. <L: s[i+a] = b[i] + else: + spliceImpl(s, a, L, b) + +proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[int]): seq[T] = + ## slice operation for arrays. + when low(a) < 0: + {.error: "Slicing for arrays with negative indices is unsupported.".} + var L = x.b - x.a + 1 + newSeq(result, L) + for i in 0.. <L: result[i] = a[i + x.a] + +proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[int], b: openArray[T]) = + ## slice assignment for arrays. + when low(a) < 0: + {.error: "Slicing for arrays with negative indices is unsupported.".} + var L = x.b - x.a + 1 + if L == b.len: + for i in 0 .. <L: a[i+x.a] = b[i] + else: + sysFatal(RangeError, "different lengths for slice assignment") + +proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] = + ## slice operation for arrays. + var L = ord(x.b) - ord(x.a) + 1 + newSeq(result, L) + for i in 0.. <L: + result[i] = a[Idx(ord(x.a) + i)] + +proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) = + ## slice assignment for arrays. + var L = ord(x.b) - ord(x.a) + 1 + if L == b.len: + for i in 0 .. <L: + a[Idx(ord(x.a) + i)] = b[i] + else: + sysFatal(RangeError, "different lengths for slice assignment") + +proc `[]`*[T](s: seq[T], x: Slice[int]): seq[T] = + ## slice operation for sequences. + var a = x.a + var L = x.b - a + 1 + newSeq(result, L) + for i in 0.. <L: result[i] = s[i + a] + +proc `[]=`*[T](s: var seq[T], x: Slice[int], b: openArray[T]) = + ## slice assignment for sequences. If + ## ``b.len`` is not exactly the number of elements that are referred to + ## by `x`, a `splice`:idx: is performed. + var a = x.a + var L = x.b - a + 1 + if L == b.len: + for i in 0 .. <L: s[i+a] = b[i] + else: + spliceImpl(s, a, L, b) + +proc slurp*(filename: string): string {.magic: "Slurp".} + ## This is an alias for `staticRead <#staticRead>`_. + +proc staticRead*(filename: string): string {.magic: "Slurp".} + ## Compile-time `readFile <#readFile>`_ proc for easy `resource`:idx: + ## embedding: + ## + ## .. code-block:: nim + ## const myResource = staticRead"mydatafile.bin" + ## + ## `slurp <#slurp>`_ is an alias for ``staticRead``. + +proc gorge*(command: string, input = ""): string {. + magic: "StaticExec".} = discard + ## This is an alias for `staticExec <#staticExec>`_. + +proc staticExec*(command: string, input = ""): 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 + ## to the executed program. + ## + ## .. code-block:: nim + ## const buildInfo = "Revision " & staticExec("git rev-parse HEAD") & + ## "\nCompiled on " & staticExec("uname -v") + ## + ## `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>`_. + +proc `+=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.magic: "Inc", noSideEffect.} + ## Increments an ordinal + +proc `-=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.magic: "Dec", noSideEffect.} + ## Decrements an ordinal + +proc `*=`*[T: SomeOrdinal|uint|uint64](x: var T, y: T) {.inline, noSideEffect.} = + ## Binary `*=` operator for ordinals + x = x * y + +proc `+=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} = + ## Increments in placee a floating point number + x = x + y + +proc `-=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} = + ## Decrements in place a floating point number + x = x - y + +proc `*=`*[T: float|float32|float64] (x: var T, y: T) {.inline, noSideEffect.} = + ## Multiplies in place a floating point number + x = x * y + +proc `/=`*(x: var float64, y: float64) {.inline, noSideEffect.} = + ## Divides in place a floating point number + x = x / y + +proc `/=`*[T: float|float32](x: var T, y: T) {.inline, noSideEffect.} = + ## Divides in place a floating point number + x = x / y + +proc `&=`* (x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.} + +proc astToStr*[T](x: T): string {.magic: "AstToStr", noSideEffect.} + ## converts the AST of `x` into a string representation. This is very useful + ## for debugging. + +proc instantiationInfo*(index = -1, fullPaths = false): tuple[ + filename: string, line: int] {. magic: "InstantiationInfo", noSideEffect.} + ## provides access to the compiler's instantiation stack line information. + ## + ## This proc is mostly useful for meta programming (eg. ``assert`` template) + ## to retrieve information about the current filename and line number. + ## Example: + ## + ## .. code-block:: nim + ## import strutils + ## + ## template testException(exception, code: expr): stmt = + ## try: + ## let pos = instantiationInfo() + ## discard(code) + ## echo "Test failure at $1:$2 with '$3'" % [pos.filename, + ## $pos.line, astToStr(code)] + ## assert false, "A test expecting failure succeeded?" + ## except exception: + ## discard + ## + ## proc tester(pos: int): int = + ## let + ## a = @[1, 2, 3] + ## result = a[pos] + ## + ## when isMainModule: + ## testException(IndexError, tester(30)) + ## testException(IndexError, tester(1)) + ## # --> Test failure at example.nim:20 with 'tester(1)' + +template currentSourcePath*: string = instantiationInfo(-1, true).filename + ## returns the full file-system path of the current source + +proc raiseAssert*(msg: string) {.noinline.} = + sysFatal(AssertionError, msg) + +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, + tags: [].} + THide(raiseAssert)(msg) + +template assert*(cond: bool, msg = "") = + ## Raises ``AssertionError`` with `msg` if `cond` is false. Note + ## that ``AssertionError`` is hidden from the effect system, so it doesn't + ## produce ``{.raises: [AssertionError].}``. This exception is only supposed + ## to be caught by unit testing frameworks. + ## The compiler may not generate any code at all for ``assert`` if it is + ## advised to do so through the ``-d:release`` or ``--assertions:off`` + ## `command line switches <nimc.html#command-line-switches>`_. + bind instantiationInfo + mixin failedAssertImpl + when compileOption("assertions"): + {.line.}: + if not cond: failedAssertImpl(astToStr(cond) & ' ' & msg) + +template doAssert*(cond: bool, msg = "") = + ## same as `assert` but is always turned on and not affected by the + ## ``--assertions`` command line switch. + bind instantiationInfo + {.line: instantiationInfo().}: + if not cond: + raiseAssert(astToStr(cond) & ' ' & msg) + +iterator items*[T](a: seq[T]): T {.inline.} = + ## iterates over each item of `a`. + var i = 0 + let L = len(a) + while i < L: + yield a[i] + inc(i) + assert(len(a) == L, "seq modified while iterating over it") + +iterator mitems*[T](a: var seq[T]): var T {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = 0 + let L = len(a) + while i < L: + yield a[i] + inc(i) + assert(len(a) == L, "seq modified while iterating over it") + +iterator items*(a: string): char {.inline.} = + ## iterates over each item of `a`. + var i = 0 + let L = len(a) + while i < L: + yield a[i] + inc(i) + assert(len(a) == L, "string modified while iterating over it") + +iterator mitems*(a: var string): var char {.inline.} = + ## iterates over each item of `a` so that you can modify the yielded value. + var i = 0 + let L = len(a) + while i < L: + yield a[i] + inc(i) + assert(len(a) == L, "string modified while iterating over it") + +when not defined(nimhygiene): + {.pragma: inject.} + +template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} = + ## Sets an assertion failure handler that will intercept any assert + ## statements following `onFailedAssert` in the current module scope. + ## + ## .. code-block:: nim + ## # module-wide policy to change the failed assert + ## # exception type in order to include a lineinfo + ## onFailedAssert(msg): + ## var e = new(TMyError) + ## e.msg = msg + ## e.lineinfo = instantiationInfo(-2) + ## raise e + ## + template failedAssertImpl(msgIMPL: string): stmt {.dirty.} = + let msg = msgIMPL + code + +proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = + ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not + ## perform deep copies of `s`. This is only useful for optimization + ## purposes. + when not defined(JS) and not defined(NimrodVM): + var s = cast[PGenericSeq](s) + s.reserved = s.reserved or seqShallowFlag + +proc shallow*(s: var string) {.noSideEffect, inline.} = + ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not + ## perform deep copies of `s`. This is only useful for optimization + ## purposes. + when not defined(JS) and not defined(NimrodVM): + var s = cast[PGenericSeq](s) + s.reserved = s.reserved or seqShallowFlag + +type + NimNodeObj = object + + NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj + ## represents a Nim AST node. Macros operate on this type. +{.deprecated: [PNimrodNode: NimNode].} + +when false: + template eval*(blk: stmt): stmt = + ## executes a block of code at compile time just as if it was a macro + ## optionally, the block can return an AST tree that will replace the + ## eval expression + macro payload: stmt {.gensym.} = blk + payload() + +when hostOS != "standalone": + proc insert*(x: var string, item: string, i = 0.Natural) {.noSideEffect.} = + ## inserts `item` into `x` at position `i`. + var xl = x.len + setLen(x, xl+item.len) + var j = xl-1 + while j >= i: + shallowCopy(x[j+item.len], x[j]) + dec(j) + j = 0 + while j < item.len: + x[j+i] = item[j] + inc(j) + +proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} = + ## Special compile-time procedure that checks whether `x` can be compiled + ## without any semantic error. + ## This can be used to check whether a type supports some operation: + ## + ## .. code-block:: Nim + ## when not compiles(3 + 4): + ## echo "'+' for integers is available" + discard + +when declared(initDebugger): + initDebugger() + +when hostOS != "standalone": + # XXX: make these the default (or implement the NilObject optimization) + proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect.} = + if x == nil: x = @[y] + else: x.add(y) + + proc safeAdd*(x: var string, y: char) = + if x == nil: x = "" + x.add(y) + + proc safeAdd*(x: var string, y: string) = + if x == nil: x = y + else: x.add(y) + +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 + ## the official signature says, the return type is not ``RootObj`` but a + ## tuple of a structure that depends on the current scope. Example: + ## + ## .. code-block:: nim + ## proc testLocals() = + ## var + ## a = "something" + ## b = 4 + ## c = locals() + ## d = "super!" + ## + ## b = 1 + ## for name, value in fieldPairs(c): + ## echo "name ", name, " with value ", value + ## echo "B is ", b + ## # -> name a with value something + ## # -> name b with value 4 + ## # -> B is 1 + discard + +when hostOS != "standalone" 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``. + discard + + include "system/deepcopy" + +proc procCall*(x: expr) {.magic: "ProcCall".} = + ## special magic to prohibit dynamic binding for `method`:idx: calls. + ## This is similar to `super`:idx: in ordinary OO languages. + ## + ## .. code-block:: nim + ## # 'someMethod' will be resolved fully statically: + ## procCall someMethod(a, b) + discard + +proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} = + ## builtin `roof`:idx: operator that can be used for convenient array access. + ## ``a[^x]`` is rewritten to ``a[a.len-x]``. However currently the ``a`` + ## expression must not have side effects for this to compile. Note that since + ## this is a builtin, it automatically works for all kinds of + ## overloaded ``[]`` or ``[]=`` accessors. + discard + +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.} |