diff options
author | Araq <rumpf_a@web.de> | 2012-09-13 08:33:55 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-09-13 08:33:55 +0200 |
commit | 23c3af80f60c1da49a1c979642e712358d960301 (patch) | |
tree | 1d8fa786c0bfb0ef1481cdfe259d2bbc2d884163 /compiler | |
parent | 8c8400ea3aa8a785aa24127602de917c21c20ffb (diff) | |
download | Nim-23c3af80f60c1da49a1c979642e712358d960301.tar.gz |
semExpr/semStmt merged
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/ast.nim | 4 | ||||
-rwxr-xr-x | compiler/msgs.nim | 2 | ||||
-rwxr-xr-x | compiler/sem.nim | 11 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 112 | ||||
-rw-r--r-- | compiler/sempass2.nim | 22 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 202 |
6 files changed, 187 insertions, 166 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 2b0fe6470..434e09dd9 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1197,3 +1197,7 @@ iterator items*(n: PNode): PNode = proc isAtom*(n: PNode): bool {.inline.} = result = n.kind >= nkNone and n.kind <= nkNilLit + +proc isEmptyType*(t: PType): bool {.inline.} = + ## 'void' and 'stmt' types are often equivalent to 'nil' these days: + result = t == nil or t.kind in {tyEmpty, tyStmt} diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 74267c059..0ad79f597 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -226,7 +226,7 @@ const errOrdXMustNotBeNegative: "ord($1) must not be negative", errLenXinvalid: "len($1) must be less than 32768", errWrongNumberOfVariables: "wrong number of variables", - errExprCannotBeRaised: "only objects can be raised", + errExprCannotBeRaised: "only a 'ref object' can be raised", errBreakOnlyInLoop: "'break' only allowed in loop construct", errTypeXhasUnknownSize: "type \'$1\' has unknown size", errConstNeedsConstExpr: "a constant can only be initialized with a constant expression", diff --git a/compiler/sem.nim b/compiler/sem.nim index 2c65f55a0..1ccc29577 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -22,12 +22,17 @@ proc semPass*(): TPass type TExprFlag = enum - efLValue, efWantIterator, efInTypeof + efLValue, efWantIterator, efInTypeof, efWantStmt TExprFlags = set[TExprFlag] 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 fitNode(c: PContext, formal: PType, arg: PNode): PNode +proc changeType(n: PNode, newType: PType) + proc semLambda(c: PContext, n: PNode): PNode proc semTypeNode(c: PContext, n: PNode, prev: PType): PType proc semStmt(c: PContext, n: PNode): PNode @@ -83,6 +88,8 @@ proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym, semCheck: bool = true): PNode +proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags, + semCheck = true): PNode proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode @@ -156,7 +163,7 @@ proc semConstBoolExpr(c: PContext, n: PNode): PNode = LocalError(n.info, errConstExprExpected) result = nn -include semtypes, semtempl, semexprs, semgnrc, semstmts +include semtypes, semtempl, semgnrc, semstmts, semexprs proc addCodeForGenerics(c: PContext, n: PNode) = for i in countup(c.generics.lastGenericIdx, Len(c.generics.generics) - 1): diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 521de8c23..e53db7cec 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -706,10 +706,14 @@ proc semExprNoType(c: PContext, n: PNode): 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) + result = semExpr(c, n, {efWantStmt}) if result.typ != nil and result.typ.kind notin {tyStmt, tyEmpty}: if gCmd == cmdInteractive: result = buildEchoStmt(c, result) + elif result.kind == nkNilLit: + # XXX too much work and fixing would break bootstrapping: + #Message(n.info, warnNilStatement) + result.typ = nil elif not ImplicitelyDiscardable(result) and result.typ.kind != tyError: localError(n.info, errDiscardValue) @@ -1041,6 +1045,60 @@ proc semAsgn(c: PContext, n: PNode): PNode = asgnToResultVar(c, n, n.sons[0], n.sons[1]) result = n +proc SemReturn(c: PContext, n: PNode): PNode = + result = n + checkSonsLen(n, 1) + if c.p.owner.kind notin {skConverter, skMethod, skProc, skMacro}: + LocalError(n.info, errXNotAllowedHere, "\'return\'") + elif n.sons[0].kind != nkEmpty: + # transform ``return expr`` to ``result = expr; return`` + if c.p.resultSym != nil: + var a = newNodeI(nkAsgn, n.sons[0].info) + addSon(a, newSymNode(c.p.resultSym)) + 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: + n.sons[0] = ast.emptyNode + else: + LocalError(n.info, errNoReturnTypeDeclared) + +proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) = + var t = skipTypes(restype, {tyGenericInst}) + case t.kind + of tyVar: + n.sons[0] = takeImplicitAddr(c, n.sons[0]) + of tyTuple: + for i in 0.. <t.sonsLen: + var e = skipTypes(t.sons[i], {tyGenericInst}) + if e.kind == tyVar: + if n.sons[0].kind == nkPar: + n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i]) + elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and + n.sons[0].sons[1].kind == nkPar: + var a = n.sons[0].sons[1] + a.sons[i] = takeImplicitAddr(c, a.sons[i]) + else: + localError(n.sons[0].info, errXExpected, "tuple constructor") + else: nil + +proc SemYield(c: PContext, n: PNode): PNode = + result = n + checkSonsLen(n, 1) + if c.p.owner == nil or c.p.owner.kind != skIterator: + LocalError(n.info, errYieldNotAllowedHere) + elif c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline: + LocalError(n.info, errYieldNotAllowedInTryStmt) + elif n.sons[0].kind != nkEmpty: + n.sons[0] = SemExprWithType(c, n.sons[0]) # check for type compatibility: + var restype = c.p.owner.typ.sons[0] + if restype != nil: + n.sons[0] = fitNode(c, restype, n.sons[0]) + if n.sons[0].typ == nil: InternalError(n.info, "semYield") + SemYieldVarResult(c, n, restype) + else: + localError(n.info, errCannotReturnExpr) + proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym = if onlyCurrentScope: result = SymtabLocalGet(c.tab, i) @@ -1417,7 +1475,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! result = semSym(c, n, n.sym, flags) - of nkEmpty, nkNone: + of nkEmpty, nkNone, nkCommentStmt: nil of nkNilLit: result.typ = getSysType(tyNil) @@ -1505,10 +1563,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = semIndirectOp(c, n, flags) of nkMacroStmt: result = semMacroStmt(c, n, flags) - of nkWhenExpr: - result = semWhen(c, n, false) - result = semExpr(c, result) - of nkBracketExpr: + of nkWhen: + if efWantStmt in flags: + result = semWhen(c, n, true) + else: + result = semWhen(c, n, false) + result = semExpr(c, result, flags) + of nkBracketExpr: checkMinSonsLen(n, 1) var s = qualifiedLookup(c, n.sons[0], {checkUndeclared}) if s != nil and s.kind in {skProc, skMethod, skConverter, skIterator}: @@ -1562,6 +1623,45 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = n.sons[0] of nkStaticExpr: result = semStaticExpr(c, n) + + of nkAsgn: result = semAsgn(c, n) + of nkBlockStmt: result = semBlock(c, n) + of nkStmtList: result = semStmtList(c, n) + of nkRaiseStmt: result = semRaise(c, n) + of nkVarSection: result = semVarOrLet(c, n, skVar) + of nkLetSection: result = semVarOrLet(c, n, skLet) + of nkConstSection: result = semConst(c, n) + of nkTypeSection: result = SemTypeSection(c, n) + of nkIfStmt: result = SemIf(c, n) + of nkDiscardStmt: result = semDiscard(c, n) + of nkWhileStmt: result = semWhile(c, n) + of nkTryStmt: result = semTry(c, n) + of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n) + of nkForStmt, nkParForStmt: result = semFor(c, n) + of nkCaseStmt: result = semCase(c, n) + of nkReturnStmt: result = semReturn(c, n) + of nkAsmStmt: result = semAsm(c, n) + of nkYieldStmt: result = semYield(c, n) + of nkPragma: pragma(c, c.p.owner, n, stmtPragmas) + of nkIteratorDef: result = semIterator(c, n) + of nkProcDef: result = semProc(c, n) + of nkMethodDef: result = semMethod(c, n) + of nkConverterDef: result = semConverterDef(c, n) + of nkMacroDef: result = semMacroDef(c, n) + of nkTemplateDef: result = semTemplateDef(c, n) + of nkImportStmt: + if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "import") + result = evalImport(c, n) + of nkFromStmt: + if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "from") + result = evalFrom(c, n) + of nkIncludeStmt: + if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "include") + result = evalInclude(c, n) + of nkPragmaBlock: + result = semPragmaBlock(c, n) + of nkStaticStmt: + result = semStaticStmt(c, n) else: LocalError(n.info, errInvalidExpressionX, renderTree(n, {renderNoComments})) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim new file mode 100644 index 000000000..139f8f15e --- /dev/null +++ b/compiler/sempass2.nim @@ -0,0 +1,22 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +# included from sem.nim + +# Second semantic checking pass over the AST. Necessary because the old +# way had some inherent problems. Performs: +# +# * procvar checks +# * effect tracking +# * closure analysis +# * checks for invalid usages of compiletime magics +# * checks for invalid usages of PNimNode +# * later: will do an escape analysis for closures at least + + diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 193d6b7cf..666c57cd1 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -64,7 +64,7 @@ proc semDiscard(c: PContext, n: PNode): PNode = checkSonsLen(n, 1) if n.sons[0].kind != nkEmpty: n.sons[0] = semExprWithType(c, n.sons[0]) - if n.sons[0].typ == nil: localError(n.info, errInvalidDiscard) + if isEmptyType(n.sons[0].typ): localError(n.info, errInvalidDiscard) proc semBreakOrContinue(c: PContext, n: PNode): PNode = result = n @@ -162,60 +162,6 @@ proc semCase(c: PContext, n: PNode): PNode = if chckCovered and (covered != toCover(n.sons[0].typ)): localError(n.info, errNotAllCasesCovered) closeScope(c.tab) - -proc SemReturn(c: PContext, n: PNode): PNode = - result = n - checkSonsLen(n, 1) - if c.p.owner.kind notin {skConverter, skMethod, skProc, skMacro}: - LocalError(n.info, errXNotAllowedHere, "\'return\'") - elif n.sons[0].kind != nkEmpty: - # transform ``return expr`` to ``result = expr; return`` - if c.p.resultSym != nil: - var a = newNodeI(nkAsgn, n.sons[0].info) - addSon(a, newSymNode(c.p.resultSym)) - 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: - n.sons[0] = ast.emptyNode - else: - LocalError(n.info, errNoReturnTypeDeclared) - -proc SemYieldVarResult(c: PContext, n: PNode, restype: PType) = - var t = skipTypes(restype, {tyGenericInst}) - case t.kind - of tyVar: - n.sons[0] = takeImplicitAddr(c, n.sons[0]) - of tyTuple: - for i in 0.. <t.sonsLen: - var e = skipTypes(t.sons[i], {tyGenericInst}) - if e.kind == tyVar: - if n.sons[0].kind == nkPar: - n.sons[0].sons[i] = takeImplicitAddr(c, n.sons[0].sons[i]) - elif n.sons[0].kind in {nkHiddenStdConv, nkHiddenSubConv} and - n.sons[0].sons[1].kind == nkPar: - var a = n.sons[0].sons[1] - a.sons[i] = takeImplicitAddr(c, a.sons[i]) - else: - localError(n.sons[0].info, errXExpected, "tuple constructor") - else: nil - -proc SemYield(c: PContext, n: PNode): PNode = - result = n - checkSonsLen(n, 1) - if c.p.owner == nil or c.p.owner.kind != skIterator: - LocalError(n.info, errYieldNotAllowedHere) - elif c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline: - LocalError(n.info, errYieldNotAllowedInTryStmt) - elif n.sons[0].kind != nkEmpty: - n.sons[0] = SemExprWithType(c, n.sons[0]) # check for type compatibility: - var restype = c.p.owner.typ.sons[0] - if restype != nil: - n.sons[0] = fitNode(c, restype, n.sons[0]) - if n.sons[0].typ == nil: InternalError(n.info, "semYield") - SemYieldVarResult(c, n, restype) - else: - localError(n.info, errCannotReturnExpr) proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode = result = fitNode(c, typ, n) @@ -1125,111 +1071,53 @@ proc insertDestructors(c: PContext, varSection: PNode): return -proc SemStmt(c: PContext, n: PNode): PNode = - const # must be last statements in a block: +proc semStmtList(c: PContext, n: PNode): PNode = + # these must be last statements in a block: + const LastBlockStmts = {nkRaiseStmt, nkReturnStmt, nkBreakStmt, nkContinueStmt} result = n - if gCmd == cmdIdeTools: - suggestStmt(c, n) - if nfSem in n.flags: return - case n.kind - of nkAsgn: result = semAsgn(c, n) - of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkMacroStmt, nkCallStrLit: - result = semCommand(c, n) - of nkEmpty, nkCommentStmt: nil - of nkNilLit: - # XXX too much work and fixing would break bootstrapping: - #Message(n.info, warnNilStatement) - of nkBlockStmt: result = semBlock(c, n) - of nkStmtList: - var length = sonsLen(n) - for i in countup(0, length - 1): - case n.sons[i].kind - of nkFinally, nkExceptBranch: - # stand-alone finally and except blocks are - # transformed into regular try blocks: - # - # var f = fopen("somefile") | var f = fopen("somefile") - # finally: fclose(f) | try: - # ... | ... - # | finally: - # | fclose(f) - var tryStmt = newNodeI(nkTryStmt, n.sons[i].info) - var body = newNodeI(nkStmtList, n.sons[i].info) - if i < n.sonsLen - 1: - body.sons = n.sons[(i+1)..(-1)] - tryStmt.addSon(body) - tryStmt.addSon(n.sons[i]) - n.sons[i] = semTry(c, tryStmt) - n.sons.setLen(i+1) - return - else: - n.sons[i] = semStmt(c, n.sons[i]) - case n.sons[i].kind - of nkVarSection, nkLetSection: - let (outer, inner) = insertDestructors(c, n.sons[i]) - if outer != nil: - n.sons[i] = outer - for j in countup(i+1, length-1): - inner.addSon(SemStmt(c, n.sons[j])) - n.sons.setLen(i+1) - return - of LastBlockStmts: - for j in countup(i + 1, length - 1): - case n.sons[j].kind - of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil - else: localError(n.sons[j].info, errStmtInvalidAfterReturn) - else: nil - of nkRaiseStmt: result = semRaise(c, n) - of nkVarSection: result = semVarOrLet(c, n, skVar) - of nkLetSection: result = semVarOrLet(c, n, skLet) - of nkConstSection: result = semConst(c, n) - of nkTypeSection: result = SemTypeSection(c, n) - of nkIfStmt: result = SemIf(c, n) - of nkWhenStmt: result = semWhen(c, n) - of nkDiscardStmt: result = semDiscard(c, n) - of nkWhileStmt: result = semWhile(c, n) - of nkTryStmt: result = semTry(c, n) - of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n) - of nkForStmt, nkParForStmt: result = semFor(c, n) - of nkCaseStmt: result = semCase(c, n) - of nkReturnStmt: result = semReturn(c, n) - of nkAsmStmt: result = semAsm(c, n) - of nkYieldStmt: result = semYield(c, n) - of nkPragma: pragma(c, c.p.owner, n, stmtPragmas) - of nkIteratorDef: result = semIterator(c, n) - of nkProcDef: result = semProc(c, n) - of nkMethodDef: result = semMethod(c, n) - of nkConverterDef: result = semConverterDef(c, n) - of nkMacroDef: result = semMacroDef(c, n) - of nkTemplateDef: result = semTemplateDef(c, n) - of nkImportStmt: - if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "import") - result = evalImport(c, n) - of nkFromStmt: - if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "from") - result = evalFrom(c, n) - of nkIncludeStmt: - if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "include") - result = evalInclude(c, n) - of nkPragmaBlock: - result = semPragmaBlock(c, n) - of nkStaticStmt: - result = semStaticStmt(c, n) - else: - # in interactive mode, we embed the expression in an 'echo': - if gCmd == cmdInteractive: - result = buildEchoStmt(c, semExpr(c, n)) + var length = sonsLen(n) + for i in countup(0, length - 1): + case n.sons[i].kind + of nkFinally, nkExceptBranch: + # stand-alone finally and except blocks are + # transformed into regular try blocks: + # + # var f = fopen("somefile") | var f = fopen("somefile") + # finally: fclose(f) | try: + # ... | ... + # | finally: + # | fclose(f) + var tryStmt = newNodeI(nkTryStmt, n.sons[i].info) + var body = newNodeI(nkStmtList, n.sons[i].info) + if i < n.sonsLen - 1: + body.sons = n.sons[(i+1)..(-1)] + tryStmt.addSon(body) + tryStmt.addSon(n.sons[i]) + n.sons[i] = semTry(c, tryStmt) + n.sons.setLen(i+1) + return else: - result = semExprNoType(c, n) - #LocalError(n.info, errStmtExpected) - #result = ast.emptyNode - if result == nil: - InternalError(n.info, "SemStmt: result = nil") - # error correction: - result = emptyNode - else: - incl(result.flags, nfSem) + n.sons[i] = semStmt(c, n.sons[i]) + case n.sons[i].kind + of nkVarSection, nkLetSection: + let (outer, inner) = insertDestructors(c, n.sons[i]) + if outer != nil: + n.sons[i] = outer + for j in countup(i+1, length-1): + inner.addSon(SemStmt(c, n.sons[j])) + n.sons.setLen(i+1) + return + of LastBlockStmts: + for j in countup(i + 1, length - 1): + case n.sons[j].kind + of nkPragma, nkCommentStmt, nkNilLit, nkEmpty: nil + else: localError(n.sons[j].info, errStmtInvalidAfterReturn) + else: nil + +proc SemStmt(c: PContext, n: PNode): PNode = + # now: simply an alias: + result = semExprNoType(c, n) proc semStmtScope(c: PContext, n: PNode): PNode = openScope(c.tab) |