summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim1
-rwxr-xr-xcompiler/docgen.nim3
-rw-r--r--compiler/lambdalifting.nim7
-rwxr-xr-xcompiler/parser.nim7
-rwxr-xr-xcompiler/renderer.nim7
-rwxr-xr-xcompiler/sem.nim1
-rwxr-xr-xcompiler/semexprs.nim28
-rwxr-xr-xcompiler/seminst.nim2
-rwxr-xr-xcompiler/semstmts.nim7
-rwxr-xr-xcompiler/semtempl.nim23
-rwxr-xr-xlib/core/macros.nim2
-rw-r--r--tests/compile/tircbot.nim20
-rwxr-xr-xtests/run/tenumhole.nim5
-rwxr-xr-xtodo.txt7
-rwxr-xr-xweb/news.txt2
15 files changed, 91 insertions, 31 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 434e09dd9..e556ac671 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -176,6 +176,7 @@ type
     nkFromStmt,           # a from * import statement
     nkIncludeStmt,        # an include statement
     nkBindStmt,           # a bind statement
+    nkMixinStmt,          # a mixin statement
     nkCommentStmt,        # a comment statement
     nkStmtListExpr,       # a statement list followed by an expr; this is used
                           # to allow powerful multi-line templates
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 6fe1d03b1..0fc5e03cf 100755
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -184,8 +184,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
   var kind = tkEof
   var comm = genRecComment(d, n)  # call this here for the side-effect!
   var r: TSrcGen
-  initTokRender(r, n, {renderNoPragmas, renderNoBody, renderNoComments, 
-                       renderDocComments})
+  initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments})
   while true: 
     getNextTok(r, kind, literal)
     case kind
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 0748b99b3..5896615c0 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -538,9 +538,6 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
   if body.kind == nkEmpty or gCmd == cmdCompileToEcmaScript:
     # ignore forward declaration:
     result = body
-  elif not containsNode(body, procDefs) and false:
-    # fast path: no inner procs, so no closure needed:
-    result = body
   else:
     var o = newOuterContext(fn)
     let ex = closureCreationPoint(body)
@@ -552,6 +549,10 @@ proc liftLambdas*(fn: PSym, body: PNode): PNode =
         InternalError(params.info, "liftLambdas: strange params")
       let param = params.sons[i].sym
       IdTablePut(o.localsToEnv, param, o.currentEnv)
+    # put the 'result' into the environment so it can be captured:
+    let ast = fn.ast
+    if resultPos < sonsLen(ast) and ast.sons[resultPos].kind == nkSym:
+      IdTablePut(o.localsToEnv, ast.sons[resultPos].sym, o.currentEnv)
     searchForInnerProcs(o, body)
     discard transformOuterProc(o, body)
     result = ex
diff --git a/compiler/parser.nim b/compiler/parser.nim
index b359c6e3d..cdbe42c7e 100755
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -1461,8 +1461,8 @@ proc parseVariable(p: var TParser): PNode =
   else: result = parseIdentColonEquals(p, {withPragma})
   indAndComment(p, result)    # special extension!
   
-proc parseBind(p: var TParser): PNode =
-  result = newNodeP(nkBindStmt, p)
+proc parseBind(p: var TParser, k: TNodeKind): PNode =
+  result = newNodeP(k, p)
   getTok(p)
   optInd(p, result)
   while true:
@@ -1523,7 +1523,8 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
   of tkLet: result = parseSection(p, nkLetSection, parseVariable)
   of tkWhen: result = parseIfOrWhen(p, nkWhenStmt)
   of tkVar: result = parseSection(p, nkVarSection, parseVariable)
-  of tkBind: result = parseBind(p)
+  of tkBind: result = parseBind(p, nkBindStmt)
+  of tkMixin: result = parseBind(p, nkMixinStmt)
   else: result = simpleStmt(p)
   
 proc parseStmt(p: var TParser): PNode = 
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 8a8e1e849..5199e234d 100755
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -386,6 +386,7 @@ proc lsub(n: PNode): int =
   of nkDotExpr: result = lsons(n) + 1
   of nkBind: result = lsons(n) + len("bind_")
   of nkBindStmt: result = lcomma(n) + len("bind_")
+  of nkMixinStmt: result = lcomma(n) + len("mixin_")
   of nkCheckedFieldExpr: result = lsub(n.sons[0])
   of nkLambda: result = lsons(n) + len("proc__=_")
   of nkDo: result = lsons(n) + len("do__:_")
@@ -1114,7 +1115,8 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     putWithSpace(g, tkContinue, "continue")
     gsub(g, n.sons[0])
   of nkPragma: 
-    if not (renderNoPragmas in g.flags): 
+    if renderNoPragmas notin g.flags:
+      put(g, tkSpaces, Space)
       put(g, tkCurlyDotLe, "{.")
       gcomma(g, n, emptyContext)
       put(g, tkCurlyDotRi, ".}")
@@ -1152,6 +1154,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
   of nkBindStmt: 
     putWithSpace(g, tkBind, "bind")
     gcomma(g, n, c)
+  of nkMixinStmt:
+    putWithSpace(g, tkMixin, "mixin")
+    gcomma(g, n, c)
   of nkElifBranch: 
     optNL(g)
     putWithSpace(g, tkElif, "elif")
diff --git a/compiler/sem.nim b/compiler/sem.nim
index e1f2fb21c..315ff92cd 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -30,6 +30,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
 proc semExprNoType(c: PContext, n: PNode): PNode
 proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
+proc semProcBody(c: PContext, n: PNode): PNode
 
 proc fitNode(c: PContext, formal: PType, arg: PNode): PNode
 proc changeType(n: PNode, newType: PType)
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 8a42a7090..89789f269 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -706,11 +706,10 @@ proc buildEchoStmt(c: PContext, n: PNode): PNode =
   # and check 'arg' for semantics again:
   addSon(result, semExpr(c, arg))
 
-proc semExprNoType(c: PContext, n: PNode): PNode =
+proc discardCheck(result: PNode) =
   proc ImplicitelyDiscardable(n: PNode): bool {.inline.} =
     result = isCallExpr(n) and n.sons[0].kind == nkSym and 
              sfDiscardable in n.sons[0].sym.flags
-  result = semExpr(c, n, {efWantStmt})
   if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}:
     if result.kind == nkNilLit:
       # XXX too much work and fixing would break bootstrapping:
@@ -718,7 +717,11 @@ proc semExprNoType(c: PContext, n: PNode): PNode =
       result.typ = nil
     elif not ImplicitelyDiscardable(result) and result.typ.kind != tyError and
         gCmd != cmdInteractive:
-      localError(n.info, errDiscardValue)
+      localError(result.info, errDiscardValue)
+
+proc semExprNoType(c: PContext, n: PNode): PNode =
+  result = semExpr(c, n, {efWantStmt})
+  discardCheck(result)
   
 proc isTypeExpr(n: PNode): bool = 
   case n.kind
@@ -1061,11 +1064,28 @@ proc SemReturn(c: PContext, n: PNode): PNode =
       addSon(a, n.sons[0])
       n.sons[0] = semAsgn(c, a)
       # optimize away ``result = result``:
-      if n[0][1].kind == nkSym and n[0][1].sym.kind == skResult: 
+      if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym: 
         n.sons[0] = ast.emptyNode
     else:
       LocalError(n.info, errNoReturnTypeDeclared)
 
+proc semProcBody(c: PContext, n: PNode): PNode =
+  openScope(c.tab)
+  result = semExpr(c, n)
+  if c.p.resultSym != nil and not isEmptyType(result.typ):
+    # transform ``expr`` to ``result = expr``, but not if the expr is already
+    # ``result``:
+    if result.kind == nkSym and result.sym == c.p.resultSym: 
+      nil
+    else:
+      var a = newNodeI(nkAsgn, n.info, 2)
+      a.sons[0] = newSymNode(c.p.resultSym)
+      a.sons[1] = result
+      result = semAsgn(c, a)
+  else:
+    discardCheck(result)
+  closeScope(c.tab)
+
 proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) =
   var t = skipTypes(restype, {tyGenericInst})
   case t.kind
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 135f9bba9..ba950422f 100755
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -93,7 +93,7 @@ proc instantiateBody(c: PContext, n: PNode, result: PSym) =
     var symMap: TIdTable
     InitIdTable symMap
     freshGenSyms(b, result, symMap)
-    b = semStmtScope(c, b)
+    b = semProcBody(c, b)
     b = hloBody(c, b)
     n.sons[bodyPos] = transformBody(c.module, b, result)
     #echo "code instantiated ", result.name.s
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 666c57cd1..2bd5898a7 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -661,7 +661,7 @@ proc semLambda(c: PContext, n: PNode): PNode =
       LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
     pushProcCon(c, s)
     addResult(c, s.typ.sons[0], n.info, skProc)
-    let semBody = hloBody(c, semStmtScope(c, n.sons[bodyPos]))
+    let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
     n.sons[bodyPos] = transformBody(c.module, semBody, s)
     addResultNode(c, n)
     popProcCon(c)
@@ -765,13 +765,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
       pushProcCon(c, s)
       if s.typ.sons[0] != nil and kind != skIterator: 
         addResult(c, s.typ.sons[0], n.info, kind)
+        addResultNode(c, n)
       if sfImportc notin s.flags:
         # no semantic checking for importc:
-        let semBody = hloBody(c, semStmtScope(c, n.sons[bodyPos]))
+        let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos]))
         # unfortunately we cannot skip this step when in 'system.compiles'
         # context as it may even be evaluated in 'system.compiles':
         n.sons[bodyPos] = transformBody(c.module, semBody, s)
-      if s.typ.sons[0] != nil and kind != skIterator: addResultNode(c, n)
+      #if s.typ.sons[0] != nil and kind != skIterator: addResultNode(c, n)
       popProcCon(c)
     else: 
       if s.typ.sons[0] != nil and kind != skIterator:
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 8e36aac20..1444255ff 100755
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -90,6 +90,29 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var TIntSet): PNode =
     else:
       illFormedAst(a)
   result = newNodeI(nkNilLit, n.info)
+
+when false:
+  # not active before 0.9.0 is out
+  proc semMixinStmt(c: PContext, n: PNode, toMixin: var TIntSet): PNode =
+    for i in 0 .. < n.len:
+      var a = n.sons[i]
+      # If 'a' is an overloaded symbol, we used to use the first symbol
+      # as a 'witness' and use the fact that subsequent lookups will yield
+      # the same symbol!
+      # This is however not true anymore for hygienic templates as semantic
+      # processing for them changes the symbol table...
+      let s = QualifiedLookUp(c, a)
+      if s != nil:
+        # we need to mark all symbols:
+        let sc = symChoice(c, n, s, scForceOpen)
+        if sc.kind == nkSym:
+          toMixin.incl(sc.sym.id)
+        else:
+          for x in items(sc): toMixin.incl(x.sym.id)
+      else:
+        # do nothing: identifiers are already not bound:
+        nil
+    result = newNodeI(nkNilLit, n.info)
   
 proc replaceIdentBySym(n: var PNode, s: PNode) =
   case n.kind
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 2eab1750c..b43105f44 100755
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -46,7 +46,7 @@ type
     nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt, 

     nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,

     nnkDiscardStmt, nnkStmtList, nnkImportStmt, nnkFromStmt, 

-    nnkIncludeStmt, nnkBindStmt, 

+    nnkIncludeStmt, nnkBindStmt, nnkMixinStmt,

     nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr, 

     nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy, 

     nnkTupleTy, nnkRecList, nnkRecCase, nnkRecWhen, 

diff --git a/tests/compile/tircbot.nim b/tests/compile/tircbot.nim
index e538a7e57..10482c3f6 100644
--- a/tests/compile/tircbot.nim
+++ b/tests/compile/tircbot.nim
@@ -426,21 +426,23 @@ proc handleIrc(irc: var TAsyncIRC, event: TIRCEvent, state: PState) =
       nil # TODO: ?
 
 proc open(port: TPort = TPort(5123)): PState =
-  new(result)
-  result.dispatcher = newDispatcher()
+  var res: PState
+  new(res)
+  res.dispatcher = newDispatcher()
   
-  result.hubPort = port
-  result.hubConnect()
+  res.hubPort = port
+  res.hubConnect()
   let hirc =
     proc (a: var TAsyncIRC, ev: TIRCEvent) =
-      handleIrc(a, ev, result)
+      handleIrc(a, ev, res)
   # Connect to the irc server.
-  result.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname,
+  res.ircClient = AsyncIrc(ircServer, nick = botNickname, user = botNickname,
                  joinChans = joinChans, ircEvent = hirc)
-  result.ircClient.connect()
-  result.dispatcher.register(result.ircClient)
+  res.ircClient.connect()
+  res.dispatcher.register(res.ircClient)
 
-  result.dbConnected = false
+  res.dbConnected = false
+  result = res
 
 var state = tircbot.open() # Connect to the website and the IRC server.
 
diff --git a/tests/run/tenumhole.nim b/tests/run/tenumhole.nim
index b721c73dd..a35526378 100755
--- a/tests/run/tenumhole.nim
+++ b/tests/run/tenumhole.nim
@@ -13,8 +13,11 @@ type
     valueC,
     valueD = (4, "abc")
  
+# test the new "proc body can be an expr" feature:
+proc getValue: TMyEnum = valueD
+ 
 # trick the optimizer with a variable:
-var x = valueD
+var x = getValue()
 echo valueA, ord(valueA), valueB, ord(valueB), valueC, valueD, ord(valueD), x
 
 
diff --git a/todo.txt b/todo.txt
index eec4985b5..53bd9d714 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,8 +1,7 @@
-version 0.9.0
+version 0.9.2
 =============
 
 - make 'bind' default for templates and introduce 'mixin'
-
 - implicit deref for parameter matching; overloading based on 'var T'
 - optimize genericAssign in the code generator
 
@@ -173,4 +172,6 @@ Version 2 and beyond
     
     case x with `=~`
 
-- implement ``partial`` pragma for partial evaluation
+- implement ``partial`` pragma for partial evaluation: easily done with AST
+  overloading
+
diff --git a/web/news.txt b/web/news.txt
index f6a7dd112..6d660579d 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -165,6 +165,8 @@ Language Additions
   comment pieces don't have to align on the same column.
 - Enums can be annotated with ``pure`` so that their field names do not pollute
   the current scope.
+- A proc body can consist of an expression that has a type. This is rewritten
+  to ``result = expression`` then.
 
 
 2012-02-09 Version 0.8.14 released