summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ccgcalls.nim110
-rw-r--r--tests/iter/tscheduler.nim76
2 files changed, 166 insertions, 20 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 64cdc789d..4f7856769 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -217,7 +217,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
   else:
     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):
     # 'var T' is 'T&' in C++. This means we ignore the request of
     # 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:
       result = genArgNoParam(p, ri.sons[i][0])
     else:
-      result = genArg(p, ri.sons[i], typ.n.sons[i].sym)
+      result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
   else:
     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 =
   var i = 0
   var j = 1
   while i < pat.len:
     case pat[i]
     of '@':
-      result.app genCppArg(p, ri, j, typ)
+      result.app genOtherArg(p, ri, j, typ)
       for k in j+1 .. < ri.len:
         result.app(~", ")
-        result.app genCppArg(p, ri, k, typ)
+        result.app genOtherArg(p, ri, k, typ)
       inc i
     of '#':
       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)
           if pat[i+1] == '+': result.app genArgNoParam(p, ri.sons[0])
           result.app(~"(")
-          result.app genCppArg(p, ri, 1, typ)
+          result.app genOtherArg(p, ri, 1, typ)
           for k in j+1 .. < ri.len:
             result.app(~", ")
-            result.app genCppArg(p, ri, k, typ)
+            result.app genOtherArg(p, ri, k, typ)
           result.app(~")")
         else:
           localError(ri.info, "call expression expected for C++ pattern")
         inc i
-      else:
-        result.app genCppArg(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(~".")
+      elif pat[i+1] == '.':
+        result.app genThisArg(p, ri, j, typ)
         inc i
+      else:
+        result.app genOtherArg(p, ri, j, typ)
       inc j
+      inc i
     of '\'':
       inc 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
         var t = typ.sons[j]
         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")
         else: result.app(getTypeDesc(p.module, t))
+        inc i
     else:
-      result.app(toRope($pat[i]))
-    inc i
+      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) =
   var op, a: TLoc
@@ -305,16 +377,14 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
       line(p, cpsStmts, pl)
   else:
     var pl: PRope = nil
-    var param = typ.n.sons[1].sym
-    app(pl, genCppArg(p, ri, 1, typ))
-    if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, ~"->")
-    else: app(pl, ~".")
+    #var param = typ.n.sons[1].sym
+    app(pl, genThisArg(p, ri, 1, typ))
     app(pl, op.r)
     var params: PRope
     for i in countup(2, length - 1):
       if params != nil: params.app(~", ")
       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)
 
 proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
diff --git a/tests/iter/tscheduler.nim b/tests/iter/tscheduler.nim
new file mode 100644
index 000000000..a267f15c4
--- /dev/null
+++ b/tests/iter/tscheduler.nim
@@ -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()