diff options
-rwxr-xr-x | compiler/ast.nim | 1 | ||||
-rwxr-xr-x | compiler/docgen.nim | 3 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 7 | ||||
-rwxr-xr-x | compiler/parser.nim | 7 | ||||
-rwxr-xr-x | compiler/renderer.nim | 7 | ||||
-rwxr-xr-x | compiler/sem.nim | 1 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 28 | ||||
-rwxr-xr-x | compiler/seminst.nim | 2 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 7 | ||||
-rwxr-xr-x | compiler/semtempl.nim | 23 | ||||
-rwxr-xr-x | lib/core/macros.nim | 2 | ||||
-rw-r--r-- | tests/compile/tircbot.nim | 20 | ||||
-rwxr-xr-x | tests/run/tenumhole.nim | 5 | ||||
-rwxr-xr-x | todo.txt | 7 | ||||
-rwxr-xr-x | web/news.txt | 2 |
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 |