better C++ support wrt 'this'
This commit is contained in:
parent
4a9647d4db
commit
a2b7e6c392
2 changed files with 166 additions and 20 deletions
|
|
@ -217,7 +217,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
else:
|
else:
|
||||||
genCallPattern()
|
genCallPattern()
|
||||||
|
|
||||||
proc genCppArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
|
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
|
||||||
if i < sonsLen(typ):
|
if i < sonsLen(typ):
|
||||||
# 'var T' is 'T&' in C++. This means we ignore the request of
|
# 'var T' is 'T&' in C++. This means we ignore the request of
|
||||||
# any nkHiddenAddr when it's a 'var T'.
|
# any nkHiddenAddr when it's a 'var T'.
|
||||||
|
|
@ -225,20 +225,87 @@ proc genCppArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
|
||||||
if typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr:
|
if typ.sons[i].kind == tyVar and ri.sons[i].kind == nkHiddenAddr:
|
||||||
result = genArgNoParam(p, ri.sons[i][0])
|
result = genArgNoParam(p, ri.sons[i][0])
|
||||||
else:
|
else:
|
||||||
result = genArg(p, ri.sons[i], typ.n.sons[i].sym)
|
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
|
||||||
else:
|
else:
|
||||||
result = genArgNoParam(p, ri.sons[i])
|
result = genArgNoParam(p, ri.sons[i])
|
||||||
|
|
||||||
|
discard """
|
||||||
|
Dot call syntax in C++
|
||||||
|
======================
|
||||||
|
|
||||||
|
so c2nim translates 'this' sometimes to 'T' and sometimes to 'var T'
|
||||||
|
both of which are wrong, but often more convenient to use.
|
||||||
|
For manual wrappers it can also be 'ptr T'
|
||||||
|
|
||||||
|
Fortunately we know which parameter is the 'this' parameter and so can fix this
|
||||||
|
mess in the codegen.
|
||||||
|
now ... if the *argument* is a 'ptr' the codegen shall emit -> and otherwise .
|
||||||
|
but this only depends on the argument and not on how the 'this' was declared
|
||||||
|
however how the 'this' was declared affects whether we end up with
|
||||||
|
wrong 'addr' and '[]' ops...
|
||||||
|
|
||||||
|
Since I'm tired I'll enumerate all the cases here:
|
||||||
|
|
||||||
|
var
|
||||||
|
x: ptr T
|
||||||
|
y: T
|
||||||
|
|
||||||
|
proc t(x: T)
|
||||||
|
x[].t() --> (*x).t() is correct.
|
||||||
|
y.t() --> y.t() is correct
|
||||||
|
|
||||||
|
proc u(x: ptr T)
|
||||||
|
x.u() --> needs to become x->u()
|
||||||
|
(addr y).u() --> needs to become y.u()
|
||||||
|
|
||||||
|
proc v(x: var T)
|
||||||
|
--> first skip the implicit 'nkAddr' node
|
||||||
|
x[].v() --> (*x).v() is correct, but might have been eliminated due
|
||||||
|
to the nkAddr node! So for this case we need to generate '->'
|
||||||
|
y.v() --> y.v() is correct
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): PRope =
|
||||||
|
# for better or worse c2nim translates the 'this' argument to a 'var T'.
|
||||||
|
# However manual wrappers may also use 'ptr T'. In any case we support both
|
||||||
|
# for convenience.
|
||||||
|
internalAssert i < sonsLen(typ)
|
||||||
|
assert(typ.n.sons[i].kind == nkSym)
|
||||||
|
# if the parameter is lying (tyVar) and thus we required an additional deref,
|
||||||
|
# skip the deref:
|
||||||
|
if typ.sons[i].kind == tyVar:
|
||||||
|
let x = if ri[i].kind == nkHiddenAddr: ri[i][0] else: ri[i]
|
||||||
|
if x.kind in {nkHiddenDeref, nkDerefExpr}:
|
||||||
|
result = genArgNoParam(p, x[0])
|
||||||
|
result.app("->")
|
||||||
|
elif x.typ.kind in {tyVar, tyPtr}:
|
||||||
|
result = genArgNoParam(p, x)
|
||||||
|
result.app("->")
|
||||||
|
else:
|
||||||
|
result = genArgNoParam(p, x)
|
||||||
|
result.app(".")
|
||||||
|
elif typ.sons[i].kind == tyPtr:
|
||||||
|
if ri.sons[i].kind in {nkAddr, nkHiddenAddr}:
|
||||||
|
result = genArgNoParam(p, ri.sons[i][0])
|
||||||
|
result.app(".")
|
||||||
|
else:
|
||||||
|
result = genArgNoParam(p, ri.sons[i])
|
||||||
|
result.app("->")
|
||||||
|
else:
|
||||||
|
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
|
||||||
|
result.app(".")
|
||||||
|
|
||||||
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
||||||
var i = 0
|
var i = 0
|
||||||
var j = 1
|
var j = 1
|
||||||
while i < pat.len:
|
while i < pat.len:
|
||||||
case pat[i]
|
case pat[i]
|
||||||
of '@':
|
of '@':
|
||||||
result.app genCppArg(p, ri, j, typ)
|
result.app genOtherArg(p, ri, j, typ)
|
||||||
for k in j+1 .. < ri.len:
|
for k in j+1 .. < ri.len:
|
||||||
result.app(~", ")
|
result.app(~", ")
|
||||||
result.app genCppArg(p, ri, k, typ)
|
result.app genOtherArg(p, ri, k, typ)
|
||||||
inc i
|
inc i
|
||||||
of '#':
|
of '#':
|
||||||
if pat[i+1] in {'+', '@'}:
|
if pat[i+1] in {'+', '@'}:
|
||||||
|
|
@ -247,22 +314,21 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
||||||
let typ = skipTypes(ri.sons[0].typ, abstractInst)
|
let typ = skipTypes(ri.sons[0].typ, abstractInst)
|
||||||
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
|
if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
|
||||||
result.app(~"(")
|
result.app(~"(")
|
||||||
result.app genCppArg(p, ri, 1, typ)
|
result.app genOtherArg(p, ri, 1, typ)
|
||||||
for k in j+1 .. < ri.len:
|
for k in j+1 .. < ri.len:
|
||||||
result.app(~", ")
|
result.app(~", ")
|
||||||
result.app genCppArg(p, ri, k, typ)
|
result.app genOtherArg(p, ri, k, typ)
|
||||||
result.app(~")")
|
result.app(~")")
|
||||||
else:
|
else:
|
||||||
localError(ri.info, "call expression expected for C++ pattern")
|
localError(ri.info, "call expression expected for C++ pattern")
|
||||||
inc i
|
inc i
|
||||||
else:
|
elif pat[i+1] == '.':
|
||||||
result.app genCppArg(p, ri, j, typ)
|
result.app genThisArg(p, ri, j, typ)
|
||||||
if pat[i+1] == '.':
|
|
||||||
let param = typ.n.sons[j].sym
|
|
||||||
if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: result.app(~"->")
|
|
||||||
else: result.app(~".")
|
|
||||||
inc i
|
inc i
|
||||||
|
else:
|
||||||
|
result.app genOtherArg(p, ri, j, typ)
|
||||||
inc j
|
inc j
|
||||||
|
inc i
|
||||||
of '\'':
|
of '\'':
|
||||||
inc i
|
inc i
|
||||||
let stars = i
|
let stars = i
|
||||||
|
|
@ -271,12 +337,18 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): PRope =
|
||||||
let j = pat[i].ord - '0'.ord
|
let j = pat[i].ord - '0'.ord
|
||||||
var t = typ.sons[j]
|
var t = typ.sons[j]
|
||||||
for k in 1..i-stars:
|
for k in 1..i-stars:
|
||||||
if t != nil and t.len > 0: t = t.elemType
|
if t != nil and t.len > 0:
|
||||||
|
t = if t.kind == tyGenericInst: t.sons[1] else: t.elemType
|
||||||
if t == nil: result.app(~"void")
|
if t == nil: result.app(~"void")
|
||||||
else: result.app(getTypeDesc(p.module, t))
|
else: result.app(getTypeDesc(p.module, t))
|
||||||
else:
|
|
||||||
result.app(toRope($pat[i]))
|
|
||||||
inc i
|
inc i
|
||||||
|
else:
|
||||||
|
let start = i
|
||||||
|
while i < pat.len:
|
||||||
|
if pat[i] notin {'@', '#', '\''}: inc(i)
|
||||||
|
else: break
|
||||||
|
if i - 1 >= start:
|
||||||
|
app(result, substr(pat, start, i - 1))
|
||||||
|
|
||||||
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
var op, a: TLoc
|
var op, a: TLoc
|
||||||
|
|
@ -305,16 +377,14 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||||
line(p, cpsStmts, pl)
|
line(p, cpsStmts, pl)
|
||||||
else:
|
else:
|
||||||
var pl: PRope = nil
|
var pl: PRope = nil
|
||||||
var param = typ.n.sons[1].sym
|
#var param = typ.n.sons[1].sym
|
||||||
app(pl, genCppArg(p, ri, 1, typ))
|
app(pl, genThisArg(p, ri, 1, typ))
|
||||||
if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, ~"->")
|
|
||||||
else: app(pl, ~".")
|
|
||||||
app(pl, op.r)
|
app(pl, op.r)
|
||||||
var params: PRope
|
var params: PRope
|
||||||
for i in countup(2, length - 1):
|
for i in countup(2, length - 1):
|
||||||
if params != nil: params.app(~", ")
|
if params != nil: params.app(~", ")
|
||||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||||
app(params, genCppArg(p, ri, i, typ))
|
app(params, genOtherArg(p, ri, i, typ))
|
||||||
fixupCall(p, le, ri, d, pl, params)
|
fixupCall(p, le, ri, d, pl, params)
|
||||||
|
|
||||||
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
|
||||||
|
|
|
||||||
76
tests/iter/tscheduler.nim
Normal file
76
tests/iter/tscheduler.nim
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
discard """
|
||||||
|
output: '''a1 5
|
||||||
|
a2 10
|
||||||
|
a1 3
|
||||||
|
a1 1
|
||||||
|
a2 8
|
||||||
|
a2 6
|
||||||
|
a2 4
|
||||||
|
a2 2'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os, strutils, times, algorithm
|
||||||
|
|
||||||
|
|
||||||
|
type TaskFn = iterator (): float
|
||||||
|
|
||||||
|
type Task = object
|
||||||
|
coro: TaskFn
|
||||||
|
next_run: float
|
||||||
|
|
||||||
|
|
||||||
|
type Scheduler = object
|
||||||
|
tasks: seq[Task]
|
||||||
|
|
||||||
|
|
||||||
|
proc newScheduler(): Scheduler =
|
||||||
|
var s = Scheduler()
|
||||||
|
s.tasks = @[]
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
proc start(this: var Scheduler, task: TaskFn) =
|
||||||
|
var t = Task()
|
||||||
|
t.coro = task
|
||||||
|
t.next_run = 0.0
|
||||||
|
this.tasks.add(t)
|
||||||
|
|
||||||
|
|
||||||
|
proc run(this: var Scheduler) =
|
||||||
|
while this.tasks.len > 0:
|
||||||
|
var dead: seq[int] = @[]
|
||||||
|
for i in this.tasks.low..this.tasks.high:
|
||||||
|
var task = this.tasks[i]
|
||||||
|
if finished(task.coro):
|
||||||
|
dead.add(i)
|
||||||
|
continue
|
||||||
|
if task.next_run <= epochTime():
|
||||||
|
task.next_run = task.coro() + epochTime()
|
||||||
|
this.tasks[i] = task
|
||||||
|
for i in dead:
|
||||||
|
this.tasks.delete(i)
|
||||||
|
if this.tasks.len > 0:
|
||||||
|
sort(this.tasks, proc (t1: Task, t2: Task): int = cmp(t1.next_run, t2.next_run))
|
||||||
|
sleep(int((this.tasks[0].next_run - epochTime()) * 1000))
|
||||||
|
|
||||||
|
|
||||||
|
iterator a1(): float {.closure.} =
|
||||||
|
var k = 5
|
||||||
|
while k > 0:
|
||||||
|
echo "a1 $1" % [$k]
|
||||||
|
dec k, 2
|
||||||
|
yield 0.5
|
||||||
|
|
||||||
|
|
||||||
|
iterator a2(): float {.closure.} =
|
||||||
|
var k = 10
|
||||||
|
while k > 0:
|
||||||
|
echo "a2 $1" % [$k]
|
||||||
|
dec k, 2
|
||||||
|
yield 1.5
|
||||||
|
|
||||||
|
|
||||||
|
var sched = newScheduler()
|
||||||
|
sched.start(a1)
|
||||||
|
sched.start(a2)
|
||||||
|
sched.run()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue