handling of compiler procs improved for DLL generation

This commit is contained in:
Andreas Rumpf
2010-07-29 21:30:04 +02:00
parent 804e2ac89d
commit ff02ce2d50
33 changed files with 694 additions and 664 deletions

39
lib/nimrtl.nim Executable file
View File

@@ -0,0 +1,39 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Main file to generate a DLL from the standard library.
## The default Nimrtl does not only contain the ``system`` module, but these
## too:
##
## * strutils
## * parseutils
## * parseopt
## * parsecfg
## * strtabs
## * times
## * os
## * osproc
## * pegs
## * unicode
## * ropes
## * re
##
## So the resulting dynamic library is quite big. However, it is very easy to
## strip modules out. Just modify the ``import`` statement in
## ``lib/nimrtl.nim`` and recompile. Note that simply *adding* a module
## here is not sufficient, though.
when system.appType != "lib":
{.error: "This file has to be compiled as a library!".}
when not defined(createNimRtl):
{.error: "This file has to be compiled with '-d:createNimRtl'".}

View File

@@ -125,19 +125,6 @@ proc find*(s: string, chars: set[char], start: int = 0): int {.noSideEffect.}
## Searches for `chars` in `s` starting at position `start`. If `s` contains
## none of the characters in `chars`, -1 is returned.
proc replaceStr*(s, sub, by: string): string {.noSideEffect, deprecated.}
## Replaces `sub` in `s` by the string `by`.
## **Deprecated since version 0.8.0**: Use `replace` instead.
proc replaceStr*(s: string, sub, by: char): string {.noSideEffect, deprecated.}
## optimized version for characters.
## **Deprecated since version 0.8.0**: Use `replace` instead.
proc deleteStr*(s: var string, first, last: int) {.deprecated.}
## Deletes in `s` the characters at position `first` .. `last`. This modifies
## `s` itself, it does not return a copy.
## **Deprecated since version 0.8.0**: Use `delete` instead.
proc toOctal*(c: char): string
## Converts a character `c` to its octal representation. The resulting
## string may not have a leading zero. Its length is always exactly 3.
@@ -241,24 +228,6 @@ iterator splitLines*(s: string): string =
else: break # was '\0'
first = last
proc splitLinesSeq*(s: string): seq[string] {.noSideEffect, deprecated.} =
## The same as `splitLines`, but is a proc that returns a sequence
## of substrings.
## **Deprecated since version 0.8.0**: Use `splitLines` instead.
accumulateResult(splitLines(s))
proc splitSeq*(s: string, seps: set[char] = Whitespace): seq[string] {.
noSideEffect, deprecated.} =
## The same as `split`, but is a proc that returns a sequence of substrings.
## **Deprecated since version 0.8.0**: Use `split` instead.
accumulateResult(split(s, seps))
proc splitSeq*(s: string, sep: char): seq[string] {.noSideEffect,
deprecated.} =
## The same as `split`, but is a proc that returns a sequence of substrings.
## **Deprecated since version 0.8.0**: Use `split` instead.
accumulateResult(split(s, sep))
proc splitLines*(s: string): seq[string] {.noSideEffect.} =
## The same as the `splitLines` iterator, but is a proc that returns a
## sequence of substrings.
@@ -328,12 +297,6 @@ proc ParseHexInt*(s: string): int {.noSideEffect, procvar.}
## following optional prefixes: ``0x``, ``0X``, ``#``.
## Underscores within `s` are ignored.
# the stringify and format operators:
proc toString*[Ty](x: Ty): string {.deprecated.}
## This generic proc is the same as the stringify operator `$`.
##
## **Deprecated since version 0.8.2:** Use `$` instead.
proc repeatChar*(count: int, c: Char = ' '): string
## Returns a string of length `count` consisting only of
## the character `c`.
@@ -670,10 +633,6 @@ proc delete*(s: var string, first, last: int) =
inc(j)
setlen(s, newLen)
proc replaceStr(s, sub, by: string): string = return replace(s, sub, by)
proc replaceStr(s: string, sub, by: char): string = return replace(s, sub, by)
proc deleteStr(s: var string, first, last: int) = delete(s, first, last)
# parsing numbers:
proc toHex(x: BiggestInt, len: int): string =

View File

@@ -667,6 +667,8 @@ proc `&` * (x: char, y: string): string {.
proc add*(x: var string, y: char) {.magic: "AppendStrCh", noSideEffect.}
proc add*(x: var string, y: string) {.magic: "AppendStrStr", noSideEffect.}
include "system/cgprocs"
when not defined(ECMAScript):
{.push overflow_checks:off}
proc add* (x: var string, y: cstring) =
@@ -732,7 +734,6 @@ type
## is the signed integer type that should be used for converting
## pointers to integer addresses for readability.
type
BiggestInt* = int64
## is an alias for the biggest signed integer type the Nimrod compiler
## supports. Currently this is ``int64``, but it is platform-dependant
@@ -767,7 +768,7 @@ type # these work for most platforms:
cstringArray* {.importc: "char**", nodecl.} = ptr array [0..50_000, cstring]
## This is binary compatible to the type ``char**`` in *C*. The array's
## high value is large enough to disable bounds checking in practice.
## Use cstringArrayToSeq to convert it into a ``seq[string]``.
## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
TEndian* = enum ## is a type describing the endianness of a processor.
littleEndian, bigEndian
@@ -823,6 +824,8 @@ const
## a string that describes the application type. Possible values:
## "console", "gui", "lib".
include "system/inclrtl"
proc toFloat*(i: int): float {.
magic: "ToFloat", noSideEffect, importc: "toFloat".}
## converts an integer `i` into a ``float``. If the conversion
@@ -897,23 +900,23 @@ proc equalMem*(a, b: Pointer, size: int): bool {.
## otherwise. Like any procedure dealing with raw memory this is
## *unsafe*.
proc alloc*(size: int): pointer {.noconv.}
proc alloc*(size: int): pointer {.noconv, rtl.}
## 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!
proc alloc0*(size: int): pointer {.noconv.}
proc alloc0*(size: int): pointer {.noconv, rtl.}
## 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``.
proc realloc*(p: Pointer, newsize: int): pointer {.noconv.}
proc realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl.}
## 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``.
proc dealloc*(p: Pointer) {.noconv.}
proc dealloc*(p: Pointer) {.noconv, rtl.}
## 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
@@ -1009,14 +1012,14 @@ var
# GC interface:
proc getOccupiedMem*(): int
proc getOccupiedMem*(): int {.rtl.}
## returns the number of bytes that are owned by the process and hold data.
proc getFreeMem*(): int
proc getFreeMem*(): int {.rtl.}
## returns the number of bytes that are owned by the process, but do not
## hold any meaningful data.
proc getTotalMem*(): int
proc getTotalMem*(): int {.rtl.}
## returns the number of bytes that are owned by the process.
@@ -1205,15 +1208,15 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
# ----------------- GC interface ---------------------------------------------
proc GC_disable*()
proc GC_disable*() {.rtl.}
## disables the GC. If called n-times, n calls to `GC_enable` are needed to
## reactivate the GC. Note that in most circumstances one should only disable
## the mark and sweep phase with `GC_disableMarkAndSweep`.
proc GC_enable*()
proc GC_enable*() {.rtl.}
## enables the GC again.
proc GC_fullCollect*()
proc GC_fullCollect*() {.rtl.}
## forces a full garbage collection pass.
## Ordinary code does not need to call this (and should not).
@@ -1224,18 +1227,18 @@ type
gcOptimizeTime, ## optimize for speed
gcOptimizeSpace ## optimize for memory footprint
proc GC_setStrategy*(strategy: TGC_Strategy)
proc GC_setStrategy*(strategy: TGC_Strategy) {.rtl.}
## tells the GC the desired strategy for the application.
proc GC_enableMarkAndSweep*()
proc GC_disableMarkAndSweep*()
proc GC_enableMarkAndSweep*() {.rtl.}
proc GC_disableMarkAndSweep*() {.rtl.}
## the current implementation uses a reference counting garbage collector
## with a seldomly run mark and sweep phase to free cycles. The mark and
## sweep phase may take a long time and is not needed if the application
## does not create cycles. Thus the mark and sweep phase can be deactivated
## and activated separately from the rest of the GC.
proc GC_getStatistics*(): string
proc GC_getStatistics*(): string {.rtl.}
## returns an informative string about the GC's activity. This may be useful
## for tweaking.
@@ -1372,23 +1375,14 @@ when not defined(EcmaScript) and not defined(NimrodVM):
## appropriately. It also annoys people if redirection via ``>output.txt``
## does not work because the program writes to ``stderr``.
proc OpenFile*(f: var TFile, filename: string,
mode: TFileMode = fmRead,
bufSize: int = -1): Bool {.deprecated.}
## **Deprecated since version 0.8.0**: Use `open` instead.
proc OpenFile*(f: var TFile, filehandle: TFileHandle,
mode: TFileMode = fmRead): Bool {.deprecated.}
## **Deprecated since version 0.8.0**: Use `open` instead.
proc Open*(f: var TFile, filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): Bool
## 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. The reason is
## that the programmer needs to provide an appropriate error message anyway
## (yes, even in scripts).
## that the programmer needs to provide an appropriate error message
## anyway.
proc Open*(f: var TFile, filehandle: TFileHandle,
mode: TFileMode = fmRead): Bool
@@ -1403,10 +1397,6 @@ when not defined(EcmaScript) and not defined(NimrodVM):
##
## Default mode is readonly. Returns true iff the file could be reopened.
proc CloseFile*(f: TFile) {.importc: "fclose", nodecl, deprecated.}
## Closes the file.
## **Deprecated since version 0.8.0**: Use `close` instead.
proc Close*(f: TFile) {.importc: "fclose", nodecl.}
## Closes the file.
@@ -1545,7 +1535,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
const
GenericSeqSize = (2 * sizeof(int))
proc reprAny(p: pointer, typ: PNimType): string {.compilerproc.}
proc reprAny(p: pointer, typ: PNimType): string {.compilerRtl.}
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
assert(n.kind == nkCase)

14
lib/system/cgprocs.nim Normal file
View File

@@ -0,0 +1,14 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
# Headers for procs that the code generator depends on ("compilerprocs")
proc addChar(s: NimString, c: char): NimString {.compilerProc.}

View File

@@ -24,7 +24,12 @@ proc nimUnloadLibrary(lib: TLibHandle) {.compilerproc.}
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr {.compilerproc.}
proc nimLoadLibraryError(path: string) {.compilerproc, noinline.} =
raise newException(EInvalidLibrary, "could not load: " & path)
when true:
# carefully written to avoid memory allocation:
stdout.write("could not load: ")
quit(path)
else:
raise newException(EInvalidLibrary, "could not load: " & path)
# this code was inspired from Lua's source code:
# Lua - An Extensible Extension Language

View File

@@ -74,13 +74,13 @@ var
# This is wasteful but safe. This is a lock against recursive garbage
# collection, not a lock for threads!
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc.}
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerRtl.}
# unsureAsgnRef updates the reference counters only if dest is not on the
# stack. It is used by the code generator if it cannot decide wether a
# reference is in the stack or not (this can happen for var parameters).
#proc growObj(old: pointer, newsize: int): pointer {.compilerproc.}
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.}
proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.}
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.}
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
if (c.refcount and rcZct) == 0:
@@ -214,8 +214,10 @@ proc prepareDealloc(cell: PCell) =
(cast[TFinalizer](cell.typ.finalizer))(cellToUsr(cell))
dec(recGcLock)
proc setStackBottom(theStackBottom: pointer) {.compilerproc.} =
stackBottom = theStackBottom
proc setStackBottom(theStackBottom: pointer) {.compilerRtl.} =
# the first init must be the one that defines the stack bottom:
if stackBottom == nil:
stackBottom = theStackBottom
proc PossibleRoot(gch: var TGcHeap, c: PCell) {.inline.} =
if canbeCycleRoot(c): incl(gch.cycleRoots, c)
@@ -236,10 +238,10 @@ proc incRef(c: PCell) {.inline.} =
if canBeCycleRoot(c):
incl(gch.cycleRoots, c)
proc nimGCref(p: pointer) {.compilerproc, inline.} = incRef(usrToCell(p))
proc nimGCunref(p: pointer) {.compilerproc, inline.} = decRef(usrToCell(p))
proc nimGCref(p: pointer) {.compilerRtl, inl.} = incRef(usrToCell(p))
proc nimGCunref(p: pointer) {.compilerRtl, inl.} = decRef(usrToCell(p))
proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
proc asgnRef(dest: ppointer, src: pointer) {.compilerRtl, inl.} =
# the code generator calls this proc!
assert(not isOnStack(dest))
# BUGFIX: first incRef then decRef!
@@ -247,7 +249,7 @@ proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
if dest^ != nil: decRef(usrToCell(dest^))
dest^ = src
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerRtl, inl.} =
# the code generator calls this proc if it is known at compile time that no
# cycle is possible.
if src != nil:

45
lib/system/inclrtl.nim Executable file
View File

@@ -0,0 +1,45 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Pragmas for RTL generation. Has to be an include, because user-defined
## pragmas cannot be exported.
# There are 3 different usages:
# 1) Ordinary imported code.
# 2) Imported from nimrtl.
# -> defined(useNimRtl) or appType == "lib" and not defined(createNimRtl)
# 3) Exported into nimrtl.
# -> appType == "lib" and defined(createNimRtl)
when defined(createNimRtl):
when defined(useNimRtl):
{.error: "Cannot create and use nimrtl at the same time!".}
elif appType != "lib":
{.error: "nimrtl must be build as a library!".}
when defined(createNimRtl):
# NOTE: compilerproc cannot make use of name mangling!
{.pragma: rtl, exportc: "nimrtl_$1", dynlib.}
{.pragma: inl.}
{.pragma: compilerRtl, compilerproc, exportc: "nimrtl_$1", dynlib.}
elif defined(useNimRtl):
when hostOS == "windows":
const nimrtl* = "nimrtl.dll"
elif hostOS == "macosx":
const nimrtl* = "nimrtl.dynlib"
else:
const nimrtl* = "libnimrtl.so"
{.pragma: rtl, importc: "nimrtl_$1", dynlib: nimrtl.}
{.pragma: inl.}
{.pragma: compilerRtl, compilerproc, importc: "nimrtl_$1", dynlib: nimrtl.}
else:
{.pragma: rtl.}
{.pragma: inl, inline.}
{.pragma: compilerRtl, compilerproc.}

View File

@@ -187,60 +187,35 @@ elif defined(nogc):
dest^ = src
include "system/cellsets"
elif appType == "lib":
{.warning: "gc in a library context may not work".}
when hostOS == "windows":
const nimrtl = "nimrtl.dll"
elif hostOS == "macosx":
const nimrtl = "nimrtl.dynlib"
else:
const nimrtl = "libnimrtl.so"
when not defined(includeGC):
# ordinary client; use the GC from nimrtl.dll:
proc initGC() {.cdecl, importc, dynlib: nimrtl.}
proc GC_disable() {.cdecl, importc, dynlib: nimrtl.}
proc GC_enable() {.cdecl, importc, dynlib: nimrtl.}
proc GC_fullCollect() {.cdecl, importc, dynlib: nimrtl.}
proc GC_setStrategy(strategy: TGC_Strategy) {.
cdecl, importc, dynlib: nimrtl.}
proc GC_enableMarkAndSweep() {.cdecl, importc, dynlib: nimrtl.}
proc GC_disableMarkAndSweep() {.cdecl, importc, dynlib: nimrtl.}
proc GC_getStatistics(): string {.cdecl, importc, dynlib: nimrtl.}
elif defined(useNimRtl):
proc initGC() = nil
proc newObj(typ: PNimType, size: int): pointer {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc newSeq(typ: PNimType, len: int): pointer {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc growObj(old: pointer, newsize: int): pointer {.
cdecl, importc, dynlib: nimrtl.}
proc setStackBottom(theStackBottom: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc nimGCref(p: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc nimGCunref(p: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.}
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.}
proc growObj(old: pointer, newsize: int): pointer {.rtl.}
# The write barrier is performance critical!
# XXX We should ensure that they are inlined here.
# Later implementations will do this.
proc setStackBottom(theStackBottom: pointer) {.compilerProc, inline.} =
# This happens before setStackBottom has been loaded by dlsym(), so
# we simply provide a dummy implemenation here for the code gen. No
# harm is done by this.
nil
proc unsureAsgnRef(dest: ppointer, src: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc asgnRef(dest: ppointer, src: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.
compilerproc, cdecl, importc, dynlib: nimrtl.}
else:
# include the GC and export it!
include "system/alloc"
include "system/cellsets"
assert(sizeof(TCell) == sizeof(TFreeCell))
include "system/gc"
proc nimGCref(p: pointer) {.compilerRtl.}
proc nimGCunref(p: pointer) {.compilerRtl.}
# The write barrier is performance critical!
# XXX We should ensure that they are inlined here.
# Later implementations will do this.
proc unsureAsgnRef(dest: ppointer, src: pointer) {.
compilerRtl.}
proc asgnRef(dest: ppointer, src: pointer) {.
compilerRtl.}
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.
compilerRtl.}
include "system/cellsets"
else:
include "system/alloc"
include "system/cellsets"

View File

@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -35,15 +35,15 @@ proc reprStrAux(result: var string, s: string) =
else: result.add(c)
add result, "\""
proc reprStr(s: string): string {.compilerproc.} =
proc reprStr(s: string): string {.compilerRtl.} =
result = ""
reprStrAux(result, s)
proc reprBool(x: bool): string {.compilerproc.} =
proc reprBool(x: bool): string {.compilerRtl.} =
if x: result = "true"
else: result = "false"
proc reprChar(x: char): string {.compilerproc.} =
proc reprChar(x: char): string {.compilerRtl.} =
result = "\'"
case x
of '"': add result, "\\\""
@@ -52,7 +52,7 @@ proc reprChar(x: char): string {.compilerproc.} =
else: add result, x
add result, "\'"
proc reprEnum(e: int, typ: PNimType): string {.compilerproc.} =
proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
if e <% typ.node.len: # BUGFIX
result = $typ.node.sons[e].name
else:
@@ -97,7 +97,7 @@ proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
inc(elemCounter)
add result, "}"
proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} =
proc reprSet(p: pointer, typ: PNimType): string {.compilerRtl.} =
result = ""
reprSetAux(result, p, typ)
@@ -108,122 +108,123 @@ type
recdepth: int # do not recurse endless
indent: int # indentation
proc initReprClosure(cl: var TReprClosure) =
Init(cl.marked)
cl.recdepth = -1 # default is to display everything!
cl.indent = 0
when not defined(useNimRtl):
proc initReprClosure(cl: var TReprClosure) =
Init(cl.marked)
cl.recdepth = -1 # default is to display everything!
cl.indent = 0
proc deinitReprClosure(cl: var TReprClosure) =
Deinit(cl.marked)
proc deinitReprClosure(cl: var TReprClosure) =
Deinit(cl.marked)
proc reprBreak(result: var string, cl: TReprClosure) =
add result, "\n"
for i in 0..cl.indent-1: add result, ' '
proc reprBreak(result: var string, cl: TReprClosure) =
add result, "\n"
for i in 0..cl.indent-1: add result, ' '
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure)
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure)
proc reprArray(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
add result, "["
var bs = typ.base.size
for i in 0..typ.size div bs - 1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
add result, "]"
proc reprArray(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
add result, "["
var bs = typ.base.size
for i in 0..typ.size div bs - 1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + i*bs), typ.base, cl)
add result, "]"
proc reprSequence(result: var string, p: pointer, typ: PNimType,
proc reprSequence(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if p == nil:
add result, "nil"
return
result.add(reprPointer(p) & "[")
var bs = typ.base.size
for i in 0..cast[PGenericSeq](p).len-1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
typ.Base, cl)
add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
cl: var TReprClosure) =
case n.kind
of nkNone: assert(false)
of nkSlot:
add result, $n.name
add result, " = "
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
of nkList:
for i in 0..n.len-1:
if i > 0: add result, ",\n"
reprRecordAux(result, p, n.sons[i], cl)
of nkCase:
var m = selectBranch(p, n)
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
if m != nil: reprRecordAux(result, p, m, cl)
proc reprRecord(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if p == nil:
add result, "nil"
return
result.add(reprPointer(p) & "[")
var bs = typ.base.size
for i in 0..cast[PGenericSeq](p).len-1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
typ.Base, cl)
add result, "]"
add result, "["
reprRecordAux(result, p, typ.node, cl)
add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
cl: var TReprClosure) =
case n.kind
of nkNone: assert(false)
of nkSlot:
add result, $n.name
add result, " = "
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
of nkList:
for i in 0..n.len-1:
if i > 0: add result, ",\n"
reprRecordAux(result, p, n.sons[i], cl)
of nkCase:
var m = selectBranch(p, n)
reprAux(result, cast[pointer](cast[TAddress](p) + n.offset), n.typ, cl)
if m != nil: reprRecordAux(result, p, m, cl)
proc reprRef(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
# we know that p is not nil here:
when defined(boehmGC) or defined(nogc):
var cell = cast[PCell](p)
else:
var cell = usrToCell(p)
add result, "ref " & reprPointer(p)
if cell notin cl.marked:
# only the address is shown:
incl(cl.marked, cell)
add result, " --> "
reprAux(result, p, typ.base, cl)
proc reprRecord(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
add result, "["
reprRecordAux(result, p, typ.node, cl)
add result, "]"
proc reprRef(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
# we know that p is not nil here:
when defined(boehmGC) or defined(nogc):
var cell = cast[PCell](p)
else:
var cell = usrToCell(p)
add result, "ref " & reprPointer(p)
if cell notin cl.marked:
# only the address is shown:
incl(cl.marked, cell)
add result, " --> "
reprAux(result, p, typ.base, cl)
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if cl.recdepth == 0:
add result, "..."
return
dec(cl.recdepth)
case typ.kind
of tySet: reprSetAux(result, p, typ)
of tyArray: reprArray(result, p, typ, cl)
of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
of tyObject:
var t = cast[ptr PNimType](p)^
reprRecord(result, p, t, cl)
of tyRef, tyPtr:
assert(p != nil)
if cast[ppointer](p)^ == nil: add result, "nil"
else: reprRef(result, cast[ppointer](p)^, typ, cl)
of tySequence:
reprSequence(result, cast[ppointer](p)^, typ, cl)
of tyInt: add result, $(cast[ptr int](p)^)
of tyInt8: add result, $int(cast[ptr Int8](p)^)
of tyInt16: add result, $int(cast[ptr Int16](p)^)
of tyInt32: add result, $int(cast[ptr Int32](p)^)
of tyInt64: add result, $(cast[ptr Int64](p)^)
of tyFloat: add result, $(cast[ptr float](p)^)
of tyFloat32: add result, $(cast[ptr float32](p)^)
of tyFloat64: add result, $(cast[ptr float64](p)^)
of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
of tyBool: add result, reprBool(cast[ptr bool](p)^)
of tyChar: add result, reprChar(cast[ptr char](p)^)
of tyString: reprStrAux(result, cast[ptr string](p)^)
of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
of tyRange: reprAux(result, p, typ.base, cl)
of tyProc, tyPointer:
if cast[ppointer](p)^ == nil: add result, "nil"
else: add result, reprPointer(cast[ppointer](p)^)
else:
add result, "(invalid data!)"
inc(cl.recdepth)
proc reprAux(result: var string, p: pointer, typ: PNimType,
cl: var TReprClosure) =
if cl.recdepth == 0:
add result, "..."
return
dec(cl.recdepth)
case typ.kind
of tySet: reprSetAux(result, p, typ)
of tyArray: reprArray(result, p, typ, cl)
of tyTuple, tyPureObject: reprRecord(result, p, typ, cl)
of tyObject:
var t = cast[ptr PNimType](p)^
reprRecord(result, p, t, cl)
of tyRef, tyPtr:
assert(p != nil)
if cast[ppointer](p)^ == nil: add result, "nil"
else: reprRef(result, cast[ppointer](p)^, typ, cl)
of tySequence:
reprSequence(result, cast[ppointer](p)^, typ, cl)
of tyInt: add result, $(cast[ptr int](p)^)
of tyInt8: add result, $int(cast[ptr Int8](p)^)
of tyInt16: add result, $int(cast[ptr Int16](p)^)
of tyInt32: add result, $int(cast[ptr Int32](p)^)
of tyInt64: add result, $(cast[ptr Int64](p)^)
of tyFloat: add result, $(cast[ptr float](p)^)
of tyFloat32: add result, $(cast[ptr float32](p)^)
of tyFloat64: add result, $(cast[ptr float64](p)^)
of tyEnum: add result, reprEnum(cast[ptr int](p)^, typ)
of tyBool: add result, reprBool(cast[ptr bool](p)^)
of tyChar: add result, reprChar(cast[ptr char](p)^)
of tyString: reprStrAux(result, cast[ptr string](p)^)
of tyCString: reprStrAux(result, $(cast[ptr cstring](p)^))
of tyRange: reprAux(result, p, typ.base, cl)
of tyProc, tyPointer:
if cast[ppointer](p)^ == nil: add result, "nil"
else: add result, reprPointer(cast[ppointer](p)^)
else:
add result, "(invalid data!)"
inc(cl.recdepth)
proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
compilerproc.} =
compilerRtl.} =
var
cl: TReprClosure
initReprClosure(cl)
@@ -235,15 +236,17 @@ proc reprOpenArray(p: pointer, length: int, elemtyp: PNimType): string {.
add result, "]"
deinitReprClosure(cl)
proc reprAny(p: pointer, typ: PNimType): string =
var
cl: TReprClosure
initReprClosure(cl)
result = ""
if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
reprAux(result, p, typ, cl)
else:
var p = p
reprAux(result, addr(p), typ, cl)
add result, "\n"
deinitReprClosure(cl)
when not defined(useNimRtl):
proc reprAny(p: pointer, typ: PNimType): string =
var
cl: TReprClosure
initReprClosure(cl)
result = ""
if typ.kind in {tyObject, tyPureObject, tyTuple, tyArray, tySet}:
reprAux(result, p, typ, cl)
else:
var p = p
reprAux(result, addr(p), typ, cl)
add result, "\n"
deinitReprClosure(cl)

View File

@@ -135,14 +135,6 @@ proc open(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
f = fdopen(filehandle, FormatOpen[mode])
result = f != nil
proc OpenFile(f: var TFile, filename: string,
mode: TFileMode = fmRead,
bufSize: int = -1): Bool =
result = open(f, filename, mode, bufSize)
proc openFile(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
result = open(f, filehandle, mode)
# C routine that is used here:
proc fread(buf: Pointer, size, n: int, f: TFile): int {.
importc: "fread", noDecl.}

View File

@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2009 Andreas Rumpf
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -88,7 +88,8 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.exportc.} =
proc copyStr(s: NimString, start: int): NimString {.exportc.} =
return copyStrLast(s, start, s.len-1)
proc addChar(s: NimString, c: char): NimString {.compilerProc.} =
proc addChar(s: NimString, c: char): NimString =
# is compilerproc!
result = s
if result.len >= result.space:
result.space = resize(result.space)
@@ -196,7 +197,7 @@ proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} =
inc(result.len)
proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
compilerProc.} =
compilerRtl.} =
when false:
# broken version:
result = seq
@@ -223,7 +224,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
result.len = newLen
# --------------- other string routines ----------------------------------
proc nimIntToStr(x: int): string {.compilerproc.} =
proc nimIntToStr(x: int): string {.compilerRtl.} =
result = newString(sizeof(x)*4)
var i = 0
var y = x
@@ -246,7 +247,7 @@ proc nimFloatToStr(x: float): string {.compilerproc.} =
c_sprintf(buf, "%#g", x)
return $buf
proc nimInt64ToStr(x: int64): string {.compilerproc.} =
proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
# we don't rely on C's runtime here as some C compiler's
# int64 support is weak
result = newString(sizeof(x)*4)