next steps for FFI at compile time

This commit is contained in:
Araq 2013-01-02 01:17:53 +01:00
commit 88a441ea8e
6 changed files with 215 additions and 182 deletions

View file

@ -279,6 +279,13 @@ proc unpackArray(x: pointer, typ: PType, n: PNode): PNode =
for i in 0 .. < result.len: for i in 0 .. < result.len:
result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i]) result.sons[i] = unpack(x +! i * baseSize, typ.sons[1], result.sons[i])
proc canonNodeKind(k: TNodeKind): TNodeKind =
case k
of nkCharLit..nkUInt64Lit: result = nkIntLit
of nkFloatLit..nkFloat128Lit: result = nkFloatLit
of nkStrLit..nkTripleStrLit: result = nkStrLit
else: result = k
proc unpack(x: pointer, typ: PType, n: PNode): PNode = proc unpack(x: pointer, typ: PType, n: PNode): PNode =
template aw(k, v, field: expr) {.immediate, dirty.} = template aw(k, v, field: expr) {.immediate, dirty.} =
if n.isNil: if n.isNil:
@ -287,7 +294,8 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
else: else:
# check we have the right field: # check we have the right field:
result = n result = n
if result.kind != k: if result.kind.canonNodeKind != k.canonNodeKind:
echo "expected ", k, " but got ", result.kind
GlobalError(n.info, "cannot map value from FFI") GlobalError(n.info, "cannot map value from FFI")
result.field = v result.field = v
@ -309,15 +317,15 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
of tyBool: awi(nkIntLit, rd(bool, x).ord) of tyBool: awi(nkIntLit, rd(bool, x).ord)
of tyChar: awi(nkIntLit, rd(char, x).ord) of tyChar: awi(nkIntLit, rd(char, x).ord)
of tyInt: awi(nkIntLit, rd(int, x)) of tyInt: awi(nkIntLit, rd(int, x))
of tyInt8: awi(nkIntLit, rd(int8, x)) of tyInt8: awi(nkInt8Lit, rd(int8, x))
of tyInt16: awi(nkIntLit, rd(int16, x)) of tyInt16: awi(nkInt16Lit, rd(int16, x))
of tyInt32: awi(nkIntLit, rd(int32, x)) of tyInt32: awi(nkInt32Lit, rd(int32, x))
of tyInt64: awi(nkIntLit, rd(int64, x)) of tyInt64: awi(nkInt64Lit, rd(int64, x))
of tyUInt: awi(nkIntLit, rd(uint, x).biggestInt) of tyUInt: awi(nkUIntLit, rd(uint, x).biggestInt)
of tyUInt8: awi(nkIntLit, rd(uint8, x).biggestInt) of tyUInt8: awi(nkUInt8Lit, rd(uint8, x).biggestInt)
of tyUInt16: awi(nkIntLit, rd(uint16, x).biggestInt) of tyUInt16: awi(nkUInt16Lit, rd(uint16, x).biggestInt)
of tyUInt32: awi(nkIntLit, rd(uint32, x).biggestInt) of tyUInt32: awi(nkUInt32Lit, rd(uint32, x).biggestInt)
of tyUInt64: awi(nkIntLit, rd(uint64, x).biggestInt) of tyUInt64: awi(nkUInt64Lit, rd(uint64, x).biggestInt)
of tyEnum: of tyEnum:
case typ.getSize case typ.getSize
of 1: awi(nkIntLit, rd(uint8, x).biggestInt) of 1: awi(nkIntLit, rd(uint8, x).biggestInt)
@ -327,8 +335,8 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
else: else:
GlobalError(n.info, "cannot map value from FFI (tyEnum, tySet)") GlobalError(n.info, "cannot map value from FFI (tyEnum, tySet)")
of tyFloat: awf(nkFloatLit, rd(float, x)) of tyFloat: awf(nkFloatLit, rd(float, x))
of tyFloat32: awf(nkFloatLit, rd(float32, x)) of tyFloat32: awf(nkFloat32Lit, rd(float32, x))
of tyFloat64: awf(nkFloatLit, rd(float64, x)) of tyFloat64: awf(nkFloat64Lit, rd(float64, x))
of tyPointer, tyProc: of tyPointer, tyProc:
let p = rd(pointer, x) let p = rd(pointer, x)
if p.isNil: if p.isNil:
@ -339,7 +347,7 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
let p = rd(pointer, x) let p = rd(pointer, x)
if p.isNil: if p.isNil:
setNil() setNil()
elif n != nil and n.kind == nkPtrLit: elif n == nil or n.kind == nkPtrLit:
awi(nkPtrLit, cast[TAddress](p)) awi(nkPtrLit, cast[TAddress](p))
elif n != nil and n.len == 1: elif n != nil and n.len == 1:
n.sons[0] = unpack(rd(pointer, x), typ.sons[0], n.sons[0]) n.sons[0] = unpack(rd(pointer, x), typ.sons[0], n.sons[0])
@ -363,6 +371,14 @@ proc unpack(x: pointer, typ: PType, n: PNode): PNode =
# XXX what to do with 'array' here? # XXX what to do with 'array' here?
GlobalError(n.info, "cannot map value from FFI " & typeToString(typ)) GlobalError(n.info, "cannot map value from FFI " & typeToString(typ))
proc fficast*(x: PNode, destTyp: PType): PNode =
# we play safe here and allocate the max possible size:
let allocSize = max(packSize(x, x.typ), packSize(x, destTyp))
var a = alloc0(allocSize)
pack(x, x.typ, a)
result = unpack(a, destTyp, nil)
dealloc a
proc callForeignFunction*(call: PNode): PNode = proc callForeignFunction*(call: PNode): PNode =
InternalAssert call.sons[0].kind == nkPtrLit InternalAssert call.sons[0].kind == nkPtrLit

View file

@ -77,6 +77,7 @@ proc newEvalContext*(module: PSym, filename: string,
new(result) new(result)
result.module = module result.module = module
result.mode = mode result.mode = mode
result.features = {allowFFI}
initIdNodeTable(result.globals) initIdNodeTable(result.globals)
proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} = proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} =
@ -351,7 +352,7 @@ proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
result = copyTree(result) result = copyTree(result)
else: else:
when hasFFI: when hasFFI:
if sfImportc in s.flags: if sfImportc in s.flags and allowFFI in c.features:
result = importcSymbol(s) result = importcSymbol(s)
IdNodeTablePut(c.globals, s, result) IdNodeTablePut(c.globals, s, result)
return result return result
@ -398,7 +399,7 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
if n.typ != nil: d.params[0] = getNullValue(n.typ, n.info) if n.typ != nil: d.params[0] = getNullValue(n.typ, n.info)
when hasFFI: when hasFFI:
if sfImportc in prc.sym.flags: if sfImportc in prc.sym.flags and allowFFI in c.features:
var newCall = newNodeI(nkCall, n.info, n.len) var newCall = newNodeI(nkCall, n.info, n.len)
newCall.sons[0] = evalGlobalVar(c, prc.sym, {}) newCall.sons[0] = evalGlobalVar(c, prc.sym, {})
for i in 1 .. <n.len: for i in 1 .. <n.len:
@ -549,7 +550,8 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
of skConst: result = s.ast of skConst: result = s.ast
of skEnumField: result = newIntNodeT(s.position, n) of skEnumField: result = newIntNodeT(s.position, n)
else: result = nil else: result = nil
const mask = when hasFFI: {sfForward} else: {sfImportc, sfForward} let mask = if hasFFI and allowFFI in c.features: {sfForward}
else: {sfImportc, sfForward}
if result == nil or mask * s.flags != {}: if result == nil or mask * s.flags != {}:
result = raiseCannotEval(c, n.info) result = raiseCannotEval(c, n.info)
@ -650,9 +652,13 @@ proc evalConv(c: PEvalContext, n: PNode): PNode =
proc evalCast(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = proc evalCast(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
if allowCast in c.features: if allowCast in c.features:
# XXX we need better checking here and the new pack/unpack stuff should when hasFFI:
# be useful for some casts too: result = evalAux(c, n.sons[1], {efLValue})
result = evalConv(c, n) if isSpecial(result): return
InternalAssert result.typ != nil
result = fficast(result, n.typ)
else:
result = evalConv(c, n)
else: else:
result = raiseCannotEval(c, n.info) result = raiseCannotEval(c, n.info)
@ -1429,7 +1435,7 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
if sonsLen(result) >= 1: if sonsLen(result) >= 1:
stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ)) stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ))
else: else:
stackTrace(c, n, errCannotInterpretNodeX, renderTree(n)) stackTrace(c, result, errCannotInterpretNodeX, renderTree(n))
proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode = proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode =
var p = newEvalContext(module, "", mode) var p = newEvalContext(module, "", mode)
@ -1474,6 +1480,7 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
proc myOpen(module: PSym, filename: string): PPassContext = proc myOpen(module: PSym, filename: string): PPassContext =
var c = newEvalContext(module, filename, emRepl) var c = newEvalContext(module, filename, emRepl)
c.features = {allowCast, allowFFI, allowInfiniteLoops}
pushStackFrame(c, newStackFrame()) pushStackFrame(c, newStackFrame())
result = c result = c

View file

@ -153,7 +153,6 @@ proc CommandCompileToEcmaScript =
proc CommandInteractive = proc CommandInteractive =
msgs.gErrorMax = high(int) # do not stop after first error msgs.gErrorMax = high(int) # do not stop after first error
incl(gGlobalOptions, optSafeCode)
#setTarget(osNimrodVM, cpuNimrodVM) #setTarget(osNimrodVM, cpuNimrodVM)
initDefines() initDefines()
DefineSymbol("nimrodvm") DefineSymbol("nimrodvm")

View file

@ -1547,40 +1547,41 @@ when false:
# ----------------- GC interface --------------------------------------------- # ----------------- GC interface ---------------------------------------------
proc GC_disable*() {.rtl, inl.} when not defined(nimrodVM):
## disables the GC. If called n-times, n calls to `GC_enable` are needed to proc GC_disable*() {.rtl, inl.}
## reactivate the GC. Note that in most circumstances one should only disable ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
## the mark and sweep phase with `GC_disableMarkAndSweep`. ## reactivate the GC. Note that in most circumstances one should only disable
## the mark and sweep phase with `GC_disableMarkAndSweep`.
proc GC_enable*() {.rtl, inl.} proc GC_enable*() {.rtl, inl.}
## enables the GC again. ## enables the GC again.
proc GC_fullCollect*() {.rtl.} proc GC_fullCollect*() {.rtl.}
## forces a full garbage collection pass. ## forces a full garbage collection pass.
## Ordinary code does not need to call this (and should not). ## Ordinary code does not need to call this (and should not).
type type
TGC_Strategy* = enum ## the strategy the GC should use for the application TGC_Strategy* = enum ## the strategy the GC should use for the application
gcThroughput, ## optimize for throughput gcThroughput, ## optimize for throughput
gcResponsiveness, ## optimize for responsiveness (default) gcResponsiveness, ## optimize for responsiveness (default)
gcOptimizeTime, ## optimize for speed gcOptimizeTime, ## optimize for speed
gcOptimizeSpace ## optimize for memory footprint gcOptimizeSpace ## optimize for memory footprint
proc GC_setStrategy*(strategy: TGC_Strategy) {.rtl, deprecated.} proc GC_setStrategy*(strategy: TGC_Strategy) {.rtl, deprecated.}
## tells the GC the desired strategy for the application. ## tells the GC the desired strategy for the application.
## **Deprecated** since version 0.8.14. This has always been a nop. ## **Deprecated** since version 0.8.14. This has always been a nop.
proc GC_enableMarkAndSweep*() {.rtl.} proc GC_enableMarkAndSweep*() {.rtl.}
proc GC_disableMarkAndSweep*() {.rtl.} proc GC_disableMarkAndSweep*() {.rtl.}
## the current implementation uses a reference counting garbage collector ## the current implementation uses a reference counting garbage collector
## with a seldomly run mark and sweep phase to free cycles. The mark and ## 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 ## 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 ## does not create cycles. Thus the mark and sweep phase can be deactivated
## and activated separately from the rest of the GC. ## and activated separately from the rest of the GC.
proc GC_getStatistics*(): string {.rtl.} proc GC_getStatistics*(): string {.rtl.}
## returns an informative string about the GC's activity. This may be useful ## returns an informative string about the GC's activity. This may be useful
## for tweaking. ## for tweaking.
proc GC_ref*[T](x: ref T) {.magic: "GCref".} proc GC_ref*[T](x: ref T) {.magic: "GCref".}
proc GC_ref*[T](x: seq[T]) {.magic: "GCref".} proc GC_ref*[T](x: seq[T]) {.magic: "GCref".}
@ -1707,28 +1708,29 @@ 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.
when not defined(EcmaScript) and not defined(NimrodVM): when not defined(EcmaScript): #and not defined(NimrodVM):
{.push stack_trace: off, profiler:off.} {.push stack_trace: off, profiler:off.}
proc initGC() when not defined(NimrodVM):
when not defined(boehmgc) and not defined(useMalloc): proc initGC()
proc initAllocator() {.inline.} when not defined(boehmgc) and not defined(useMalloc):
proc initAllocator() {.inline.}
proc initStackBottom() {.inline, compilerproc.} = proc initStackBottom() {.inline, compilerproc.} =
# WARNING: This is very fragile! An array size of 8 does not work on my # WARNING: This is very fragile! An array size of 8 does not work on my
# Linux 64bit system. -- That's because the stack direction is the other # Linux 64bit system. -- That's because the stack direction is the other
# way round. # way round.
when defined(setStackBottom): when defined(setStackBottom):
var locals {.volatile.}: pointer var locals {.volatile.}: pointer
locals = addr(locals) locals = addr(locals)
setStackBottom(locals) setStackBottom(locals)
var var
strDesc: TNimType strDesc: TNimType
strDesc.size = sizeof(string) strDesc.size = sizeof(string)
strDesc.kind = tyString strDesc.kind = tyString
strDesc.flags = {ntfAcyclic} strDesc.flags = {ntfAcyclic}
include "system/ansi_c" include "system/ansi_c"
@ -1736,22 +1738,23 @@ when not defined(EcmaScript) and not defined(NimrodVM):
result = int(c_strcmp(x, y)) result = int(c_strcmp(x, y))
const pccHack = if defined(pcc): "_" else: "" # Hack for PCC const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
when defined(windows): when not defined(NimrodVM):
# work-around C's sucking abstraction: when defined(windows):
# BUGFIX: stdin and stdout should be binary files! # work-around C's sucking abstraction:
proc setmode(handle, mode: int) {.importc: pccHack & "setmode", # BUGFIX: stdin and stdout should be binary files!
header: "<io.h>".} proc setmode(handle, mode: int) {.importc: pccHack & "setmode",
proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno", header: "<io.h>".}
header: "<fcntl.h>".} proc fileno(f: C_TextFileStar): int {.importc: pccHack & "fileno",
var header: "<fcntl.h>".}
O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int var
O_BINARY {.importc: pccHack & "O_BINARY", nodecl.}: int
# we use binary mode in Windows: # we use binary mode in Windows:
setmode(fileno(c_stdin), O_BINARY) setmode(fileno(c_stdin), O_BINARY)
setmode(fileno(c_stdout), O_BINARY) setmode(fileno(c_stdout), O_BINARY)
when defined(endb): when defined(endb):
proc endbStep() proc endbStep()
# ----------------- IO Part ------------------------------------------------ # ----------------- IO Part ------------------------------------------------
type type
@ -1957,13 +1960,14 @@ when not defined(EcmaScript) and not defined(NimrodVM):
inc(i) inc(i)
dealloc(a) dealloc(a)
proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable.} when not defined(NimrodVM):
## atomic increment of `memLoc`. Returns the value after the operation. proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable.}
## atomic increment of `memLoc`. Returns the value after the operation.
proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, discardable.} proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, discardable.}
## atomic decrement of `memLoc`. Returns the value after the operation. ## atomic decrement of `memLoc`. Returns the value after the operation.
include "system/atomics" include "system/atomics"
type type
PSafePoint = ptr TSafePoint PSafePoint = ptr TSafePoint
@ -1979,71 +1983,76 @@ when not defined(EcmaScript) and not defined(NimrodVM):
when hasThreadSupport: when hasThreadSupport:
include "system/syslocks" include "system/syslocks"
include "system/threads" include "system/threads"
elif not defined(nogc): elif not defined(nogc) and not defined(NimrodVM):
when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom() when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
initGC() initGC()
proc setControlCHook*(hook: proc () {.noconv.}) when not defined(NimrodVM):
## allows you to override the behaviour of your application when CTRL+C proc setControlCHook*(hook: proc () {.noconv.})
## is pressed. Only one such hook is supported. ## allows you to override the behaviour of your application when CTRL+C
## is pressed. Only one such hook is supported.
proc writeStackTrace*() {.tags: [FWriteIO].} proc writeStackTrace*() {.tags: [FWriteIO].}
## writes the current stack trace to ``stderr``. This is only works ## writes the current stack trace to ``stderr``. This is only works
## for debug builds. ## for debug builds.
when hostOS != "standalone": when hostOS != "standalone":
proc getStackTrace*(): string proc getStackTrace*(): string
## gets the current stack trace. This only works for debug builds. ## gets the current stack trace. This only works for debug builds.
proc getStackTrace*(e: ref E_Base): string proc getStackTrace*(e: ref E_Base): string
## gets the stack trace associated with `e`, which is the stack that ## gets the stack trace associated with `e`, which is the stack that
## lead to the ``raise`` statement. This only works for debug builds. ## lead to the ``raise`` statement. This only works for debug builds.
{.push stack_trace: off, profiler:off.} {.push stack_trace: off, profiler:off.}
when hostOS == "standalone": when hostOS == "standalone":
include "system/embedded" include "system/embedded"
else:
include "system/excpt"
# we cannot compile this with stack tracing on
# as it would recurse endlessly!
include "system/arithm"
{.pop.} # stack trace
{.pop.} # stack trace
when hostOS != "standalone": include "system/dyncalls"
include "system/sets"
const
GenericSeqSize = (2 * sizeof(int))
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
var d: int
var a = cast[TAddress](aa)
case n.typ.size
of 1: d = ze(cast[ptr int8](a +% n.offset)[])
of 2: d = ze(cast[ptr int16](a +% n.offset)[])
of 4: d = int(cast[ptr int32](a +% n.offset)[])
else: sysAssert(false, "getDiscriminant: invalid n.typ.size")
return d
proc selectBranch(aa: Pointer, n: ptr TNimNode): ptr TNimNode =
var discr = getDiscriminant(aa, n)
if discr <% n.len:
result = n.sons[discr]
if result == nil: result = n.sons[n.len]
# n.sons[n.len] contains the ``else`` part (but may be nil)
else: else:
result = n.sons[n.len] include "system/excpt"
include "system/mmdisp" # we cannot compile this with stack tracing on
{.push stack_trace: off, profiler:off.} # as it would recurse endlessly!
when hostOS != "standalone": include "system/sysstr" include "system/arithm"
{.pop.} {.pop.} # stack trace
{.pop.} # stack trace
include "system/sysio" when hostOS != "standalone" and not defined(NimrodVM):
when hasThreadSupport: include "system/dyncalls"
include "system/channels" when not defined(NimrodVM):
include "system/sets"
const
GenericSeqSize = (2 * sizeof(int))
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
var d: int
var a = cast[TAddress](aa)
case n.typ.size
of 1: d = ze(cast[ptr int8](a +% n.offset)[])
of 2: d = ze(cast[ptr int16](a +% n.offset)[])
of 4: d = int(cast[ptr int32](a +% n.offset)[])
else: sysAssert(false, "getDiscriminant: invalid n.typ.size")
return d
proc selectBranch(aa: Pointer, n: ptr TNimNode): ptr TNimNode =
var discr = getDiscriminant(aa, n)
if discr <% n.len:
result = n.sons[discr]
if result == nil: result = n.sons[n.len]
# n.sons[n.len] contains the ``else`` part (but may be nil)
else:
result = n.sons[n.len]
include "system/mmdisp"
{.push stack_trace: off, profiler:off.}
when hostOS != "standalone": include "system/sysstr"
{.pop.}
include "system/sysio"
when hasThreadSupport:
include "system/channels"
else:
include "system/sysio"
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`.
@ -2058,7 +2067,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
var res = TaintedString(newStringOfCap(80)) var res = TaintedString(newStringOfCap(80))
while f.readLine(res): yield TaintedString(res) while f.readLine(res): yield TaintedString(res)
when hostOS != "standalone": when hostOS != "standalone" and not defined(NimrodVM):
include "system/assign" include "system/assign"
include "system/repr" include "system/repr"
@ -2083,42 +2092,43 @@ when not defined(EcmaScript) and not defined(NimrodVM):
excHandler.raiseAction = action excHandler.raiseAction = action
{.push stack_trace: off, profiler:off.} {.push stack_trace: off, profiler:off.}
when defined(endb): when defined(endb) and not defined(NimrodVM):
include "system/debugger" include "system/debugger"
when defined(profiler) or defined(memProfiler): when defined(profiler) or defined(memProfiler):
include "system/profiler" include "system/profiler"
{.pop.} # stacktrace {.pop.} # stacktrace
proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.} when not defined(NimrodVM):
## can be used to mark a condition to be likely. This is a hint for the proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
## optimizer. ## can be used to mark a condition to be likely. This is a hint for the
## optimizer.
proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.} proc unlikely*(val: bool): bool {.importc: "unlikely", nodecl, nosideeffect.}
## can be used to mark a condition to be unlikely. This is a hint for the ## can be used to mark a condition to be unlikely. This is a hint for the
## optimizer. ## optimizer.
proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} = proc rawProc*[T: proc](x: T): pointer {.noSideEffect, inline.} =
## retrieves the raw proc pointer of the closure `x`. This is ## retrieves the raw proc pointer of the closure `x`. This is
## useful for interfacing closures with C. ## useful for interfacing closures with C.
{.emit: """ {.emit: """
`result` = `x`.ClPrc; `result` = `x`.ClPrc;
""".} """.}
proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} = proc rawEnv*[T: proc](x: T): pointer {.noSideEffect, inline.} =
## retrieves the raw environment pointer of the closure `x`. This is ## retrieves the raw environment pointer of the closure `x`. This is
## useful for interfacing closures with C. ## useful for interfacing closures with C.
{.emit: """ {.emit: """
`result` = `x`.ClEnv; `result` = `x`.ClEnv;
""".} """.}
proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} = proc finished*[T: proc](x: T): bool {.noSideEffect, inline.} =
## can be used to determine if a first class iterator has finished. ## can be used to determine if a first class iterator has finished.
{.emit: """ {.emit: """
`result` = *((NI*) `x`.ClEnv) < 0; `result` = *((NI*) `x`.ClEnv) < 0;
""".} """.}
elif defined(ecmaScript) or defined(NimrodVM): elif defined(ecmaScript):
# Stubs: # Stubs:
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = nil proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = nil

View file

@ -139,7 +139,7 @@ elif defined(macosx):
ImageLibName = "libSDL_image-1.2.0.dylib" ImageLibName = "libSDL_image-1.2.0.dylib"
else: else:
const const
ImageLibName = "libSDL_image.so" ImageLibName = "libSDL_image(.so|-1.2.so.0)"
const const
IMAGE_MAJOR_VERSION* = 1 IMAGE_MAJOR_VERSION* = 1
IMAGE_MINOR_VERSION* = 2 IMAGE_MINOR_VERSION* = 2

View file

@ -27,6 +27,7 @@ version 0.9.X
- optimize genericAssign in the code generator - optimize genericAssign in the code generator
- better support for macros that rewrite procs - better support for macros that rewrite procs
- macros need access to types and symbols (partially implemented) - macros need access to types and symbols (partially implemented)
- result = result shr 8 for the "system()" wrapper
- rethink the syntax/grammar: - rethink the syntax/grammar:
* parser is not strict enough with newlines * parser is not strict enough with newlines