--os:standalone works again

This commit is contained in:
Araq 2013-06-30 21:15:28 +02:00
commit 52851b722d
16 changed files with 552 additions and 621 deletions

View file

@ -147,7 +147,7 @@ const
scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}), scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".", props: {}),
(name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/", (name: "Standalone", parDir: "..", dllFrmt: "lib$1.so", altDirSep: "/",
objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/", objExt: ".o", newLine: "\x0A", pathSep: ":", dirSep: "/",
scriptExt: ".sh", curDir: ".", exeExt: ".elf", extSep: ".", scriptExt: ".sh", curDir: ".", exeExt: "", extSep: ".",
props: {})] props: {})]
type type

View file

@ -493,9 +493,14 @@ OS features.
To make the compiler output code for a 16bit target use the ``--cpu:avr`` To make the compiler output code for a 16bit target use the ``--cpu:avr``
target. 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 Nimrod for realtime systems

View file

@ -27,9 +27,7 @@ __clang__
# define _GNU_SOURCE 1 # define _GNU_SOURCE 1
#endif #endif
#if !defined(__TINYC__) #if defined(__TINYC__)
# include <math.h>
#else
/*# define __GNUC__ 3 /*# define __GNUC__ 3
# define GCC_MAJOR 4 # define GCC_MAJOR 4
# define __GNUC_MINOR__ 4 # define __GNUC_MINOR__ 4
@ -58,10 +56,6 @@ __clang__
# define N_INLINE(rettype, name) rettype __inline name # define N_INLINE(rettype, name) rettype __inline name
#endif #endif
#if defined(__POCC__) || defined(_MSC_VER)
# define HAVE_LRINT 1
#endif
#if defined(__POCC__) #if defined(__POCC__)
# define NIM_CONST /* PCC is really picky with const modifiers */ # define NIM_CONST /* PCC is really picky with const modifiers */
# undef _MSC_VER /* Yeah, right PCC defines _MSC_VER even if it is # 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 <erikd AT mega-nerd DOT com>
**
** 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h> #include <limits.h>
#include <stddef.h> #include <stddef.h>
#include <signal.h>
#include <setjmp.h>
/*
#ifndef INF
static unsigned long nimInf[2]={0xffffffff, 0x7fffffff};
# define INF (*(double*) nimInf)
#endif */
/* C99 compiler? */ /* C99 compiler? */
#if (defined(__STD_VERSION__) && (__STD_VERSION__ >= 199901)) #if (defined(__STD_VERSION__) && (__STD_VERSION__ >= 199901))

View file

@ -165,7 +165,7 @@ when not defined(JS):
## float value) equals m * 2**n. frexp stores n in `exponent` and returns ## float value) equals m * 2**n. frexp stores n in `exponent` and returns
## m. ## m.
proc round*(x: float): int {.importc: "lrint", nodecl.} proc round*(x: float): int {.importc: "lrint", header: "<math.h>".}
## converts a float to an int by rounding. ## converts a float to an int by rounding.
proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".} proc arccos*(x: float): float {.importc: "acos", header: "<math.h>".}
@ -191,12 +191,12 @@ when not defined(JS):
# C procs: # C procs:
proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".} proc gettime(dummy: ptr cint): cint {.importc: "time", header: "<time.h>".}
proc srand(seed: cint) {.importc: "srand", nodecl.} proc srand(seed: cint) {.importc: "srand", header: "<stdlib.h>".}
proc rand(): cint {.importc: "rand", nodecl.} proc rand(): cint {.importc: "rand", header: "<stdlib.h>".}
when not defined(windows): when not defined(windows):
proc srand48(seed: clong) {.importc: "srand48", nodecl.} proc srand48(seed: clong) {.importc: "srand48", header: "<stdlib.h>".}
proc drand48(): float {.importc: "drand48", nodecl.} proc drand48(): float {.importc: "drand48", header: "<stdlib.h>".}
proc random(max: float): float = proc random(max: float): float =
result = drand48() * max result = drand48() * max
@ -209,9 +209,9 @@ when not defined(JS):
proc random(max: int): int = proc random(max: int): int =
result = int(rand()) mod max result = int(rand()) mod max
proc trunc*(x: float): float {.importc: "trunc", nodecl.} proc trunc*(x: float): float {.importc: "trunc", header: "<math.h>".}
proc floor*(x: float): float {.importc: "floor", nodecl.} proc floor*(x: float): float {.importc: "floor", header: "<math.h>".}
proc ceil*(x: float): float {.importc: "ceil", nodecl.} proc ceil*(x: float): float {.importc: "ceil", header: "<math.h>".}
proc fmod*(x, y: float): float {.importc: "fmod", header: "<math.h>".} proc fmod*(x, y: float): float {.importc: "fmod", header: "<math.h>".}

View file

@ -450,7 +450,7 @@ proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.} proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as ## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned. ## 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 ## 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``. ## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
## (This is the case on 64 bit processors.) ## (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. ## prematurelly using ``quit``, this value is ignored.
proc quit*(errorcode: int = QuitSuccess) {. proc quit*(errorcode: int = QuitSuccess) {.
magic: "Exit", importc: "exit", noDecl, noReturn.} magic: "Exit", importc: "exit", header: "<stdlib.h>", noReturn.}
## Stops the program immediately with an exit code. ## Stops the program immediately with an exit code.
## ##
## Before stopping the program the "quit procedures" are called in the ## 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 ## rounds `f` if it does not contain an integer value. If the conversion
## fails (because `f` is infinite for example), `EInvalidValue` is raised. ## 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: "<stdlib.h>".}
## adds/registers a quit procedure. Each call to ``addQuitProc`` ## adds/registers a quit procedure. Each call to ``addQuitProc``
## registers another quit procedure. Up to 30 procedures can be ## registers another quit procedure. Up to 30 procedures can be
## registered. They are executed on a last-in, first-out basis ## 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 ## Exactly ``size`` bytes will be overwritten. Like any procedure
## dealing with raw memory this is *unsafe*. ## 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: "<string.h>".}
## copies the contents from the memory at ``source`` to the memory ## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
## regions may not overlap. Like any procedure dealing with raw ## regions may not overlap. Like any procedure dealing with raw
## memory this is *unsafe*. ## memory this is *unsafe*.
proc moveMem*(dest, source: Pointer, size: int) {.importc: "memmove", noDecl.} proc moveMem*(dest, source: Pointer, size: int) {.
importc: "memmove", header: "<string.h>".}
## copies the contents from the memory at ``source`` to the memory ## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
## regions may overlap, ``moveMem`` handles this case appropriately ## regions may overlap, ``moveMem`` handles this case appropriately
@ -1124,6 +1127,7 @@ when not defined(nimrodVM):
## otherwise. Like any procedure dealing with raw memory this is ## otherwise. Like any procedure dealing with raw memory this is
## *unsafe*. ## *unsafe*.
when hostOs != "standalone":
proc alloc*(size: int): pointer {.noconv, rtl, tags: [].} proc alloc*(size: int): pointer {.noconv, rtl, tags: [].}
## allocates a new memory block with at least ``size`` bytes. The ## allocates a new memory block with at least ``size`` bytes. The
## block has to be freed with ``realloc(block, 0)`` or ## block has to be freed with ``realloc(block, 0)`` or
@ -1201,7 +1205,7 @@ proc `$` *(x: int64): string {.magic: "Int64ToStr", noSideEffect.}
## converted to a decimal string. ## converted to a decimal string.
when not defined(NimrodVM): when not defined(NimrodVM):
when not defined(JS): when not defined(JS) and hostOS != "standalone":
proc `$` *(x: uint64): string {.noSideEffect.} proc `$` *(x: uint64): string {.noSideEffect.}
## The stingify operator for an unsigned integer argument. Returns `x` ## The stingify operator for an unsigned integer argument. Returns `x`
## converted to a decimal string. ## converted to a decimal string.
@ -1254,7 +1258,7 @@ const
# GC interface: # GC interface:
when not defined(nimrodVM): when not defined(nimrodVM) and hostOS != "standalone":
proc getOccupiedMem*(): int {.rtl.} proc getOccupiedMem*(): int {.rtl.}
## returns the number of bytes that are owned by the process and hold data. ## returns the number of bytes that are owned by the process and hold data.
@ -1632,7 +1636,7 @@ when false:
# ----------------- GC interface --------------------------------------------- # ----------------- GC interface ---------------------------------------------
when not defined(nimrodVM): when not defined(nimrodVM) and hostOS != "standalone":
proc GC_disable*() {.rtl, inl.} proc GC_disable*() {.rtl, inl.}
## disables the GC. If called n-times, n calls to `GC_enable` are needed to ## 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 ## reactivate the GC. Note that in most circumstances one should only disable
@ -1741,15 +1745,7 @@ type
filename*: cstring ## filename of the proc that is currently executing filename*: cstring ## filename of the proc that is currently executing
len*: int ## length of the inspectable slots len*: int ## length of the inspectable slots
when not defined(JS): when 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:
proc add*(x: var string, y: cstring) {.noStackFrame.} = proc add*(x: var string, y: cstring) {.noStackFrame.} =
asm """ asm """
var len = `x`[0].length-1; var len = `x`[0].length-1;
@ -1759,9 +1755,17 @@ else:
} }
`x`[0][len] = 0 `x`[0][len] = 0
""" """
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} 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].} proc echo*[T](x: varargs[T, `$`]) {.magic: "Echo", tags: [FWriteIO].}
## special built-in that takes a variable number of arguments. Each argument ## special built-in that takes a variable number of arguments. Each argument
## is converted to a string via ``$``, so it works for user-defined ## 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.msg = message
e 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".} proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo".}
## get type information for `x`. Ordinary code should not use this, but ## get type information for `x`. Ordinary code should not use this, but
## the `typeinfo` module instead. ## the `typeinfo` module instead.
@ -1793,7 +1820,7 @@ proc getTypeInfo*[T](x: T): pointer {.magic: "GetTypeInfo".}
when not defined(JS): #and not defined(NimrodVM): when not defined(JS): #and not defined(NimrodVM):
{.push stack_trace: off, profiler:off.} {.push stack_trace: off, profiler:off.}
when not defined(NimrodVM): when not defined(NimrodVM) and hostOS != "standalone":
proc initGC() proc initGC()
when not defined(boehmgc) and not defined(useMalloc): when not defined(boehmgc) and not defined(useMalloc):
proc initAllocator() {.inline.} proc initAllocator() {.inline.}
@ -1839,8 +1866,10 @@ when not defined(JS): #and not defined(NimrodVM):
proc endbStep() proc endbStep()
# ----------------- IO Part ------------------------------------------------ # ----------------- IO Part ------------------------------------------------
when hostOS != "standalone":
type type
CFile {.importc: "FILE", nodecl, final, incompletestruct.} = object CFile {.importc: "FILE", header: "<stdio.h>",
final, incompletestruct.} = object
TFile* = ptr CFile ## The type representing a file handle. TFile* = ptr CFile ## The type representing a file handle.
TFileMode* = enum ## The file mode when opening a file. TFileMode* = enum ## The file mode when opening a file.
@ -1894,7 +1923,7 @@ when not defined(JS): #and not defined(NimrodVM):
## Default mode is readonly. Raises an ``IO`` exception if the file ## Default mode is readonly. Raises an ``IO`` exception if the file
## could not be opened. ## could not be opened.
if not open(result, filename, mode, bufSize): if not open(result, filename, mode, bufSize):
raise newException(EIO, "cannot open: " & filename) sysFatal(EIO, "cannot open: ", filename)
proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool {. proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool {.
tags: [].} tags: [].}
@ -1904,15 +1933,17 @@ when not defined(JS): #and not defined(NimrodVM):
## ##
## Default mode is readonly. Returns true iff the file could be reopened. ## Default mode is readonly. Returns true iff the file could be reopened.
proc Close*(f: TFile) {.importc: "fclose", nodecl, tags: [].} proc Close*(f: TFile) {.importc: "fclose", header: "<stdio.h>", tags: [].}
## Closes the file. ## Closes the file.
proc EndOfFile*(f: TFile): Bool {.tags: [].} proc EndOfFile*(f: TFile): Bool {.tags: [].}
## Returns true iff `f` is at the end. ## Returns true iff `f` is at the end.
proc readChar*(f: TFile): char {.importc: "fgetc", nodecl, tags: [FReadIO].} proc readChar*(f: TFile): char {.
importc: "fgetc", header: "<stdio.h>", tags: [FReadIO].}
## Reads a single character from the stream `f`. ## Reads a single character from the stream `f`.
proc FlushFile*(f: TFile) {.importc: "fflush", noDecl, tags: [FWriteIO].} proc FlushFile*(f: TFile) {.
importc: "fflush", header: "<stdio.h>", tags: [FWriteIO].}
## Flushes `f`'s buffer. ## Flushes `f`'s buffer.
proc readAll*(file: TFile): TaintedString {.tags: [FReadIO].} proc readAll*(file: TFile): TaintedString {.tags: [FReadIO].}
@ -2023,16 +2054,15 @@ when not defined(JS): #and not defined(NimrodVM):
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
when not defined(NimrodVM): when not defined(NimrodVM) and hostOS != "standalone":
proc allocCStringArray*(a: openArray[string]): cstringArray = proc allocCStringArray*(a: openArray[string]): cstringArray =
## creates a NULL terminated cstringArray from `a`. The result has to ## creates a NULL terminated cstringArray from `a`. The result has to
## be freed with `deallocCStringArray` after it's not needed anymore. ## be freed with `deallocCStringArray` after it's not needed anymore.
result = cast[cstringArray](alloc0((a.len+1) * sizeof(cstring))) 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: for i in 0 .. a.high:
# XXX get rid of this string copy here: result[i] = cast[cstring](alloc0(x[i].len+1))
var x = a[i] copyMem(result[i], addr(x[i][0]), x[i].len)
result[i] = cast[cstring](alloc0(x.len+1))
copyMem(result[i], addr(x[0]), x.len)
proc deallocCStringArray*(a: cstringArray) = proc deallocCStringArray*(a: cstringArray) =
## frees a NULL terminated cstringArray. ## frees a NULL terminated cstringArray.
@ -2042,6 +2072,7 @@ when not defined(JS): #and not defined(NimrodVM):
inc(i) inc(i)
dealloc(a) dealloc(a)
when not defined(NimrodVM):
proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable.} proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable.}
## atomic increment of `memLoc`. Returns the value after the operation. ## atomic increment of `memLoc`. Returns the value after the operation.
@ -2064,7 +2095,7 @@ when not defined(JS): #and not defined(NimrodVM):
when hasThreadSupport: when hasThreadSupport:
include "system/syslocks" include "system/syslocks"
include "system/threads" 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() when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
initGC() initGC()
@ -2089,6 +2120,7 @@ when not defined(JS): #and not defined(NimrodVM):
include "system/embedded" include "system/embedded"
else: else:
include "system/excpt" include "system/excpt"
include "system/chcks"
# we cannot compile this with stack tracing on # we cannot compile this with stack tracing on
# as it would recurse endlessly! # as it would recurse endlessly!
@ -2124,17 +2156,18 @@ when not defined(JS): #and not defined(NimrodVM):
else: else:
result = n.sons[n.len] result = n.sons[n.len]
include "system/mmdisp" when hostOS != "standalone": include "system/mmdisp"
{.push stack_trace: off, profiler:off.} {.push stack_trace: off, profiler:off.}
when hostOS != "standalone": include "system/sysstr" when hostOS != "standalone": include "system/sysstr"
{.pop.} {.pop.}
include "system/sysio" when hostOS != "standalone": include "system/sysio"
when hasThreadSupport: when hasThreadSupport:
include "system/channels" when hostOS != "standalone": include "system/channels"
else: else:
include "system/sysio" include "system/sysio"
when hostOS != "standalone":
iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} = iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} =
## Iterate over any line in the file named `filename`. ## Iterate over any line in the file named `filename`.
## If the file does not exist `EIO` is raised. ## If the file does not exist `EIO` is raised.
@ -2146,7 +2179,7 @@ when not defined(JS): #and not defined(NimrodVM):
iterator lines*(f: TFile): TaintedString {.tags: [FReadIO].} = iterator lines*(f: TFile): TaintedString {.tags: [FReadIO].} =
## Iterate over any line in the file `f`. ## Iterate over any line in the file `f`.
var res = TaintedString(newStringOfCap(80)) var res = TaintedString(newStringOfCap(80))
while f.readLine(res): yield TaintedString(res) while f.readLine(res): yield res
when hostOS != "standalone" and not defined(NimrodVM): when hostOS != "standalone" and not defined(NimrodVM):
include "system/assign" include "system/assign"
@ -2263,10 +2296,6 @@ proc `/`*(x, y: int): float {.inline, noSideEffect.} =
template `-|`*(b, s: expr): expr = template `-|`*(b, s: expr): expr =
(if b >= 0: b else: s.len + b) (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.} = template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
# make room for additional elements or cut: # make room for additional elements or cut:
var slen = s.len var slen = s.len
@ -2283,6 +2312,11 @@ template spliceImpl(s, a, L, b: expr): stmt {.immediate.} =
# fill the hole: # fill the hole:
for i in 0 .. <b.len: s[i+a] = b[i] for i in 0 .. <b.len: s[i+a] = b[i]
when hostOS != "standalone":
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)
proc `[]=`*(s: var string, x: TSlice[int], b: string) = proc `[]=`*(s: var string, x: TSlice[int], b: string) =
## slice assignment for strings. Negative indexes are supported. If ## slice assignment for strings. Negative indexes are supported. If
## ``b.len`` is not exactly the number of elements that are referred to ## ``b.len`` is not exactly the number of elements that are referred to
@ -2313,7 +2347,7 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: TSlice[int], b: openArray[T]) =
if L == b.len: if L == b.len:
for i in 0 .. <L: a[i+x.a] = b[i] for i in 0 .. <L: a[i+x.a] = b[i]
else: else:
raise newException(EOutOfRange, "differing lengths for slice assignment") sysFatal(EOutOfRange, "differing lengths for slice assignment")
proc `[]`*[Idx, T](a: array[Idx, T], x: TSlice[Idx]): seq[T] = proc `[]`*[Idx, T](a: array[Idx, T], x: TSlice[Idx]): seq[T] =
## slice operation for arrays. Negative indexes are **not** supported ## slice operation for arrays. Negative indexes are **not** supported
@ -2335,7 +2369,7 @@ proc `[]=`*[Idx, T](a: var array[Idx, T], x: TSlice[Idx], b: openArray[T]) =
a[j] = b[i] a[j] = b[i]
inc(j) inc(j)
else: else:
raise newException(EOutOfRange, "differing lengths for slice assignment") sysFatal(EOutOfRange, "differing lengths for slice assignment")
proc `[]`*[T](s: seq[T], x: TSlice[int]): seq[T] = proc `[]`*[T](s: seq[T], x: TSlice[int]): seq[T] =
## slice operation for sequences. Negative indexes are supported. ## slice operation for sequences. Negative indexes are supported.
@ -2448,7 +2482,7 @@ template CurrentSourcePath*: string = InstantiationInfo(-1, true).filename
## returns the full file-system path of the current source ## returns the full file-system path of the current source
proc raiseAssert*(msg: string) {.noinline.} = proc raiseAssert*(msg: string) {.noinline.} =
raise newException(EAssertionFailed, msg) sysFatal(EAssertionFailed, msg)
when true: when true:
proc hiddenRaiseAssert(msg: string) {.raises: [], tags: [].} = proc hiddenRaiseAssert(msg: string) {.raises: [], tags: [].} =
@ -2532,6 +2566,7 @@ template eval*(blk: stmt): stmt =
macro payload: stmt {.gensym.} = blk macro payload: stmt {.gensym.} = blk
payload() payload()
when hostOS != "standalone":
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} = proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
## inserts `item` into `x` at position `i`. ## inserts `item` into `x` at position `i`.
var xl = x.len var xl = x.len
@ -2558,6 +2593,7 @@ proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} =
when defined(initDebugger): when defined(initDebugger):
initDebugger() initDebugger()
when hostOS != "standalone":
# XXX: make these the default (or implement the NilObject optimization) # XXX: make these the default (or implement the NilObject optimization)
proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect.} = proc safeAdd*[T](x: var seq[T], y: T) {.noSideEffect.} =
if x == nil: x = @[y] if x == nil: x = @[y]

View file

@ -13,25 +13,30 @@
{.push hints:off} {.push hints:off}
proc c_strcmp(a, b: CString): cint {.nodecl, noSideEffect, importc: "strcmp".} proc c_strcmp(a, b: CString): cint {.header: "<string.h>",
proc c_memcmp(a, b: CString, size: int): cint {. noSideEffect, importc: "strcmp".}
nodecl, noSideEffect, importc: "memcmp".} proc c_memcmp(a, b: CString, size: int): cint {.header: "<string.h>",
proc c_memcpy(a, b: CString, size: int) {.nodecl, importc: "memcpy".} noSideEffect, importc: "memcmp".}
proc c_strlen(a: CString): int {.nodecl, noSideEffect, importc: "strlen".} proc c_memcpy(a, b: CString, size: int) {.header: "<string.h>", importc: "memcpy".}
proc c_memset(p: pointer, value: cint, size: int) {.nodecl, importc: "memset".} proc c_strlen(a: CString): int {.header: "<string.h>",
noSideEffect, importc: "strlen".}
proc c_memset(p: pointer, value: cint, size: int) {.
header: "<string.h>", importc: "memset".}
type type
C_TextFile {.importc: "FILE", nodecl, final, incompleteStruct.} = object C_TextFile {.importc: "FILE", header: "<stdio.h>",
C_BinaryFile {.importc: "FILE", nodecl, final, incompleteStruct.} = object final, incompleteStruct.} = object
C_BinaryFile {.importc: "FILE", header: "<stdio.h>",
final, incompleteStruct.} = object
C_TextFileStar = ptr CTextFile C_TextFileStar = ptr CTextFile
C_BinaryFileStar = ptr CBinaryFile C_BinaryFileStar = ptr CBinaryFile
C_JmpBuf {.importc: "jmp_buf".} = array[0..31, int] C_JmpBuf {.importc: "jmp_buf", header: "<setjmp.h>".} = array[0..31, int]
var var
c_stdin {.importc: "stdin", noDecl.}: C_TextFileStar c_stdin {.importc: "stdin", header: "<stdio.h>".}: C_TextFileStar
c_stdout {.importc: "stdout", noDecl.}: C_TextFileStar c_stdout {.importc: "stdout", header: "<stdio.h>".}: C_TextFileStar
c_stderr {.importc: "stderr", noDecl.}: C_TextFileStar c_stderr {.importc: "stderr", header: "<stdio.h>".}: C_TextFileStar
# constants faked as variables: # constants faked as variables:
when not defined(SIGINT): when not defined(SIGINT):
@ -51,59 +56,70 @@ else:
SIGBUS {.importc: "SIGSEGV", nodecl.}: cint SIGBUS {.importc: "SIGSEGV", nodecl.}: cint
# only Mac OS X has this shit # only Mac OS X has this shit
proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.nodecl, importc: "longjmp".} proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
proc c_setjmp(jmpb: var C_JmpBuf): cint {.nodecl, importc: "setjmp".} header: "<setjmp.h>", importc: "longjmp".}
proc c_setjmp(jmpb: var C_JmpBuf): cint {.
header: "<setjmp.h>", importc: "setjmp".}
proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {. proc c_signal(sig: cint, handler: proc (a: cint) {.noconv.}) {.
importc: "signal", header: "<signal.h>".} importc: "signal", header: "<signal.h>".}
proc c_raise(sig: cint) {.importc: "raise", header: "<signal.h>".} proc c_raise(sig: cint) {.importc: "raise", header: "<signal.h>".}
proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs", noDecl.} proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs",
header: "<stdio.h>".}
proc c_fgets(c: cstring, n: int, f: C_TextFileStar): cstring {. proc c_fgets(c: cstring, n: int, f: C_TextFileStar): cstring {.
importc: "fgets", noDecl.} importc: "fgets", header: "<stdio.h>".}
proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc", nodecl.} proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc",
proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc", nodecl.} header: "<stdio.h>".}
proc c_putc(c: Char, stream: C_TextFileStar) {.importc: "putc", nodecl.} proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc",
header: "<stdio.h>".}
proc c_putc(c: Char, stream: C_TextFileStar) {.importc: "putc",
header: "<stdio.h>".}
proc c_fprintf(f: C_TextFileStar, frmt: CString) {. proc c_fprintf(f: C_TextFileStar, frmt: CString) {.
importc: "fprintf", nodecl, varargs.} importc: "fprintf", header: "<stdio.h>", varargs.}
proc c_printf(frmt: CString) {. proc c_printf(frmt: CString) {.
importc: "printf", nodecl, varargs.} importc: "printf", header: "<stdio.h>", varargs.}
proc c_fopen(filename, mode: cstring): C_TextFileStar {. proc c_fopen(filename, mode: cstring): C_TextFileStar {.
importc: "fopen", nodecl.} importc: "fopen", header: "<stdio.h>".}
proc c_fclose(f: C_TextFileStar) {.importc: "fclose", nodecl.} proc c_fclose(f: C_TextFileStar) {.importc: "fclose", header: "<stdio.h>".}
proc c_sprintf(buf, frmt: CString) {.nodecl, importc: "sprintf", varargs, proc c_sprintf(buf, frmt: CString) {.header: "<stdio.h>",
noSideEffect.} importc: "sprintf", varargs, noSideEffect.}
# we use it only in a way that cannot lead to security issues # 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 {. proc c_fread(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {.
importc: "fread", noDecl.} importc: "fread", header: "<stdio.h>".}
proc c_fseek(f: C_BinaryFileStar, offset: clong, whence: int): int {. proc c_fseek(f: C_BinaryFileStar, offset: clong, whence: int): int {.
importc: "fseek", noDecl.} importc: "fseek", header: "<stdio.h>".}
proc c_fwrite(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {. proc c_fwrite(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {.
importc: "fwrite", noDecl.} importc: "fwrite", header: "<stdio.h>".}
proc c_exit(errorcode: cint) {.importc: "exit", nodecl.} proc c_exit(errorcode: cint) {.importc: "exit", header: "<stdlib.h>".}
proc c_ferror(stream: C_TextFileStar): bool {.importc: "ferror", nodecl.} proc c_ferror(stream: C_TextFileStar): bool {.
proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", nodecl.} importc: "ferror", header: "<stdio.h>".}
proc c_abort() {.importc: "abort", nodecl.} proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", header: "<stdio.h>".}
proc c_feof(stream: C_TextFileStar): bool {.importc: "feof", nodecl.} proc c_abort() {.importc: "abort", header: "<stdlib.h>".}
proc c_feof(stream: C_TextFileStar): bool {.
importc: "feof", header: "<stdio.h>".}
proc c_malloc(size: int): pointer {.importc: "malloc", nodecl.} proc c_malloc(size: int): pointer {.importc: "malloc", header: "<stdlib.h>".}
proc c_free(p: pointer) {.importc: "free", nodecl.} proc c_free(p: pointer) {.importc: "free", header: "<stdlib.h>".}
proc c_realloc(p: pointer, newsize: int): pointer {.importc: "realloc", nodecl.} proc c_realloc(p: pointer, newsize: int): pointer {.
importc: "realloc", header: "<stdlib.h>".}
when not defined(errno): when not defined(errno):
var errno {.importc, header: "<errno.h>".}: cint ## error variable var errno {.importc, header: "<errno.h>".}: cint ## error variable
proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".} proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
proc c_remove(filename: CString): cint {.importc: "remove", noDecl.} proc c_remove(filename: CString): cint {.
proc c_rename(oldname, newname: CString): cint {.importc: "rename", noDecl.} importc: "remove", header: "<stdio.h>".}
proc c_rename(oldname, newname: CString): cint {.
importc: "rename", header: "<stdio.h>".}
proc c_system(cmd: CString): cint {.importc: "system", header: "<stdlib.h>".} proc c_system(cmd: CString): cint {.importc: "system", header: "<stdlib.h>".}
proc c_getenv(env: CString): CString {.importc: "getenv", noDecl.} proc c_getenv(env: CString): CString {.importc: "getenv", header: "<stdlib.h>".}
proc c_putenv(env: CString): cint {.importc: "putenv", noDecl.} proc c_putenv(env: CString): cint {.importc: "putenv", header: "<stdlib.h>".}
{.pop} {.pop}

View file

@ -12,10 +12,10 @@
proc raiseOverflow {.compilerproc, noinline, noreturn.} = proc raiseOverflow {.compilerproc, noinline, noreturn.} =
# a single proc to reduce code size to a minimum # 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.} = proc raiseDivByZero {.compilerproc, noinline, noreturn.} =
raise newException(EDivByZero, "divison by zero") sysFatal(EDivByZero, "divison by zero")
proc addInt64(a, b: int64): int64 {.compilerProc, inline.} = proc addInt64(a, b: int64): int64 {.compilerProc, inline.} =
result = a +% b result = a +% b
@ -322,16 +322,16 @@ when not defined(mulInt):
# written in other languages. # written in other languages.
proc raiseFloatInvalidOp {.noinline, noreturn.} = 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.} = proc nanCheck(x: float64) {.compilerProc, inline.} =
if x != x: raiseFloatInvalidOp() if x != x: raiseFloatInvalidOp()
proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} = proc raiseFloatOverflow(x: float64) {.noinline, noreturn.} =
if x > 0.0: if x > 0.0:
raise newException(EFloatOverflow, "FPU operation caused an overflow") sysFatal(EFloatOverflow, "FPU operation caused an overflow")
else: else:
raise newException(EFloatUnderflow, "FPU operations caused an underflow") sysFatal(EFloatUnderflow, "FPU operations caused an underflow")
proc infCheck(x: float64) {.compilerProc, inline.} = proc infCheck(x: float64) {.compilerProc, inline.} =
if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x) if x != 0.0 and x*0.5 == x: raiseFloatOverflow(x)

View file

@ -223,6 +223,4 @@ proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int,
var oldBranch = selectBranch(oldDiscVal, L, a) var oldBranch = selectBranch(oldDiscVal, L, a)
var newBranch = selectBranch(newDiscVal, L, a) var newBranch = selectBranch(newDiscVal, L, a)
if newBranch != oldBranch and oldDiscVal != 0: if newBranch != oldBranch and oldDiscVal != 0:
raise newException(EInvalidField, sysFatal(EInvalidField, "assignment to discriminant changes object branch")
"assignment to discriminant changes object branch")

View file

@ -187,7 +187,7 @@ template lockChannel(q: expr, action: stmt) {.immediate.} =
template sendImpl(q: expr) {.immediate.} = template sendImpl(q: expr) {.immediate.} =
if q.mask == ChannelDeadMask: if q.mask == ChannelDeadMask:
raise newException(EDeadThread, "cannot send message; thread died") sysFatal(EDeadThread, "cannot send message; thread died")
acquireSys(q.lock) acquireSys(q.lock)
var m: TMsg var m: TMsg
shallowCopy(m, msg) shallowCopy(m, msg)
@ -211,7 +211,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
q.ready = false q.ready = false
if typ != q.elemType: if typ != q.elemType:
releaseSys(q.lock) releaseSys(q.lock)
raise newException(EInvalidValue, "cannot receive message of wrong type") sysFatal(EInvalidValue, "cannot receive message of wrong type")
rawRecv(q, res, typ) rawRecv(q, res, typ)
releaseSys(q.lock) releaseSys(q.lock)

77
lib/system/chcks.nim Normal file
View file

@ -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

View file

@ -10,8 +10,6 @@
# Bare-bones implementation of some things for embedded targets. # 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 chckIndx(i, a, b: int): int {.inline, compilerproc.}
proc chckRange(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.} proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
@ -35,72 +33,11 @@ proc quitOrDebug() {.inline.} =
quit(1) quit(1)
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} = proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
writeToStdErr(ename) sysFatal(ENoExceptionToReraise, "exception handling is not available")
proc reraiseException() {.compilerRtl.} = proc reraiseException() {.compilerRtl.} =
writeToStdErr("reraise not supported") sysFatal(ENoExceptionToReraise, "no exception to reraise")
proc WriteStackTrace() = nil proc WriteStackTrace() = nil
proc setControlCHook(hook: proc () {.noconv.}) = proc setControlCHook(hook: proc () {.noconv.}) = nil
# 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

View file

@ -249,7 +249,7 @@ proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
proc reraiseException() {.compilerRtl.} = proc reraiseException() {.compilerRtl.} =
if currException == nil: if currException == nil:
raise newException(ENoExceptionToReraise, "no exception to reraise") sysFatal(ENoExceptionToReraise, "no exception to reraise")
else: else:
raiseExceptionAux(currException) raiseExceptionAux(currException)
@ -324,63 +324,3 @@ proc setControlCHook(hook: proc () {.noconv.}) =
# ugly cast, but should work on all architectures: # ugly cast, but should work on all architectures:
type TSignalHandler = proc (sig: cint) {.noconv.} type TSignalHandler = proc (sig: cint) {.noconv.}
c_signal(SIGINT, cast[TSignalHandler](hook)) 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

View file

@ -16,39 +16,44 @@
# of the standard library! # of the standard library!
proc fputs(c: cstring, f: TFile) {.importc: "fputs", noDecl, tags: [FWriteIO].} proc fputs(c: cstring, f: TFile) {.importc: "fputs", header: "<stdio.h>",
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].} tags: [FWriteIO].}
proc strlen(c: cstring): int {.importc: "strlen", nodecl, tags: [].} proc fgets(c: cstring, n: int, f: TFile): cstring {.
importc: "fgets", header: "<stdio.h>", tags: [FReadIO].}
proc fgetc(stream: TFile): cint {.importc: "fgetc", header: "<stdio.h>",
tags: [FReadIO].}
proc ungetc(c: cint, f: TFile) {.importc: "ungetc", header: "<stdio.h>",
tags: [].}
proc putc(c: Char, stream: TFile) {.importc: "putc", header: "<stdio.h>",
tags: [FWriteIO].}
proc fprintf(f: TFile, frmt: CString) {.importc: "fprintf",
header: "<stdio.h>", varargs, tags: [FWriteIO].}
proc strlen(c: cstring): int {.
importc: "strlen", header: "<string.h>", tags: [].}
# C routine that is used here: # C routine that is used here:
proc fread(buf: Pointer, size, n: int, f: TFile): int {. proc fread(buf: Pointer, size, n: int, f: TFile): int {.
importc: "fread", noDecl, tags: [FReadIO].} importc: "fread", header: "<stdio.h>", tags: [FReadIO].}
proc fseek(f: TFile, offset: clong, whence: int): int {. proc fseek(f: TFile, offset: clong, whence: int): int {.
importc: "fseek", noDecl, tags: [].} importc: "fseek", header: "<stdio.h>", tags: [].}
proc ftell(f: TFile): int {.importc: "ftell", noDecl, tags: [].} proc ftell(f: TFile): int {.importc: "ftell", header: "<stdio.h>", tags: [].}
proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {. proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {.
importc, nodecl, tags: [].} importc, header: "<stdio.h>", tags: [].}
{.push stackTrace:off, profiler:off.} {.push stackTrace:off, profiler:off.}
proc write(f: TFile, c: cstring) = fputs(c, f) proc write(f: TFile, c: cstring) = fputs(c, f)
{.pop.} {.pop.}
var var
IOFBF {.importc: "_IOFBF", nodecl.}: cint IOFBF {.importc: "_IOFBF", header: "<stdio.h>".}: cint
IONBF {.importc: "_IONBF", nodecl.}: cint IONBF {.importc: "_IONBF", header: "<stdio.h>".}: cint
const const
buf_size = 4000 buf_size = 4000
proc raiseEIO(msg: string) {.noinline, noreturn.} = proc raiseEIO(msg: string) {.noinline, noreturn.} =
raise newException(EIO, msg) sysFatal(EIO, msg)
proc readLine(f: TFile, line: var TaintedString): bool = proc readLine(f: TFile, line: var TaintedString): bool =
# of course this could be optimized a bit; but IO is slow anyway... # 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) f = cast[TFile](p)
if bufSize > 0 and bufSize <= high(cint).int: if bufSize > 0 and bufSize <= high(cint).int:
if setvbuf(f, nil, IOFBF, bufSize.cint) != 0'i32: if setvbuf(f, nil, IOFBF, bufSize.cint) != 0'i32:
raise newException(EOutOfMemory, "out of memory") sysFatal(EOutOfMemory, "out of memory")
elif bufSize == 0: elif bufSize == 0:
discard setvbuf(f, nil, IONBF, 0) discard setvbuf(f, nil, IONBF, 0)

View file

@ -0,0 +1,4 @@
proc printf(frmt: cstring) {.varargs, header: "<stdio.h>", cdecl.}
printf("hi %ld\n", 4777)

View file

@ -0,0 +1,2 @@
--os:standalone
--deadCodeElim:on

View file

@ -0,0 +1,19 @@
proc printf(frmt: cstring) {.varargs, importc, header: "<stdio.h>", cdecl.}
proc exit(code: int) {.importc, header: "<stdlib.h>", 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.}