From d9d82fb0af8688e7c847bb7b0c3b2e38f7c8a735 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 3 Oct 2012 21:11:41 +0300 Subject: syntax compatibility between do blocks and stmt blocks See the section `do notation` in the manual for more info. * nkMacroStmt has been removed Macro statements are now mapped to regular nkCall nodes. The support for additional clauses (such as else, except, of, etc) have been restored - they will now appear as additional arguments for the nkCall node (as nkElse, nkExcept, etc nodes) * fixed some regressions in the `is` operator and semCompiles --- compiler/ast.nim | 13 +++++++- compiler/c2nim/cparse.nim | 2 +- compiler/evals.nim | 2 +- compiler/idents.nim | 4 ++- compiler/msgs.nim | 19 ++++++----- compiler/options.nim | 6 ++-- compiler/parser.nim | 59 +++++++++++++------------------- compiler/renderer.nim | 1 - compiler/sem.nim | 9 +++-- compiler/semexprs.nim | 85 +++++++++++++---------------------------------- compiler/semgnrc.nim | 13 ++------ compiler/semstmts.nim | 44 ++++++++++++++++-------- compiler/semtypinst.nim | 3 +- compiler/sigmatch.nim | 8 +++-- compiler/suggest.nim | 3 +- 15 files changed, 124 insertions(+), 147 deletions(-) (limited to 'compiler') diff --git a/compiler/ast.nim b/compiler/ast.nim index aa94644aa..340a14888 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -145,7 +145,6 @@ type nkElifBranch, # used in if statements nkExceptBranch, # an except section nkElse, # an else part - nkMacroStmt, # a macro statement nkAsmStmt, # an assembler block nkPragma, # a pragma statement nkPragmaBlock, # a pragma with a block @@ -911,6 +910,18 @@ proc newMetaNodeIT*(tree: PNode, info: TLineInfo, typ: PType): PNode = result = newNodeIT(nkMetaNode, info, typ) result.add(tree) +var emptyParams = newNode(nkFormalParams) +emptyParams.addSon(emptyNode) + +proc newProcNode*(kind: TNodeKind, info: TLineInfo, body: PNode, + params = emptyParams, + name, pattern, genericParams, + pragmas, exceptions = ast.emptyNode): PNode = + result = newNodeI(kind, info) + result.sons = @[name, pattern, genericParams, params, + pragmas, exceptions, body] + + proc NewType(kind: TTypeKind, owner: PSym): PType = new(result) result.kind = kind diff --git a/compiler/c2nim/cparse.nim b/compiler/c2nim/cparse.nim index cb023411d..9f7a7bf36 100755 --- a/compiler/c2nim/cparse.nim +++ b/compiler/c2nim/cparse.nim @@ -1382,7 +1382,7 @@ proc nestedStatement(p: var TParser): PNode = # Nimrod requires complex statements to be nested in whitespace! const complexStmt = {nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, - nkTemplateDef, nkIteratorDef, nkMacroStmt, nkIfStmt, + nkTemplateDef, nkIteratorDef, nkIfStmt, nkWhenStmt, nkForStmt, nkWhileStmt, nkCaseStmt, nkVarSection, nkConstSection, nkTypeSection, nkTryStmt, nkBlockStmt, nkStmtList, nkCommentStmt, nkStmtListExpr, nkBlockExpr, nkStmtListType, nkBlockType} diff --git a/compiler/evals.nim b/compiler/evals.nim index e72231bf5..c6248e823 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -1296,7 +1296,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = of nkEmpty: result = n of nkSym: result = evalSym(c, n, flags) of nkType..nkNilLit: result = copyNode(n) # end of atoms - of nkCall, nkHiddenCallConv, nkMacroStmt, nkCommand, nkCallStrLit, nkInfix, + of nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit, nkInfix, nkPrefix, nkPostfix: result = evalMagicOrCall(c, n) of nkCurly, nkBracket, nkRange: diff --git a/compiler/idents.nim b/compiler/idents.nim index f6df3ba93..838d445d3 100755 --- a/compiler/idents.nim +++ b/compiler/idents.nim @@ -101,4 +101,6 @@ proc getIdent*(identifier: string, h: THash): PIdent = proc IdentEq*(id: PIdent, name: string): bool = result = id.id == getIdent(name).id - + +let idAnon* = getIdent":anonymous" + diff --git a/compiler/msgs.nim b/compiler/msgs.nim index e29142e4f..0d9a05240 100755 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -585,22 +585,25 @@ proc inCheckpoint*(current: TLineInfo): TCheckPointResult = type TErrorHandling = enum doNothing, doAbort, doRaise -proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = - if msg == errInternal: - assert(false) # we want a stack trace here +proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) = + template maybeTrace = + if defined(debug) or gVerbosity >= 3: + writeStackTrace() + + if msg == errInternal: + writeStackTrace() # we always want a stack trace here if msg >= fatalMin and msg <= fatalMax: - if gVerbosity >= 3: assert(false) + maybeTrace() quit(1) if msg >= errMin and msg <= errMax: - if gVerbosity >= 3: assert(false) + maybeTrace() inc(gErrorCounter) options.gExitcode = 1'i8 if gErrorCounter >= gErrorMax or eh == doAbort: - if gVerbosity >= 3: assert(false) - quit(1) # one error stops the compiler + quit(1) # one error stops the compiler elif eh == doRaise: raiseRecoverableError(s) - + proc `==`*(a, b: TLineInfo): bool = result = a.line == b.line and a.fileIndex == b.fileIndex diff --git a/compiler/options.nim b/compiler/options.nim index c6b2053b1..316ec2b14 100755 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -227,5 +227,7 @@ proc binaryStrSearch*(x: openarray[string], y: string): int = result = - 1 # Can we keep this? I'm using it all the time -template nimdbg*: expr = c.filename.endsWith"nimdbg.nim" -template cnimdbg*: expr = p.module.filename.endsWith"nimdbg.nim" +template nimdbg*: expr = c.filename.endsWith"hallo.nim" +template cnimdbg*: expr = p.module.filename.endsWith"hallo.nim" +template enimdbg*: expr = c.module.name.s == "hallo" +template pnimdbg*: expr = p.lex.fileIdx.ToFilename.endsWith"hallo.nim" diff --git a/compiler/parser.nim b/compiler/parser.nim index 7612980c5..095252d59 100755 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -693,20 +693,15 @@ proc optPragmas(p: var TParser): PNode = else: result = ast.emptyNode proc parseDoBlock(p: var TParser): PNode = - var info = parLineInfo(p) + let info = parLineInfo(p) getTok(p) - var params = parseParamList(p, retColon=false) - var pragmas = optPragmas(p) + let params = parseParamList(p, retColon=false) + let pragmas = optPragmas(p) eat(p, tkColon) - result = newNodeI(nkDo, info) - addSon(result, ast.emptyNode) # no name part - addSon(result, ast.emptyNode) # no pattern part - addSon(result, ast.emptyNode) # no generic parameters - addSon(result, params) - addSon(result, pragmas) skipComment(p, result) - addSon(result, ast.emptyNode) # no exception list - addSon(result, parseStmt(p)) + result = newProcNode(nkDo, info, parseStmt(p), + params = params, + pragmas = pragmas) proc parseDoBlocks(p: var TParser, call: PNode) = while p.tok.tokType == tkDo: @@ -723,16 +718,11 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode = params = parseParamList(p) pragmas = optPragmas(p) if p.tok.tokType == tkEquals and isExpr: - result = newNodeI(nkLambda, info) - addSon(result, ast.emptyNode) # no name part - addSon(result, ast.emptyNode) # no pattern - addSon(result, ast.emptyNode) # no generic parameters - addSon(result, params) - addSon(result, pragmas) getTok(p) skipComment(p, result) - addSon(result, ast.emptyNode) # no exception list - addSon(result, parseStmt(p)) + result = newProcNode(nkLambda, info, parseStmt(p), + params = params, + pragmas = pragmas) else: result = newNodeI(nkProcTy, info) if hasSignature: @@ -822,7 +812,7 @@ proc primary(p: var TParser, skipSuffix = false): PNode = proc parseTypeDesc(p: var TParser): PNode = if p.tok.toktype == tkProc: result = parseProcExpr(p, false) else: result = parseExpr(p) - + proc parseExprStmt(p: var TParser): PNode = var a = lowestExpr(p) if p.tok.tokType == tkEquals: @@ -832,32 +822,29 @@ proc parseExprStmt(p: var TParser): PNode = result = newNodeI(nkAsgn, a.info) addSon(result, a) addSon(result, b) - else: - result = newNodeP(nkCommand, p) - result.info = a.info - addSon(result, a) - while true: + else: + var call = if a.kind == nkCall: a + else: newNode(nkCommand, a.info, @[a]) + while true: if not isExprStart(p): break var e = parseExpr(p) - addSon(result, e) + addSon(call, e) if p.tok.tokType != tkComma: break getTok(p) optInd(p, a) if p.tok.tokType == tkDo: - parseDoBlocks(p, result) + parseDoBlocks(p, call) return - if sonsLen(result) <= 1: result = a - else: a = result + result = if call.sonsLen <= 1: a + else: call if p.tok.tokType == tkColon: - # macro statement - result = newNodeP(nkMacroStmt, p) - result.info = a.info - addSon(result, a) + result = call getTok(p) skipComment(p, result) if p.tok.tokType == tkSad: getTok(p) - if not (p.tok.TokType in {tkOf, tkElif, tkElse, tkExcept}): - addSon(result, parseStmt(p)) + if not (p.tok.TokType in {tkOf, tkElif, tkElse, tkExcept}): + let body = parseStmt(p) + addSon(result, newProcNode(nkDo, body.info, body)) while true: if p.tok.tokType == tkSad: getTok(p) var b: PNode @@ -882,7 +869,7 @@ proc parseExprStmt(p: var TParser): PNode = else: break addSon(b, parseStmt(p)) addSon(result, b) - if b.kind == nkElse: break + if b.kind == nkElse: break proc parseImportOrIncludeStmt(p: var TParser, kind: TNodeKind): PNode = var a: PNode diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 5199e234d..de642eccb 100755 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -1051,7 +1051,6 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkWhileStmt: gwhile(g, n) of nkPragmaBlock: gpragmaBlock(g, n) of nkCaseStmt, nkRecCase: gcase(g, n) - of nkMacroStmt: gmacro(g, n) of nkTryStmt: gtry(g, n) of nkForStmt, nkParForStmt: gfor(g, n) of nkBlockStmt, nkBlockExpr: gblock(g, n) diff --git a/compiler/sem.nim b/compiler/sem.nim index 0a6159dfa..9289df61c 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -22,8 +22,7 @@ proc semPass*(): TPass type TExprFlag = enum - efLValue, efWantIterator, efInTypeof, efWantStmt, - efMacroStmt # expr to semcheck is a macro statement + efLValue, efWantIterator, efInTypeof, efWantStmt, efDetermineType TExprFlags = set[TExprFlag] proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode @@ -35,7 +34,7 @@ proc semProcBody(c: PContext, n: PNode): PNode proc fitNode(c: PContext, formal: PType, arg: PNode): PNode proc changeType(n: PNode, newType: PType) -proc semLambda(c: PContext, n: PNode): PNode +proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode proc semTypeNode(c: PContext, n: PNode, prev: PType): PType proc semStmt(c: PContext, n: PNode): PNode proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) @@ -44,6 +43,8 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) proc addResultNode(c: PContext, n: PNode) proc instGenericContainer(c: PContext, n: PNode, header: PType): PType proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode +proc fixImmediateParams(n: PNode): PNode +proc activate(c: PContext, n: PNode) proc typeMismatch(n: PNode, formal, actual: PType) = if formal.kind != tyError and actual.kind != tyError: @@ -91,8 +92,6 @@ 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 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index e9dc5a8e9..adcd67ea3 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -304,16 +304,17 @@ proc semIs(c: PContext, n: PNode): PNode = # BUGFIX: don't evaluate this too early: ``T is void`` if not containsGenericType(t1): result = evalIsOp(n) -proc semOpAux(c: PContext, n: PNode, tailToExclude = 1) = - for i in countup(1, sonsLen(n) - tailToExclude): +proc semOpAux(c: PContext, n: PNode) = + let flags = {efDetermineType} + for i in countup(1, n.sonsLen- 1): var a = n.sons[i] if a.kind == nkExprEqExpr and sonsLen(a) == 2: var info = a.sons[0].info a.sons[0] = newIdentNode(considerAcc(a.sons[0]), info) - a.sons[1] = semExprWithType(c, a.sons[1]) + a.sons[1] = semExprWithType(c, a.sons[1], flags) a.typ = a.sons[1].typ else: - n.sons[i] = semExprWithType(c, a) + n.sons[i] = semExprWithType(c, a, flags) proc overloadedCallOpr(c: PContext, n: PNode): PNode = # quick check if there is *any* () operator overloaded: @@ -668,8 +669,7 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = # this seems to be a hotspot in the compiler! let nOrig = n.copyTree - semOpAux(c, n, 1 + ord(efMacroStmt in flags)) - let flags = flags - {efMacroStmt} + semOpAux(c, n) result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags) if result == nil: result = overloadedCallOpr(c, n) @@ -679,8 +679,9 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = let callee = result.sons[0].sym case callee.kind of skMacro: result = semMacroExpr(c, result, nOrig, callee) - of skTemplate: result = semTemplateExpr(c, nOrig, callee) + of skTemplate: result = semTemplateExpr(c, result, callee) else: + activate(c, n) fixAbstractType(c, result) analyseIfAddressTakenInCall(c, result) if callee.magic != mNone: @@ -1281,7 +1282,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = # we replace this node by a 'true' or 'false' node: if sonsLen(n) != 2: return semDirectOp(c, n, flags) - result = newIntNode(nkIntLit, ord(tryExpr(c, n, flags) != nil)) + result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil)) result.info = n.info result.typ = getSysType(tyBool) @@ -1496,52 +1497,6 @@ proc buildCall(n: PNode): PNode = else: result = n -proc semMacroStmt(c: PContext, n: PNode, flags: TExprFlags, - semCheck = true): PNode = - checkMinSonsLen(n, 2) - var a: PNode - if isCallExpr(n.sons[0]): a = n.sons[0].sons[0] - else: a = n.sons[0] - var s = qualifiedLookup(c, a, {checkUndeclared}) - if s != nil: - # transform - # nkMacroStmt(nkCall(a...), stmt, b...) - # to - # nkCall(a..., stmt, b...) - result = newNodeI(nkCall, n.info) - addSon(result, a) - if isCallExpr(n.sons[0]): - for i in countup(1, sonsLen(n.sons[0]) - 1): - addSon(result, n.sons[0].sons[i]) - # for sigmatch this need to have a type; we use 'void': - for i in countup(1, sonsLen(n) - 1): - n.sons[i].typ = newTypeS(tyEmpty, c) - addSon(result, n.sons[i]) - - case s.kind - of skMacro: - if sfImmediate notin s.flags: - result = semDirectOp(c, result, flags+{efMacroStmt}) - else: - result = semMacroExpr(c, result, n, s, semCheck) - of skTemplate: - if sfImmediate notin s.flags: - result = semDirectOp(c, result, flags+{efMacroStmt}) - else: - result = semTemplateExpr(c, result, s, semCheck) - else: - LocalError(n.info, errXisNoMacroOrTemplate, s.name.s) - result = errorNode(c, n) - elif a.kind == nkDotExpr: - # 'x.m(y): stmt' == nkMacroStmt(nkCall(nkDotExpr(x, m), y), stmt) - # --> nkMacroStmt(nkCall(m, x, y), stmt) - n.sons[0] = buildCall(n.sons[0]) - result = semMacroStmt(c, n, flags, semCheck) - else: - LocalError(n.info, errInvalidExpressionX, - renderTree(a, {renderNoComments})) - result = errorNode(c, n) - proc semCaseExpr(c: PContext, caseStmt: PNode): PNode = # The case expression is simply rewritten to a StmtListExpr: # var res {.noInit, genSym.}: type(values) @@ -1553,7 +1508,7 @@ proc semCaseExpr(c: PContext, caseStmt: PNode): PNode = # res var info = caseStmt.info - resVar = newSym(skVar, getIdent":res", getCurrOwner(), info) + resVar = newSym(skVar, idAnon, getCurrOwner(), info) resNode = newSymNode(resVar, info) resType: PType @@ -1592,7 +1547,15 @@ proc semCaseExpr(c: PContext, caseStmt: PNode): PNode = resNode]) result = semStmtListExpr(c, result) - + +proc fixImmediateParams(n: PNode): PNode = + # XXX: Temporary work-around until we carry out + # the planned overload resolution reforms + for i in 1 ..