summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorZahary Karadjov <zahary@gmail.com>2017-04-10 21:28:11 +0300
committerZahary Karadjov <zahary@gmail.com>2017-04-10 23:58:05 +0300
commita3f19c87fb2134db25543f1e15b96144df5638dc (patch)
treeeeb93b47e30ac8add3ead8255be97c3b3b1c1d44
parentf7b10e213b81588d560e37aa5f7c8b0d10ea5689 (diff)
downloadNim-a3f19c87fb2134db25543f1e15b96144df5638dc.tar.gz
lift parameter-less do block to lambdas
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/evaltempl.nim6
-rw-r--r--compiler/parser.nim13
-rw-r--r--compiler/semstmts.nim6
-rw-r--r--compiler/sigmatch.nim13
-rw-r--r--compiler/vm.nim3
-rw-r--r--lib/js/jsffi.nim10
-rw-r--r--tests/clearmsg/tmacroerrorproc.nim6
-rw-r--r--tests/closure/tdonotation.nim6
-rw-r--r--tests/js/tjsffi.nim8
10 files changed, 46 insertions, 26 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 982654229..5b68e9712 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -452,6 +452,7 @@ type
     nfExprCall  # this is an attempt to call a regular expression
     nfIsRef     # this node is a 'ref' node; used for the VM
     nfPreventCg # this node should be ignored by the codegen
+    nfBlockArg  # this a stmtlist appearing in a call (e.g. a do block)
 
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 30)
diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim
index 50ed4e32b..fda0b79dd 100644
--- a/compiler/evaltempl.nim
+++ b/compiler/evaltempl.nim
@@ -90,11 +90,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
 
   result = newNodeI(nkArgList, n.info)
   for i in 1 .. givenRegularParams:
-    let p = n[i]
-    if p != nil and p.kind == nkDo and s.typ.sons[i].kind in {tyStmt, tyExpr}:
-      result.addSon p[bodyPos]
-    else:
-      result.addSon p
+    result.addSon n[i]
 
   # handle parameters with default values, which were
   # not supplied by the user
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 178006e46..2607d2e3d 100644
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1170,13 +1170,11 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
     skipComment(p, result)
     if p.tok.tokType notin {tkOf, tkElif, tkElse, tkExcept}:
       var stmtList = newNodeP(nkStmtList, p)
-      let body = parseStmt(p)
-      stmtList.add body
-
-      if stmtList.len == 1 and stmtList[0].kind == nkStmtList:
-        # to keep backwards compatibility (see tests/vm/tstringnil)
-        stmtList = stmtList[0]
+      stmtList.add parseStmt(p)
+      # to keep backwards compatibility (see tests/vm/tstringnil)
+      if stmtList[0].kind == nkStmtList: stmtList = stmtList[0]
 
+      stmtList.flags.incl nfBlockArg
       if openingParams.kind != nkEmpty:
         result.add newProcNode(nkDo, stmtList.info, stmtList,
                                params = openingParams, pragmas = openingPragmas)
@@ -1209,7 +1207,10 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
         else: break
         eat(p, tkColon)
         nextBlock.addSon parseStmt(p)
+
+      nextBlock.flags.incl nfBlockArg
       result.add nextBlock
+
       if nextBlock.kind == nkElse: break
   else:
     if openingParams.kind != nkEmpty:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 63fea997a..e52a1b5cc 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -1652,7 +1652,11 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode =
       else: discard
 
   if result.len == 1 and
-     c.inTypeClass == 0 and # concept bodies should be preserved as a stmt list
+     # concept bodies should be preserved as a stmt list:
+     c.inTypeClass == 0 and
+     # also, don't make life complicated for macros.
+     # they will always expect a proper stmtlist:
+     nfBlockArg notin n.flags and
      result.sons[0].kind != nkDefer:
     result = result.sons[0]
 
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 0aa972093..89c885c64 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -1259,7 +1259,6 @@ proc typeRel(c: var TCandidate, f, aOrig: PType, doBind = true): TTypeRelation =
 
   of tyGenericInvocation:
     var x = a.skipGenericAlias
-    
     # XXX: This is very hacky. It should be moved back into liftTypeParam
     if x.kind == tyGenericInst and c.calleeSym != nil and c.calleeSym.kind == skProc:
       let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
@@ -1639,6 +1638,10 @@ proc incMatches(m: var TCandidate; r: TTypeRelation; convMatch = 1) =
   of isEqual: inc(m.exactMatches)
   of isNone: discard
 
+template matchesVoidProc(t: PType): bool =
+  (t.kind == tyProc and t.len == 1 and t.sons[0] == nil) or
+    (t.kind == tyBuiltInTypeClass and t.sons[0].kind == tyProc)
+
 proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
                         argSemantized, argOrig: PNode): PNode =
   var
@@ -1775,6 +1778,14 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
       inc(m.genericMatches)
       m.fauxMatch = a.kind
       return arg
+    elif a.kind == tyVoid and f.matchesVoidProc and argOrig.kind == nkStmtList:
+      # lift do blocks without params to lambdas
+      let lifted = c.semExpr(c, newProcNode(nkDo, argOrig.info, argOrig), {})
+      if f.kind == tyBuiltInTypeClass:
+        inc m.genericMatches
+        put(m, f, lifted.typ)
+      inc m.convMatches
+      return implicitConv(nkHiddenStdConv, f, lifted, m, c)
     result = userConvMatch(c, m, f, a, arg)
     # check for a base type match, which supports varargs[T] without []
     # constructor in a call:
diff --git a/compiler/vm.nim b/compiler/vm.nim
index d311de255..14800fb13 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1599,8 +1599,7 @@ proc setupMacroParam(x: PNode, typ: PType): TFullReg =
     putIntoReg(result, x)
   else:
     result.kind = rkNode
-    var n = if typ.kind in {tyStmt,tyExpr} and x.kind == nkDo: x[bodyPos]
-            else: x
+    var n = x
     if n.kind in {nkHiddenSubConv, nkHiddenStdConv}: n = n.sons[1]
     n = n.canonValue
     n.flags.incl nfIsRef
diff --git a/lib/js/jsffi.nim b/lib/js/jsffi.nim
index 7aa80b39b..e0310e33a 100644
--- a/lib/js/jsffi.nim
+++ b/lib/js/jsffi.nim
@@ -112,6 +112,12 @@ proc toJs*[T](val: T): JsObject {. importcpp: "(#)" .}
 
 template toJs*(s: string): JsObject = cstring(s).toJs
 
+macro jsFromAst*(n: untyped): untyped =
+  result = n
+  if n.kind == nnkStmtList:
+    result = newProc(procType = nnkDo, body = result)
+  return quote: toJs(`result`)
+
 proc `&`*(a, b: cstring): cstring {.importcpp: "(# + #)".}
   ## Concatenation operator for JavaScript strings
 
@@ -220,7 +226,7 @@ macro `.=`*(obj: JsObject, field: static[cstring], value: untyped): untyped =
 
 macro `.()`*(obj: JsObject,
              field: static[cstring],
-             args: varargs[JsObject, toJs]): JsObject =
+             args: varargs[JsObject, jsFromAst]): JsObject =
   ## Experimental "method call" operator for type JsObject.
   ## Takes the name of a method of the JavaScript object (`field`) and calls
   ## it with `args` as arguments, returning a JsObject (which may be discarded,
@@ -244,7 +250,7 @@ macro `.()`*(obj: JsObject,
     if not mangledNames.hasKey($field):
       mangledNames[$field] = $mangleJsName(field)
     importString = "#." & mangledNames[$field] & "(@)"
-  result = quote do:
+  result = quote:
     proc helper(o: JsObject): JsObject
       {. importcpp: `importString`, gensym, discardable .}
     helper(`obj`)
diff --git a/tests/clearmsg/tmacroerrorproc.nim b/tests/clearmsg/tmacroerrorproc.nim
index 9a6ff6a06..cd9b15e25 100644
--- a/tests/clearmsg/tmacroerrorproc.nim
+++ b/tests/clearmsg/tmacroerrorproc.nim
@@ -7,7 +7,7 @@ discard """
 import macros
 
 macro mixer(n: typed): untyped =
-  expectKind(n, nnkCharLit)
-  
+  expectKind(n[0], nnkCharLit)
+
 mixer:
-  echo "owh"
\ No newline at end of file
+  echo "owh"
diff --git a/tests/closure/tdonotation.nim b/tests/closure/tdonotation.nim
index 5acb17da2..94eba8ddb 100644
--- a/tests/closure/tdonotation.nim
+++ b/tests/closure/tdonotation.nim
@@ -35,11 +35,11 @@ b.onFocusLost:
 b.onFocusLost do:
   echo "lost focus 2"
 
-b.onUserEvent("UserEvent 1") do:
+b.onUserEvent "UserEvent 1" do:
   discard
 
-b.onUserEvent("UserEvent 2"):
+b.onUserEvent "UserEvent 2":
   discard
 
-b.onUserEvent("UserEvent 3", () => echo "event 2")
+b.onUserEvent("UserEvent 3", () => echo "event 3")
 
diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim
index be8e2efb7..99a475a8e 100644
--- a/tests/js/tjsffi.nim
+++ b/tests/js/tjsffi.nim
@@ -1,5 +1,6 @@
 discard """
-  output: '''true
+output: '''
+true
 true
 true
 true
@@ -19,7 +20,8 @@ true
 2
 12
 Event { name: 'click: test' }
-Event { name: 'reloaded: test' }'''
+Event { name: 'reloaded: test' }
+'''
 """
 
 import macros, jsffi, jsconsole
@@ -306,6 +308,6 @@ block:
   on("click") do (e: Event):
     console.log e
 
-  jslib.on("reloaded") do:
+  jslib.on "reloaded" do:
     console.log jsarguments[0]