[nim-dev] Re: pragma emit question

  • From: terry <terry.chen@xxxxxxxxxx>
  • To: nim-dev@xxxxxxxxxxxxx
  • Date: Tue, 17 Nov 2015 22:53:40 +0000

Thanks for the help jboy / jlp765. After a couple more hours of messing with
libmill. I finally managed to get it to work.

Here is what my final main prog looks like:

```nimrod
import libmill

{.pragma: millcoro, codegenDecl: "coroutine $# $# $#".}

proc feeder(ch : chan, val: cint) : void {.millcoro.} =
while true:
chs(ch, val)
myield()

proc main(): void =
var ch1 = chmake(cint, 0)
var ch2 = chmake(cint, 0)
go(feeder(chdup(ch1), 111))
go(feeder(chdup(ch2), 222))
for i in 0..100:
choose:
var val {.nodecl.} : cint
mill_in(ch1, int, val):
echo "ch1, val = ", val
mill_in(ch2, int, val):
echo "ch2, val = ", val
myield()

chclose(ch1)
chclose(ch2)

main()
```

Here is my work-in-progress libmill.nim

```nimrod
import macros

{.passC: "-I/home/tchen2/.tools/include ".}
{.passL: "/home/tchen2/.tools/lib/libmill.a -lanl -lrt" .}

{.pragma: millcoro, codegenDecl: "coroutine $# $# $#".}

var FILENAMELINE {.nodecl, importc:"__FILE__ \":\" mill_string(__LINE__)" .}:
cstring
var static_count {.compiletime.} = 0

const
mill_header = "<libmill.h>"

type
size_t = int
chan* = pointer

proc newEmitPragma*(s: string): NimNode {.compileTime.} =
result = newNimNode(nnkPragma)
result.add(newColonExpr(newIdentNode("emit"), newStrLitNode(s)))

proc mill_chmake(sz : size_t, bufsz: size_t, created: cstring): chan
{. importc: "mill_chmake", header: mill_header, noconv .}
proc mill_chs(ch : chan, val: pointer, sz: size_t, current: cstring): void
{. importc: "mill_chs", header: mill_header, noconv .}
proc mill_chclose(ch : chan, current: cstring): void
{. importc: "mill_chclose", header: mill_header, noconv .}
proc mill_chdup*(ch : chan, created: cstring): chan
{. importc: "mill_chdup", header: mill_header, noconv .}
proc myield*(): void {. importc: "yield", header: mill_header, noconv .}

template chmake*(T: expr, bufsz: int): expr = mill_chmake(sizeof(T), bufsz,
FILENAMELINE)
template chclose*(ch: chan): expr = mill_chclose(ch, FILENAMELINE)
template chdup*(ch: chan): expr = mill_chdup(ch, FILENAMELINE)
template chs*[T](ch: chan, v: T): stmt =
var mill_val = v
mill_chs(ch, addr mill_val, sizeof(mill_val), FILENAMELINE)
template go*(fn: expr): stmt =
var mill_sp : bool
{.emit: """{
void* mill_sp = mill_go_prologue(__FILE__ ":" mill_string(__LINE__));
if(mill_sp) {
int mill_anchor[mill_unoptimisable1];
mill_unoptimisable2 = &mill_anchor;
char mill_filler[(char*)&mill_anchor - (char*)(mill_sp)];
mill_unoptimisable2 = &mill_filler;""".}
fn
{.emit: "mill_go_epilogue(); } } ".}

macro mill_in*(ch: expr, T: expr, name: expr, actions: stmt): stmt
{.immediate.} =
var ch = repr(ch)
var name = repr(name)
var T = repr(T)
var c = repr(static_count)
static_count += 1
result = newNimNode(nnkStmtList)
result.add(newEmitPragma("break; } goto mill_concat(mill_label, " & c & ");
}"))
result.add(newEmitPragma("char mill_concat(mill_clause, " & c &
")[MILL_CLAUSELEN];"))
result.add(newEmitPragma("mill_choose_in( &mill_concat(mill_clause, " & c &
")[0], (" & ch & "), sizeof(" & T & "), " & c & ");"))
result.add(newEmitPragma("if(0) { " & T & " " & name & ";"))
result.add(newEmitPragma("mill_concat(mill_label, " & c & "):"))
result.add(newEmitPragma("if(mill_idx == " & c & ") { " & name & " = *(" & T
& "*)mill_choose_val(sizeof(" & T & "));"))
result.add(newEmitPragma("goto mill_concat(mill_dummylabel, " & c & ");
mill_concat(mill_dummylabel, " & c & "):"))
result.add(actions)

macro choose*(actions: stmt): stmt {.immediate.} =
result = newNimNode(nnkStmtList)
result.add(newEmitPragma("""{ mill_choose_init(__FILE__ ":"
mill_string(__LINE__)); int mill_idx = -2; while(1) { if(mill_idx != -2) {
if(0) {"""))
result.add(actions)
result.add(newEmitPragma("break; } } mill_idx = mill_choose_wait(); } }"))
```

Cheers to the awesome Nim community


Other related posts: