diff --git a/compiler/platform.nim b/compiler/platform.nim index d63fe66366..59091b6909 100644 --- a/compiler/platform.nim +++ b/compiler/platform.nim @@ -147,7 +147,7 @@ const scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}), (name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", - scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".", + scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {})] type diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt index fd420168ee..4ae5eae691 100644 --- a/doc/nimrodc.txt +++ b/doc/nimrodc.txt @@ -493,9 +493,14 @@ OS features. To make the compiler output code for a 16bit target use the ``--cpu:avr`` target. -So to generate code for an `AVR`:idx: processor use this command:: +For example, to generate code for an `AVR`:idx: processor use this command:: - nimrod c --cpu:avr --os:standalone --gc:none -d:useMalloc --genScript x.nim + nimrod c --cpu:avr --os:standalone --deadCodeElim:on --genScript x.nim + +For the ``standalone`` target you need to provide +a file ``panicoverride.nim``. +See ``tests/manyloc/standalone/panicoverride.nim`` for an example +implementation. Nimrod for realtime systems diff --git a/lib/nimbase.h b/lib/nimbase.h index af06e447de..19d161adf0 100644 --- a/lib/nimbase.h +++ b/lib/nimbase.h @@ -27,9 +27,7 @@ __clang__ # define _GNU_SOURCE 1 #endif -#if !defined(__TINYC__) -# include -#else +#if defined(__TINYC__) /*# define __GNUC__ 3 # define GCC_MAJOR 4 # define __GNUC_MINOR__ 4 @@ -58,10 +56,6 @@ __clang__ # define N_INLINE(rettype, name) rettype __inline name #endif -#if defined(__POCC__) || defined(_MSC_VER) -# define HAVE_LRINT 1 -#endif - #if defined(__POCC__) # define NIM_CONST /* PCC is really picky with const modifiers */ # undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is @@ -157,110 +151,8 @@ __clang__ /* ----------------------------------------------------------------------- */ -/* from float_cast.h: */ - -/* -** Copyright (C) 2001 Erik de Castro Lopo -** -** Permission to use, copy, modify, distribute, and sell this file for any -** purpose is hereby granted without fee, provided that the above copyright -** and this permission notice appear in all copies. No representations are -** made about the suitability of this software for any purpose. It is -** provided "as is" without express or implied warranty. -*/ - -/* Version 1.1 */ - - -/*============================================================================ -** On Intel Pentium processors (especially PIII and probably P4), converting -** from float to int is very slow. To meet the C specs, the code produced by -** most C compilers targeting Pentium needs to change the FPU rounding mode -** before the float to int conversion is performed. -** -** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It -** is this flushing of the pipeline which is so slow. -** -** Fortunately the ISO C99 specifications define the functions lrint, lrintf, -** llrint and llrintf which fix this problem as a side effect. -*/ - -/* -** The C99 prototypes for lrint and lrintf are as follows: -** -** long int lrintf (float x); -** long int lrint (double x); -*/ - -#if defined(__LCC__) || (defined(__GNUC__)) -/* Linux' GCC does not seem to have these. Why? */ -# define HAVE_LRINT -# define HAVE_LRINTF -#endif - -#if defined(HAVE_LRINT) && defined(HAVE_LRINTF) - -/* These defines enable functionality introduced with the 1999 ISO C -** standard. They must be defined before the inclusion of math.h to -** engage them. If optimisation is enabled, these functions will be -** inlined. With optimisation switched off, you have to link in the -** maths library using -lm. -*/ - -# define _ISOC9X_SOURCE 1 -# define _ISOC99_SOURCE 1 -# define __USE_ISOC9X 1 -# define __USE_ISOC99 1 - -#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \ - && !defined(__BORLANDC__) && !defined(__POCC__) && !defined(_M_X64) - -/* Win32 doesn't seem to have these functions. -** Therefore implement inline versions of these functions here. -*/ -static N_INLINE(long int, lrint)(double flt) { - long int intgr; - _asm { - fld flt - fistp intgr - }; - return intgr; -} - -static N_INLINE(long int, lrintf)(float flt) { - long int intgr; - _asm { - fld flt - fistp intgr - }; - return intgr; -} - -#else - -# ifndef lrint -# define lrint(dbl) ((long int)(dbl)) -# endif -# ifndef lrintf -# define lrintf(flt) ((long int)(flt)) -# endif - -#endif /* defined(HAVE_LRINT) && defined(HAVE_LRINTF) */ - - -#include -#include -#include #include #include -#include -#include - -/* -#ifndef INF -static unsigned long nimInf[2]={0xffffffff, 0x7fffffff}; -# define INF (*(double*) nimInf) -#endif */ /* C99 compiler? */ #if (defined(__STD_VERSION__) && (__STD_VERSION__ >= 199901)) diff --git a/lib/pure/math.nim b/lib/pure/math.nim index d65330c4ac..f04a1a8c11 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -165,7 +165,7 @@ when not defined(JS): ## float value) equals m * 2**n. frexp stores n in `exponent` and returns ## m. - proc round*(x: float): int {.importc: "lrint", nodecl.} + proc round*(x: float): int {.importc: "lrint", header: "".} ## converts a float to an int by rounding. proc arccos*(x: float): float {.importc: "acos", header: "".} @@ -191,12 +191,12 @@ when not defined(JS): # C procs: proc gettime(dummy: ptr cint): cint {.importc: "time", header: "".} - proc srand(seed: cint) {.importc: "srand", nodecl.} - proc rand(): cint {.importc: "rand", nodecl.} + proc srand(seed: cint) {.importc: "srand", header: "".} + proc rand(): cint {.importc: "rand", header: "".} when not defined(windows): - proc srand48(seed: clong) {.importc: "srand48", nodecl.} - proc drand48(): float {.importc: "drand48", nodecl.} + proc srand48(seed: clong) {.importc: "srand48", header: "".} + proc drand48(): float {.importc: "drand48", header: "".} proc random(max: float): float = result = drand48() * max @@ -209,13 +209,13 @@ when not defined(JS): proc random(max: int): int = result = int(rand()) mod max - proc trunc*(x: float): float {.importc: "trunc", nodecl.} - proc floor*(x: float): float {.importc: "floor", nodecl.} - proc ceil*(x: float): float {.importc: "ceil", nodecl.} + proc trunc*(x: float): float {.importc: "trunc", header: "".} + proc floor*(x: float): float {.importc: "floor", header: "".} + proc ceil*(x: float): float {.importc: "ceil", header: "".} proc fmod*(x, y: float): float {.importc: "fmod", header: "".} -else: +else: proc mathrandom(): float {.importc: "Math.random", nodecl.} proc floor*(x: float): float {.importc: "Math.floor", nodecl.} proc ceil*(x: float): float {.importc: "Math.ceil", nodecl.} diff --git a/lib/system.nim b/lib/system.nim index c372313324..dabe6d9ced 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -450,7 +450,7 @@ proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.} 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", noDecl, noSideEffect.} +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.) @@ -909,7 +909,7 @@ var programResult* {.exportc: "nim_program_result".}: int ## prematurelly using ``quit``, this value is ignored. proc quit*(errorcode: int = QuitSuccess) {. - magic: "Exit", importc: "exit", noDecl, noReturn.} + magic: "Exit", importc: "exit", header: "", noReturn.} ## Stops the program immediately with an exit code. ## ## Before stopping the program the "quit procedures" are called in the @@ -1064,7 +1064,8 @@ proc toBiggestInt*(f: biggestfloat): biggestint {. ## 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", nodecl.} +proc addQuitProc*(QuitProc: proc() {.noconv.}) {. + importc: "atexit", header: "".} ## 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 @@ -1104,13 +1105,15 @@ when not defined(nimrodVM): ## Exactly ``size`` bytes will be overwritten. Like any procedure ## dealing with raw memory this is *unsafe*. - proc copyMem*(dest, source: Pointer, size: int) {.importc: "memcpy", noDecl.} + proc copyMem*(dest, source: Pointer, size: int) {. + importc: "memcpy", header: "".} ## 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: int) {.importc: "memmove", noDecl.} + proc moveMem*(dest, source: Pointer, size: int) {. + importc: "memmove", header: "".} ## 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 @@ -1124,61 +1127,62 @@ when not defined(nimrodVM): ## otherwise. Like any procedure dealing with raw memory this is ## *unsafe*. - proc alloc*(size: int): pointer {.noconv, rtl, tags: [].} - ## 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 alloc0*(size: int): pointer {.noconv, rtl, tags: [].} - ## 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 realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl, tags: [].} - ## 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 dealloc*(p: Pointer) {.noconv, rtl, tags: [].} - ## 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. + when hostOs != "standalone": + proc alloc*(size: int): pointer {.noconv, rtl, tags: [].} + ## 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 alloc0*(size: int): pointer {.noconv, rtl, tags: [].} + ## 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 realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl, tags: [].} + ## 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 dealloc*(p: Pointer) {.noconv, rtl, tags: [].} + ## 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 allocShared*(size: int): pointer {.noconv, rtl.} - ## 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 allocShared0*(size: int): pointer {.noconv, rtl.} - ## 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 reallocShared*(p: Pointer, newsize: int): pointer {.noconv, rtl.} - ## 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 deallocShared*(p: Pointer) {.noconv, rtl.} - ## 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 allocShared*(size: int): pointer {.noconv, rtl.} + ## 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 allocShared0*(size: int): pointer {.noconv, rtl.} + ## 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 reallocShared*(p: Pointer, newsize: int): pointer {.noconv, rtl.} + ## 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 deallocShared*(p: Pointer) {.noconv, rtl.} + ## 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 swap*[T](a, b: var T) {.magic: "Swap", noSideEffect.} ## swaps the values `a` and `b`. This is often more efficient than @@ -1201,7 +1205,7 @@ proc `$` *(x: int64): string {.magic: "Int64ToStr", noSideEffect.} ## converted to a decimal string. when not defined(NimrodVM): - when not defined(JS): + when not defined(JS) and hostOS != "standalone": proc `$` *(x: uint64): string {.noSideEffect.} ## The stingify operator for an unsigned integer argument. Returns `x` ## converted to a decimal string. @@ -1254,7 +1258,7 @@ const # GC interface: -when not defined(nimrodVM): +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. @@ -1632,7 +1636,7 @@ when false: # ----------------- GC interface --------------------------------------------- -when not defined(nimrodVM): +when not defined(nimrodVM) and hostOS != "standalone": proc GC_disable*() {.rtl, inl.} ## 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 @@ -1668,17 +1672,17 @@ when not defined(nimrodVM): ## returns an informative string about the GC's activity. This may be useful ## for tweaking. -proc GC_ref*[T](x: ref T) {.magic: "GCref".} -proc GC_ref*[T](x: seq[T]) {.magic: "GCref".} -proc GC_ref*(x: string) {.magic: "GCref".} - ## 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".} -proc GC_unref*[T](x: seq[T]) {.magic: "GCunref".} -proc GC_unref*(x: string) {.magic: "GCunref".} - ## see the documentation of `GC_ref`. + proc GC_ref*[T](x: ref T) {.magic: "GCref".} + proc GC_ref*[T](x: seq[T]) {.magic: "GCref".} + proc GC_ref*(x: string) {.magic: "GCref".} + ## 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".} + proc GC_unref*[T](x: seq[T]) {.magic: "GCunref".} + proc GC_unref*(x: string) {.magic: "GCunref".} + ## see the documentation of `GC_ref`. template accumulateResult*(iter: expr) = ## helps to convert an iterator to a proc. @@ -1741,15 +1745,7 @@ type filename*: cstring ## filename of the proc that is currently executing len*: int ## length of the inspectable slots -when not defined(JS): - {.push stack_trace:off, profiler:off.} - proc add*(x: var string, y: cstring) {.noStackFrame.} = - var i = 0 - while y[i] != '\0': - add(x, y[i]) - inc(i) - {.pop.} -else: +when defined(JS): proc add*(x: var string, y: cstring) {.noStackFrame.} = asm """ var len = `x`[0].length-1; @@ -1759,9 +1755,17 @@ else: } `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) {.noStackFrame.} = + var i = 0 + while y[i] != '\0': + add(x, y[i]) + inc(i) + {.pop.} + proc echo*[T](x: varargs[T, `$`]) {.magic: "Echo", tags: [FWriteIO].} ## special built-in that takes a variable number of arguments. Each argument ## is converted to a string via ``$``, so it works for user-defined @@ -1786,6 +1790,29 @@ template newException*(exceptn: typeDesc, message: string): expr = e.msg = message e +when hostOS == "standalone": + include panicoverride + +when not defined(sysFatal): + template sysFatal(exceptn: typeDesc, message: string) = + when hostOS == "standalone": + panic(message) + else: + var e: ref exceptn + new(e) + e.msg = message + raise e + + template sysFatal(exceptn: typeDesc, message, arg: string) = + when hostOS == "standalone": + rawoutput(message) + panic(arg) + else: + var e: ref exceptn + new(e) + e.msg = message & arg + raise e + proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo".} ## get type information for `x`. Ordinary code should not use this, but ## the `typeinfo` module instead. @@ -1793,7 +1820,7 @@ proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo".} when not defined(JS): #and not defined(NimrodVM): {.push stack_trace: off, profiler:off.} - when not defined(NimrodVM): + when not defined(NimrodVM) and hostOS != "standalone": proc initGC() when not defined(boehmgc) and not defined(useMalloc): proc initAllocator() {.inline.} @@ -1839,200 +1866,203 @@ when not defined(JS): #and not defined(NimrodVM): proc endbStep() # ----------------- IO Part ------------------------------------------------ - type - CFile {.importc: "FILE", nodecl, final, incompletestruct.} = object - TFile* = ptr CFile ## The type representing a file handle. + when hostOS != "standalone": + type + CFile {.importc: "FILE", header: "", + final, incompletestruct.} = object + TFile* = ptr CFile ## The type representing a file handle. - TFileMode* = 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. + TFileMode* = 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. - TFileHandle* = cint ## type that represents an OS file handle; this is - ## useful for low-level file access + TFileHandle* = cint ## type that represents an OS file handle; this is + ## useful for low-level file access - # text file handling: - var - stdin* {.importc: "stdin", noDecl.}: TFile ## The standard input stream. - stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream. - stderr* {.importc: "stderr", noDecl.}: TFile - ## The standard error stream. + # text file handling: + var + stdin* {.importc: "stdin", noDecl.}: TFile ## The standard input stream. + stdout* {.importc: "stdout", noDecl.}: TFile ## The standard output stream. + stderr* {.importc: "stderr", noDecl.}: TFile + ## The standard error stream. + ## + ## Note: In my opinion, this should not be used -- the concept of a + ## separate error stream is a design flaw of UNIX. A separate *message + ## stream* is a good idea, but since it is named ``stderr`` there are few + ## programs out there that distinguish properly between ``stdout`` and + ## ``stderr``. So, that's what you get if you don't name your variables + ## appropriately. It also annoys people if redirection + ## via ``>output.txt`` does not work because the program writes + ## to ``stderr``. + + proc Open*(f: var TFile, filename: string, + mode: TFileMode = fmRead, bufSize: int = -1): Bool {.tags: [].} + ## Opens a file named `filename` with given `mode`. ## - ## Note: In my opinion, this should not be used -- the concept of a - ## separate error stream is a design flaw of UNIX. A separate *message - ## stream* is a good idea, but since it is named ``stderr`` there are few - ## programs out there that distinguish properly between ``stdout`` and - ## ``stderr``. So, that's what you get if you don't name your variables - ## appropriately. It also annoys people if redirection - ## via ``>output.txt`` does not work because the program writes - ## to ``stderr``. + ## Default mode is readonly. Returns true iff the file could be opened. + ## This throws no exception if the file could not be opened. - proc Open*(f: var TFile, filename: string, - mode: TFileMode = fmRead, bufSize: int = -1): Bool {.tags: [].} - ## Opens a file named `filename` with given `mode`. - ## - ## Default mode is readonly. Returns true iff the file could be opened. - ## This throws no exception if the file could not be opened. + proc Open*(f: var TFile, filehandle: TFileHandle, + mode: TFileMode = fmRead): Bool {.tags: [].} + ## Creates a ``TFile`` from a `filehandle` with given `mode`. + ## + ## Default mode is readonly. Returns true iff the file could be opened. + + proc Open*(filename: string, + mode: TFileMode = fmRead, bufSize: int = -1): TFile = + ## Opens a file named `filename` with given `mode`. + ## + ## Default mode is readonly. Raises an ``IO`` exception if the file + ## could not be opened. + if not open(result, filename, mode, bufSize): + sysFatal(EIO, "cannot open: ", filename) - proc Open*(f: var TFile, filehandle: TFileHandle, - mode: TFileMode = fmRead): Bool {.tags: [].} - ## Creates a ``TFile`` from a `filehandle` with given `mode`. - ## - ## Default mode is readonly. Returns true iff the file could be opened. + proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool {. + tags: [].} + ## 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: TFile) {.importc: "fclose", header: "", tags: [].} + ## Closes the file. + + proc EndOfFile*(f: TFile): Bool {.tags: [].} + ## Returns true iff `f` is at the end. + + proc readChar*(f: TFile): char {. + importc: "fgetc", header: "", tags: [FReadIO].} + ## Reads a single character from the stream `f`. + proc FlushFile*(f: TFile) {. + importc: "fflush", header: "", tags: [FWriteIO].} + ## Flushes `f`'s buffer. + + proc readAll*(file: TFile): TaintedString {.tags: [FReadIO].} + ## Reads all data from the stream `file`. Raises an IO exception + ## in case of an error - proc Open*(filename: string, - mode: TFileMode = fmRead, bufSize: int = -1): TFile = - ## 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): - raise newException(EIO, "cannot open: " & filename) + proc readFile*(filename: string): TaintedString {.tags: [FReadIO].} + ## Opens a file named `filename` for reading. Then calls `readAll` + ## and closes the file afterwards. Returns the string. + ## Raises an IO exception in case of an error. - proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool {. - tags: [].} - ## 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 writeFile*(filename, content: string) {.tags: [FWriteIO].} + ## 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 Close*(f: TFile) {.importc: "fclose", nodecl, tags: [].} - ## Closes the file. + proc write*(f: TFile, r: float) {.tags: [FWriteIO].} + proc write*(f: TFile, i: int) {.tags: [FWriteIO].} + proc write*(f: TFile, i: biggestInt) {.tags: [FWriteIO].} + proc write*(f: TFile, r: biggestFloat) {.tags: [FWriteIO].} + proc write*(f: TFile, s: string) {.tags: [FWriteIO].} + proc write*(f: TFile, b: Bool) {.tags: [FWriteIO].} + proc write*(f: TFile, c: char) {.tags: [FWriteIO].} + proc write*(f: TFile, c: cstring) {.tags: [FWriteIO].} + proc write*(f: TFile, a: varargs[string, `$`]) {.tags: [FWriteIO].} + ## Writes a value to the file `f`. May throw an IO exception. - proc EndOfFile*(f: TFile): Bool {.tags: [].} - ## Returns true iff `f` is at the end. + proc readLine*(f: TFile): TaintedString {.tags: [FReadIO].} + ## 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 readChar*(f: TFile): char {.importc: "fgetc", nodecl, tags: [FReadIO].} - ## Reads a single character from the stream `f`. - proc FlushFile*(f: TFile) {.importc: "fflush", noDecl, tags: [FWriteIO].} - ## Flushes `f`'s buffer. + proc readLine*(f: TFile, line: var TaintedString): bool {.tags: [FReadIO].} + ## 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 readAll*(file: TFile): TaintedString {.tags: [FReadIO].} - ## Reads all data from the stream `file`. Raises an IO exception - ## in case of an error - - proc readFile*(filename: string): TaintedString {.tags: [FReadIO].} - ## Opens a file named `filename` for reading. Then calls `readAll` - ## and closes the file afterwards. Returns the string. - ## Raises an IO exception in case of an error. + proc writeln*[Ty](f: TFile, x: varargs[Ty, `$`]) {.inline, tags: [FWriteIO].} + ## writes the values `x` to `f` and then writes "\n". + ## May throw an IO exception. - proc writeFile*(filename, content: string) {.tags: [FWriteIO].} - ## 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 getFileSize*(f: TFile): int64 {.tags: [FReadIO].} + ## retrieves the file size (in bytes) of `f`. - proc write*(f: TFile, r: float) {.tags: [FWriteIO].} - proc write*(f: TFile, i: int) {.tags: [FWriteIO].} - proc write*(f: TFile, i: biggestInt) {.tags: [FWriteIO].} - proc write*(f: TFile, r: biggestFloat) {.tags: [FWriteIO].} - proc write*(f: TFile, s: string) {.tags: [FWriteIO].} - proc write*(f: TFile, b: Bool) {.tags: [FWriteIO].} - proc write*(f: TFile, c: char) {.tags: [FWriteIO].} - proc write*(f: TFile, c: cstring) {.tags: [FWriteIO].} - proc write*(f: TFile, a: varargs[string, `$`]) {.tags: [FWriteIO].} - ## Writes a value to the file `f`. May throw an IO exception. + proc ReadBytes*(f: TFile, a: var openarray[int8], start, len: int): int {. + tags: [FReadIO].} + ## 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 readLine*(f: TFile): TaintedString {.tags: [FReadIO].} - ## reads a line of text from the file `f`. May throw an IO exception. - ## A line of text may be delimited by ``CR``, ``LF`` or - ## ``CRLF``. The newline character(s) are not part of the returned string. - - proc readLine*(f: TFile, line: var TaintedString): bool {.tags: [FReadIO].} - ## 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 ReadChars*(f: TFile, a: var openarray[char], start, len: int): int {. + tags: [FReadIO].} + ## 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 writeln*[Ty](f: TFile, x: varargs[Ty, `$`]) {.inline, tags: [FWriteIO].} - ## writes the values `x` to `f` and then writes "\n". - ## May throw an IO exception. + proc readBuffer*(f: TFile, buffer: pointer, len: int): int {.tags: [FReadIO].} + ## 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 getFileSize*(f: TFile): int64 {.tags: [FReadIO].} - ## retrieves the file size (in bytes) of `f`. + proc writeBytes*(f: TFile, a: openarray[int8], start, len: int): int {. + tags: [FWriteIO].} + ## 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 ReadBytes*(f: TFile, a: var openarray[int8], start, len: int): int {. - tags: [FReadIO].} - ## 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 writeChars*(f: tFile, a: openarray[char], start, len: int): int {. + tags: [FWriteIO].} + ## 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 ReadChars*(f: TFile, a: var openarray[char], start, len: int): int {. - tags: [FReadIO].} - ## 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 writeBuffer*(f: TFile, buffer: pointer, len: int): int {. + tags: [FWriteIO].} + ## 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 readBuffer*(f: TFile, buffer: pointer, len: int): int {.tags: [FReadIO].} - ## 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 setFilePos*(f: TFile, pos: int64) + ## sets the position of the file pointer that is used for read/write + ## operations. The file's first byte has the index zero. - proc writeBytes*(f: TFile, a: openarray[int8], start, len: int): int {. - tags: [FWriteIO].} - ## 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 getFilePos*(f: TFile): int64 + ## 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 writeChars*(f: tFile, a: openarray[char], start, len: int): int {. - tags: [FWriteIO].} - ## 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 fileHandle*(f: TFile): TFileHandle {.importc: "fileno", + header: ""} + ## returns the OS file handle of the file ``f``. This is only useful for + ## platform specific programming. - proc writeBuffer*(f: TFile, buffer: pointer, len: int): int {. - tags: [FWriteIO].} - ## 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 cstringArrayToSeq*(a: cstringArray, len: int): 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 setFilePos*(f: TFile, pos: int64) - ## sets the position of the file pointer that is used for read/write - ## operations. The file's first byte has the index zero. - - proc getFilePos*(f: TFile): int64 - ## retrieves the current position of the file pointer that is used to - ## read from the file `f`. The file's first byte has the index zero. - - proc fileHandle*(f: TFile): TFileHandle {.importc: "fileno", - header: ""} - ## returns the OS file handle of the file ``f``. This is only useful for - ## platform specific programming. - - proc cstringArrayToSeq*(a: cstringArray, len: int): 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) + 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): + 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: - # XXX get rid of this string copy here: - var x = a[i] - result[i] = cast[cstring](alloc0(x.len+1)) - copyMem(result[i], addr(x[0]), x.len) + 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. @@ -2042,6 +2072,7 @@ when not defined(JS): #and not defined(NimrodVM): inc(i) dealloc(a) + when not defined(NimrodVM): proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable.} ## atomic increment of `memLoc`. Returns the value after the operation. @@ -2064,7 +2095,7 @@ when not defined(JS): #and not defined(NimrodVM): when hasThreadSupport: include "system/syslocks" include "system/threads" - elif not defined(nogc) and not defined(NimrodVM): + elif not defined(nogc) and not defined(NimrodVM) and hostOS != "standalone": when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom() initGC() @@ -2089,6 +2120,7 @@ when not defined(JS): #and not defined(NimrodVM): include "system/embedded" else: include "system/excpt" + include "system/chcks" # we cannot compile this with stack tracing on # as it would recurse endlessly! @@ -2124,29 +2156,30 @@ when not defined(JS): #and not defined(NimrodVM): else: result = n.sons[n.len] - include "system/mmdisp" + when hostOS != "standalone": include "system/mmdisp" {.push stack_trace: off, profiler:off.} when hostOS != "standalone": include "system/sysstr" {.pop.} - include "system/sysio" + when hostOS != "standalone": include "system/sysio" when hasThreadSupport: - include "system/channels" + when hostOS != "standalone": include "system/channels" else: include "system/sysio" - iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} = - ## Iterate over any line in the file named `filename`. - ## If the file does not exist `EIO` is raised. - var f = open(filename) - var res = TaintedString(newStringOfCap(80)) - while f.readLine(res): yield res - close(f) + when hostOS != "standalone": + iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} = + ## Iterate over any line in the file named `filename`. + ## If the file does not exist `EIO` is raised. + var f = open(filename) + var res = TaintedString(newStringOfCap(80)) + while f.readLine(res): yield res + close(f) - iterator lines*(f: TFile): TaintedString {.tags: [FReadIO].} = - ## Iterate over any line in the file `f`. - var res = TaintedString(newStringOfCap(80)) - while f.readLine(res): yield TaintedString(res) + iterator lines*(f: TFile): TaintedString {.tags: [FReadIO].} = + ## Iterate over any line in the file `f`. + var res = TaintedString(newStringOfCap(80)) + while f.readLine(res): yield res when hostOS != "standalone" and not defined(NimrodVM): include "system/assign" @@ -2263,10 +2296,6 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} = template `-|`*(b, s: expr): expr = (if b >= 0: b else: s.len + b) -proc `[]`*(s: string, x: TSlice[int]): string {.inline.} = - ## slice operation for strings. Negative indexes are supported. - result = s.substr(x.a-|s, x.b-|s) - template spliceImpl(s, a, L, b: expr): stmt {.immediate.} = # make room for additional elements or cut: var slen = s.len @@ -2283,21 +2312,26 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} = # fill the hole: for i in 0 .. = i: - shallowCopy(x[j+item.len], x[j]) - dec(j) - j = 0 - while j < item.len: - x[j+i] = item[j] - inc(j) +when hostOS != "standalone": + proc insert*(x: var string, item: string, i = 0) {.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 @@ -2558,18 +2593,19 @@ proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} = when defined(initDebugger): initDebugger() -# 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) +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: 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 safeAdd*(x: var string, y: string) = + if x == nil: x = y + else: x.add(y) proc locals*(): TObject {.magic: "Locals", noSideEffect.} = ## generates a tuple constructor expression listing all the local variables diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim index 33e1ea9822..8c187ab74c 100644 --- a/lib/system/ansi_c.nim +++ b/lib/system/ansi_c.nim @@ -13,25 +13,30 @@ {.push hints:off} -proc c_strcmp(a, b: CString): cint {.nodecl, noSideEffect, importc: "strcmp".} -proc c_memcmp(a, b: CString, size: int): cint {. - nodecl, noSideEffect, importc: "memcmp".} -proc c_memcpy(a, b: CString, size: int) {.nodecl, importc: "memcpy".} -proc c_strlen(a: CString): int {.nodecl, noSideEffect, importc: "strlen".} -proc c_memset(p: pointer, value: cint, size: int) {.nodecl, importc: "memset".} +proc c_strcmp(a, b: CString): cint {.header: "", + noSideEffect, importc: "strcmp".} +proc c_memcmp(a, b: CString, size: int): cint {.header: "", + noSideEffect, importc: "memcmp".} +proc c_memcpy(a, b: CString, size: int) {.header: "", importc: "memcpy".} +proc c_strlen(a: CString): int {.header: "", + noSideEffect, importc: "strlen".} +proc c_memset(p: pointer, value: cint, size: int) {. + header: "", importc: "memset".} type - C_TextFile {.importc: "FILE", nodecl, final, incompleteStruct.} = object - C_BinaryFile {.importc: "FILE", nodecl, final, incompleteStruct.} = object + C_TextFile {.importc: "FILE", header: "", + final, incompleteStruct.} = object + C_BinaryFile {.importc: "FILE", header: "", + final, incompleteStruct.} = object C_TextFileStar = ptr CTextFile C_BinaryFileStar = ptr CBinaryFile - C_JmpBuf {.importc: "jmp_buf".} = array[0..31, int] + C_JmpBuf {.importc: "jmp_buf", header: "".} = array[0..31, int] var - c_stdin {.importc: "stdin", noDecl.}: C_TextFileStar - c_stdout {.importc: "stdout", noDecl.}: C_TextFileStar - c_stderr {.importc: "stderr", noDecl.}: C_TextFileStar + c_stdin {.importc: "stdin", header: "".}: C_TextFileStar + c_stdout {.importc: "stdout", header: "".}: C_TextFileStar + c_stderr {.importc: "stderr", header: "".}: C_TextFileStar # constants faked as variables: when not defined(SIGINT): @@ -51,59 +56,70 @@ else: SIGBUS {.importc: "SIGSEGV", nodecl.}: cint # only Mac OS X has this shit -proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.nodecl, importc: "longjmp".} -proc c_setjmp(jmpb: var C_JmpBuf): cint {.nodecl, importc: "setjmp".} +proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {. + header: "", importc: "longjmp".} +proc c_setjmp(jmpb: var C_JmpBuf): cint {. + header: "", importc: "setjmp".} proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {. importc: "signal", header: "".} proc c_raise(sig: cint) {.importc: "raise", header: "".} -proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs", noDecl.} +proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs", + header: "".} proc c_fgets(c: cstring, n: int, f: C_TextFileStar): cstring {. - importc: "fgets", noDecl.} -proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc", nodecl.} -proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc", nodecl.} -proc c_putc(c: Char, stream: C_TextFileStar) {.importc: "putc", nodecl.} + importc: "fgets", header: "".} +proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc", + header: "".} +proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc", + header: "".} +proc c_putc(c: Char, stream: C_TextFileStar) {.importc: "putc", + header: "".} proc c_fprintf(f: C_TextFileStar, frmt: CString) {. - importc: "fprintf", nodecl, varargs.} + importc: "fprintf", header: "", varargs.} proc c_printf(frmt: CString) {. - importc: "printf", nodecl, varargs.} + importc: "printf", header: "", varargs.} proc c_fopen(filename, mode: cstring): C_TextFileStar {. - importc: "fopen", nodecl.} -proc c_fclose(f: C_TextFileStar) {.importc: "fclose", nodecl.} + importc: "fopen", header: "".} +proc c_fclose(f: C_TextFileStar) {.importc: "fclose", header: "".} -proc c_sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs, - noSideEffect.} +proc c_sprintf(buf, frmt: CString) {.header: "", + importc: "sprintf", varargs, noSideEffect.} # we use it only in a way that cannot lead to security issues proc c_fread(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {. - importc: "fread", noDecl.} + importc: "fread", header: "".} proc c_fseek(f: C_BinaryFileStar, offset: clong, whence: int): int {. - importc: "fseek", noDecl.} + importc: "fseek", header: "".} proc c_fwrite(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {. - importc: "fwrite", noDecl.} + importc: "fwrite", header: "".} -proc c_exit(errorcode: cint) {.importc: "exit", nodecl.} -proc c_ferror(stream: C_TextFileStar): bool {.importc: "ferror", nodecl.} -proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", nodecl.} -proc c_abort() {.importc: "abort", nodecl.} -proc c_feof(stream: C_TextFileStar): bool {.importc: "feof", nodecl.} +proc c_exit(errorcode: cint) {.importc: "exit", header: "".} +proc c_ferror(stream: C_TextFileStar): bool {. + importc: "ferror", header: "".} +proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", header: "".} +proc c_abort() {.importc: "abort", header: "".} +proc c_feof(stream: C_TextFileStar): bool {. + importc: "feof", header: "".} -proc c_malloc(size: int): pointer {.importc: "malloc", nodecl.} -proc c_free(p: pointer) {.importc: "free", nodecl.} -proc c_realloc(p: pointer, newsize: int): pointer {.importc: "realloc", nodecl.} +proc c_malloc(size: int): pointer {.importc: "malloc", header: "".} +proc c_free(p: pointer) {.importc: "free", header: "".} +proc c_realloc(p: pointer, newsize: int): pointer {. + importc: "realloc", header: "".} when not defined(errno): var errno {.importc, header: "".}: cint ## error variable proc strerror(errnum: cint): cstring {.importc, header: "".} -proc c_remove(filename: CString): cint {.importc: "remove", noDecl.} -proc c_rename(oldname, newname: CString): cint {.importc: "rename", noDecl.} +proc c_remove(filename: CString): cint {. + importc: "remove", header: "".} +proc c_rename(oldname, newname: CString): cint {. + importc: "rename", header: "".} proc c_system(cmd: CString): cint {.importc: "system", header: "".} -proc c_getenv(env: CString): CString {.importc: "getenv", noDecl.} -proc c_putenv(env: CString): cint {.importc: "putenv", noDecl.} +proc c_getenv(env: CString): CString {.importc: "getenv", header: "".} +proc c_putenv(env: CString): cint {.importc: "putenv", header: "".} {.pop} diff --git a/lib/system/arithm.nim b/lib/system/arithm.nim index 3efbfa7bbd..d764a66722 100644 --- a/lib/system/arithm.nim +++ b/lib/system/arithm.nim @@ -12,10 +12,10 @@ proc raiseOverflow {.compilerproc, noinline, noreturn.} = # a single proc to reduce code size to a minimum - raise newException(EOverflow, "over- or underflow") + sysFatal(EOverflow, "over- or underflow") proc raiseDivByZero {.compilerproc, noinline, noreturn.} = - raise newException(EDivByZero, "divison by zero") + sysFatal(EDivByZero, "divison by zero") proc addInt64(a, b: int64): int64 {.compilerProc, inline.} = result = a +% b @@ -322,16 +322,16 @@ when not defined(mulInt): # written in other languages. proc raiseFloatInvalidOp {.noinline, noreturn.} = - raise newException(EFloatInvalidOp, "FPU operation caused a NaN result") + sysFatal(EFloatInvalidOp, "FPU operation caused a NaN result") proc nanCheck(x: float64) {.compilerProc, inline.} = if x != x: raiseFloatInvalidOp() proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} = if x > 0.0: - raise newException(EFloatOverflow, "FPU operation caused an overflow") + sysFatal(EFloatOverflow, "FPU operation caused an overflow") else: - raise newException(EFloatUnderflow, "FPU operations caused an underflow") + sysFatal(EFloatUnderflow, "FPU operations caused an underflow") proc infCheck(x: float64) {.compilerProc, inline.} = if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x) diff --git a/lib/system/assign.nim b/lib/system/assign.nim index 4b8d2033d1..19d4ebf574 100644 --- a/lib/system/assign.nim +++ b/lib/system/assign.nim @@ -223,6 +223,4 @@ proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int, var oldBranch = selectBranch(oldDiscVal, L, a) var newBranch = selectBranch(newDiscVal, L, a) if newBranch != oldBranch and oldDiscVal != 0: - raise newException(EInvalidField, - "assignment to discriminant changes object branch") - + sysFatal(EInvalidField, "assignment to discriminant changes object branch") diff --git a/lib/system/channels.nim b/lib/system/channels.nim index 13d751d80e..89f742ca51 100644 --- a/lib/system/channels.nim +++ b/lib/system/channels.nim @@ -187,7 +187,7 @@ template lockChannel(q: expr, action: stmt) {.immediate.} = template sendImpl(q: expr) {.immediate.} = if q.mask == ChannelDeadMask: - raise newException(EDeadThread, "cannot send message; thread died") + sysFatal(EDeadThread, "cannot send message; thread died") acquireSys(q.lock) var m: TMsg shallowCopy(m, msg) @@ -211,7 +211,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) = q.ready = false if typ != q.elemType: releaseSys(q.lock) - raise newException(EInvalidValue, "cannot receive message of wrong type") + sysFatal(EInvalidValue, "cannot receive message of wrong type") rawRecv(q, res, typ) releaseSys(q.lock) diff --git a/lib/system/chcks.nim b/lib/system/chcks.nim new file mode 100644 index 0000000000..e781294832 --- /dev/null +++ b/lib/system/chcks.nim @@ -0,0 +1,77 @@ +# +# +# Nimrod's Runtime Library +# (c) Copyright 2013 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# Implementation of some runtime checks. + +proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} = + when hostOs == "standalone": + sysFatal(EOutOfRange, "value out of range") + else: + sysFatal(EOutOfRange, "value out of range: ", $val) + +proc raiseIndexError() {.compilerproc, noreturn, noinline.} = + sysFatal(EInvalidIndex, "index out of bounds") + +proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} = + sysFatal(EInvalidField, f, " is not accessible") + +proc chckIndx(i, a, b: int): int = + if i >= a and i <= b: + return i + else: + raiseIndexError() + +proc chckRange(i, a, b: int): int = + if i >= a and i <= b: + return i + else: + raiseRangeError(i) + +proc chckRange64(i, a, b: int64): int64 {.compilerproc.} = + if i >= a and i <= b: + return i + else: + raiseRangeError(i) + +proc chckRangeF(x, a, b: float): float = + if x >= a and x <= b: + return x + else: + when hostOS == "standalone": + sysFatal(EOutOfRange, "value out of range") + else: + sysFatal(EOutOfRange, "value out of range: ", $x) + +proc chckNil(p: pointer) = + if p == nil: + sysFatal(EInvalidValue, "attempt to write to a nil address") + #c_raise(SIGSEGV) + +proc chckObj(obj, subclass: PNimType) {.compilerproc.} = + # checks if obj is of type subclass: + var x = obj + if x == subclass: return # optimized fast path + while x != subclass: + if x == nil: + sysFatal(EInvalidObjectConversion, "invalid object conversion") + break + x = x.base + +proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} = + if a != b: + sysFatal(EInvalidObjectAssignment, "invalid object assignment") + +proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = + # checks if obj is of type subclass: + var x = obj + if x == subclass: return true # optimized fast path + while x != subclass: + if x == nil: return false + x = x.base + return true diff --git a/lib/system/embedded.nim b/lib/system/embedded.nim index aaa3befaac..fad9722c27 100644 --- a/lib/system/embedded.nim +++ b/lib/system/embedded.nim @@ -10,8 +10,6 @@ # Bare-bones implementation of some things for embedded targets. -proc writeToStdErr(msg: CString) = write(stdout, msg) - proc chckIndx(i, a, b: int): int {.inline, compilerproc.} proc chckRange(i, a, b: int): int {.inline, compilerproc.} proc chckRangeF(x, a, b: float): float {.inline, compilerproc.} @@ -35,72 +33,11 @@ proc quitOrDebug() {.inline.} = quit(1) proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} = - writeToStdErr(ename) - + sysFatal(ENoExceptionToReraise, "exception handling is not available") + proc reraiseException() {.compilerRtl.} = - writeToStdErr("reraise not supported") + sysFatal(ENoExceptionToReraise, "no exception to reraise") proc WriteStackTrace() = nil -proc setControlCHook(hook: proc () {.noconv.}) = - # ugly cast, but should work on all architectures: - type TSignalHandler = proc (sig: cint) {.noconv.} - c_signal(SIGINT, cast[TSignalHandler](hook)) - -proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} = - writeToStdErr("value out of range") - -proc raiseIndexError() {.compilerproc, noreturn, noinline.} = - writeToStdErr("index out of bounds") - -proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} = - writeToStdErr("field is not accessible") - -proc chckIndx(i, a, b: int): int = - if i >= a and i <= b: - return i - else: - raiseIndexError() - -proc chckRange(i, a, b: int): int = - if i >= a and i <= b: - return i - else: - raiseRangeError(i) - -proc chckRange64(i, a, b: int64): int64 {.compilerproc.} = - if i >= a and i <= b: - return i - else: - raiseRangeError(i) - -proc chckRangeF(x, a, b: float): float = - if x >= a and x <= b: - return x - else: - raise newException(EOutOfRange, "value " & $x & " out of range") - -proc chckNil(p: pointer) = - if p == nil: c_raise(SIGSEGV) - -proc chckObj(obj, subclass: PNimType) {.compilerproc.} = - # checks if obj is of type subclass: - var x = obj - if x == subclass: return # optimized fast path - while x != subclass: - if x == nil: - raise newException(EInvalidObjectConversion, "invalid object conversion") - x = x.base - -proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} = - if a != b: - raise newException(EInvalidObjectAssignment, "invalid object assignment") - -proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = - # checks if obj is of type subclass: - var x = obj - if x == subclass: return true # optimized fast path - while x != subclass: - if x == nil: return false - x = x.base - return true +proc setControlCHook(hook: proc () {.noconv.}) = nil diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index bf0fe4b72a..03200c8e2b 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -249,7 +249,7 @@ proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} = proc reraiseException() {.compilerRtl.} = if currException == nil: - raise newException(ENoExceptionToReraise, "no exception to reraise") + sysFatal(ENoExceptionToReraise, "no exception to reraise") else: raiseExceptionAux(currException) @@ -324,63 +324,3 @@ proc setControlCHook(hook: proc () {.noconv.}) = # ugly cast, but should work on all architectures: type TSignalHandler = proc (sig: cint) {.noconv.} c_signal(SIGINT, cast[TSignalHandler](hook)) - -proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} = - raise newException(EOutOfRange, "value " & $val & " out of range") - -proc raiseIndexError() {.compilerproc, noreturn, noinline.} = - raise newException(EInvalidIndex, "index out of bounds") - -proc raiseFieldError(f: string) {.compilerproc, noreturn, noinline.} = - raise newException(EInvalidField, f & " is not accessible") - -proc chckIndx(i, a, b: int): int = - if i >= a and i <= b: - return i - else: - raiseIndexError() - -proc chckRange(i, a, b: int): int = - if i >= a and i <= b: - return i - else: - raiseRangeError(i) - -proc chckRange64(i, a, b: int64): int64 {.compilerproc.} = - if i >= a and i <= b: - return i - else: - raiseRangeError(i) - -proc chckRangeF(x, a, b: float): float = - if x >= a and x <= b: - return x - else: - raise newException(EOutOfRange, "value " & $x & " out of range") - -proc chckNil(p: pointer) = - if p == nil: - raise newException(EInvalidValue, "attempt to write to a nil address") - #c_raise(SIGSEGV) - -proc chckObj(obj, subclass: PNimType) {.compilerproc.} = - # checks if obj is of type subclass: - var x = obj - if x == subclass: return # optimized fast path - while x != subclass: - if x == nil: - raise newException(EInvalidObjectConversion, "invalid object conversion") - x = x.base - -proc chckObjAsgn(a, b: PNimType) {.compilerproc, inline.} = - if a != b: - raise newException(EInvalidObjectAssignment, "invalid object assignment") - -proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = - # checks if obj is of type subclass: - var x = obj - if x == subclass: return true # optimized fast path - while x != subclass: - if x == nil: return false - x = x.base - return true diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 31758eb453..e8d79ec55c 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -16,39 +16,44 @@ # of the standard library! -proc fputs(c: cstring, f: TFile) {.importc: "fputs", noDecl, tags: [FWriteIO].} -proc fgets(c: cstring, n: int, f: TFile): cstring {.importc: "fgets", noDecl, - tags: [FReadIO].} -proc fgetc(stream: TFile): cint {.importc: "fgetc", nodecl, tags: [FReadIO].} -proc ungetc(c: cint, f: TFile) {.importc: "ungetc", nodecl, tags: [].} -proc putc(c: Char, stream: TFile) {.importc: "putc", nodecl, tags: [FWriteIO].} -proc fprintf(f: TFile, frmt: CString) {.importc: "fprintf", nodecl, varargs, - tags: [FWriteIO].} -proc strlen(c: cstring): int {.importc: "strlen", nodecl, tags: [].} +proc fputs(c: cstring, f: TFile) {.importc: "fputs", header: "", + tags: [FWriteIO].} +proc fgets(c: cstring, n: int, f: TFile): cstring {. + importc: "fgets", header: "", tags: [FReadIO].} +proc fgetc(stream: TFile): cint {.importc: "fgetc", header: "", + tags: [FReadIO].} +proc ungetc(c: cint, f: TFile) {.importc: "ungetc", header: "", + tags: [].} +proc putc(c: Char, stream: TFile) {.importc: "putc", header: "", + tags: [FWriteIO].} +proc fprintf(f: TFile, frmt: CString) {.importc: "fprintf", + header: "", varargs, tags: [FWriteIO].} +proc strlen(c: cstring): int {. + importc: "strlen", header: "", tags: [].} # C routine that is used here: proc fread(buf: Pointer, size, n: int, f: TFile): int {. - importc: "fread", noDecl, tags: [FReadIO].} + importc: "fread", header: "", tags: [FReadIO].} proc fseek(f: TFile, offset: clong, whence: int): int {. - importc: "fseek", noDecl, tags: [].} -proc ftell(f: TFile): int {.importc: "ftell", noDecl, tags: [].} + importc: "fseek", header: "", tags: [].} +proc ftell(f: TFile): int {.importc: "ftell", header: "", tags: [].} proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {. - importc, nodecl, tags: [].} + importc, header: "", tags: [].} {.push stackTrace:off, profiler:off.} proc write(f: TFile, c: cstring) = fputs(c, f) {.pop.} var - IOFBF {.importc: "_IOFBF", nodecl.}: cint - IONBF {.importc: "_IONBF", nodecl.}: cint + IOFBF {.importc: "_IOFBF", header: "".}: cint + IONBF {.importc: "_IONBF", header: "".}: cint const buf_size = 4000 proc raiseEIO(msg: string) {.noinline, noreturn.} = - raise newException(EIO, msg) + sysFatal(EIO, msg) proc readLine(f: TFile, line: var TaintedString): bool = # of course this could be optimized a bit; but IO is slow anyway... @@ -197,7 +202,7 @@ proc Open(f: var TFile, filename: string, f = cast[TFile](p) if bufSize > 0 and bufSize <= high(cint).int: if setvbuf(f, nil, IOFBF, bufSize.cint) != 0'i32: - raise newException(EOutOfMemory, "out of memory") + sysFatal(EOutOfMemory, "out of memory") elif bufSize == 0: discard setvbuf(f, nil, IONBF, 0) diff --git a/tests/manyloc/standalone/barebone.nim b/tests/manyloc/standalone/barebone.nim new file mode 100644 index 0000000000..118328d82e --- /dev/null +++ b/tests/manyloc/standalone/barebone.nim @@ -0,0 +1,4 @@ + +proc printf(frmt: cstring) {.varargs, header: "", cdecl.} + +printf("hi %ld\n", 4777) diff --git a/tests/manyloc/standalone/barebone.nimrod.cfg b/tests/manyloc/standalone/barebone.nimrod.cfg new file mode 100644 index 0000000000..52ec64e3f2 --- /dev/null +++ b/tests/manyloc/standalone/barebone.nimrod.cfg @@ -0,0 +1,2 @@ +--os:standalone +--deadCodeElim:on diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim new file mode 100644 index 0000000000..efd2b21f95 --- /dev/null +++ b/tests/manyloc/standalone/panicoverride.nim @@ -0,0 +1,19 @@ + +proc printf(frmt: cstring) {.varargs, importc, header: "", cdecl.} +proc exit(code: int) {.importc, header: "", cdecl.} + +{.push stack_trace: off, profiler:off.} + +proc rawoutput(s: string) = + printf("%s\n", s) + +proc panic(s: string) = + rawoutput(s) + exit(1) + +# Alternatively we also could implement these 2 here: +# +# template sysFatal(exceptn: typeDesc, message: string) +# template sysFatal(exceptn: typeDesc, message, arg: string) + +{.pop.}