diff options
author | Araq <rumpf_a@web.de> | 2014-12-12 18:25:52 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-12-12 18:25:52 +0100 |
commit | 6e6c3d2f1e9efae9fdb05dbdaadccd6dcc8efe41 (patch) | |
tree | 02ae324cf76889a5dd875bc6e0e62fd180c34907 | |
parent | 752e920b58d537b8e871e8711551a1267a7bbb5f (diff) | |
download | Nim-6e6c3d2f1e9efae9fdb05dbdaadccd6dcc8efe41.tar.gz |
extracted the fields iterator magic to its own file
-rw-r--r-- | compiler/semfields.nim | 159 | ||||
-rw-r--r-- | compiler/semstmts.nim | 148 |
2 files changed, 160 insertions, 147 deletions
diff --git a/compiler/semfields.nim b/compiler/semfields.nim new file mode 100644 index 000000000..70dead8ab --- /dev/null +++ b/compiler/semfields.nim @@ -0,0 +1,159 @@ +# +# +# The Nim Compiler +# (c) Copyright 2014 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module does the semantic transformation of the fields* iterators. +# included from semstmts.nim + +type + TFieldInstCtx = object # either 'tup[i]' or 'field' is valid + tupleType: PType # if != nil we're traversing a tuple + tupleIndex: int + field: PSym + replaceByFieldName: bool + +proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = + case n.kind + of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n + of nkIdent: + result = n + var L = sonsLen(forLoop) + if c.replaceByFieldName: + if n.ident.id == forLoop[0].ident.id: + let fieldName = if c.tupleType.isNil: c.field.name.s + elif c.tupleType.n.isNil: "Field" & $c.tupleIndex + else: c.tupleType.n.sons[c.tupleIndex].sym.name.s + result = newStrNode(nkStrLit, fieldName) + return + # other fields: + for i in ord(c.replaceByFieldName)..L-3: + if n.ident.id == forLoop[i].ident.id: + var call = forLoop.sons[L-2] + var tupl = call.sons[i+1-ord(c.replaceByFieldName)] + if c.field.isNil: + result = newNodeI(nkBracketExpr, n.info) + result.add(tupl) + result.add(newIntNode(nkIntLit, c.tupleIndex)) + else: + result = newNodeI(nkDotExpr, n.info) + result.add(tupl) + result.add(newSymNode(c.field, n.info)) + break + else: + if n.kind == nkContinueStmt: + localError(n.info, errGenerated, + "'continue' not supported in a 'fields' loop") + result = copyNode(n) + newSons(result, sonsLen(n)) + for i in countup(0, sonsLen(n)-1): + result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop) + +type + TFieldsCtx = object + c: PContext + m: TMagic + +proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = + case typ.kind + of nkSym: + var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid + fc.field = typ.sym + fc.replaceByFieldName = c.m == mFieldPairs + openScope(c.c) + inc c.c.inUnrolledContext + let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) + father.add(semStmt(c.c, body)) + dec c.c.inUnrolledContext + closeScope(c.c) + of nkNilLit: discard + of nkRecCase: + let L = forLoop.len + let call = forLoop.sons[L-2] + if call.len > 2: + localError(forLoop.info, errGenerated, + "parallel 'fields' iterator does not work for 'case' objects") + return + # iterate over the selector: + semForObjectFields(c, typ[0], forLoop, father) + # we need to generate a case statement: + var caseStmt = newNodeI(nkCaseStmt, forLoop.info) + # generate selector: + var access = newNodeI(nkDotExpr, forLoop.info, 2) + access.sons[0] = call.sons[1] + access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info) + caseStmt.add(semExprWithType(c.c, access)) + # copy the branches over, but replace the fields with the for loop body: + for i in 1 .. <typ.len: + var branch = copyTree(typ[i]) + let L = branch.len + branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info) + semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1]) + caseStmt.add(branch) + father.add(caseStmt) + of nkRecList: + for t in items(typ): semForObjectFields(c, t, forLoop, father) + else: + illFormedAst(typ) + +proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = + # so that 'break' etc. work as expected, we produce + # a 'while true: stmt; break' loop ... + result = newNodeI(nkWhileStmt, n.info, 2) + var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true") + if trueSymbol == nil: + localError(n.info, errSystemNeeds, "true") + trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info) + trueSymbol.typ = getSysType(tyBool) + + result.sons[0] = newSymNode(trueSymbol, n.info) + var stmts = newNodeI(nkStmtList, n.info) + result.sons[1] = stmts + + var length = sonsLen(n) + var call = n.sons[length-2] + if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs): + localError(n.info, errWrongNumberOfVariables) + return result + + var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc}) + if tupleTypeA.kind notin {tyTuple, tyObject}: + localError(n.info, errGenerated, "no object or tuple type") + return result + for i in 1..call.len-1: + var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc}) + if not sameType(tupleTypeA, tupleTypeB): + typeMismatch(call.sons[i], tupleTypeA, tupleTypeB) + + inc(c.p.nestedLoopCounter) + if tupleTypeA.kind == tyTuple: + var loopBody = n.sons[length-1] + for i in 0..sonsLen(tupleTypeA)-1: + openScope(c) + var fc: TFieldInstCtx + fc.tupleType = tupleTypeA + fc.tupleIndex = i + fc.replaceByFieldName = m == mFieldPairs + var body = instFieldLoopBody(fc, loopBody, n) + inc c.inUnrolledContext + stmts.add(semStmt(c, body)) + dec c.inUnrolledContext + closeScope(c) + else: + var fc: TFieldsCtx + fc.m = m + fc.c = c + semForObjectFields(fc, tupleTypeA.n, n, stmts) + dec(c.p.nestedLoopCounter) + # for TR macros this 'while true: ...; break' loop is pretty bad, so + # we avoid it now if we can: + if hasSonWith(stmts, nkBreakStmt): + var b = newNodeI(nkBreakStmt, n.info) + b.add(ast.emptyNode) + stmts.add(b) + else: + result = stmts diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c67fdb0f9..ab1c47e68 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -465,153 +465,7 @@ proc semConst(c: PContext, n: PNode): PNode = addSon(b, copyTree(def)) addSon(result, b) -type - TFieldInstCtx = object # either 'tup[i]' or 'field' is valid - tupleType: PType # if != nil we're traversing a tuple - tupleIndex: int - field: PSym - replaceByFieldName: bool - -proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode = - case n.kind - of nkEmpty..pred(nkIdent), succ(nkIdent)..nkNilLit: result = n - of nkIdent: - result = n - var L = sonsLen(forLoop) - if c.replaceByFieldName: - if n.ident.id == forLoop[0].ident.id: - let fieldName = if c.tupleType.isNil: c.field.name.s - elif c.tupleType.n.isNil: "Field" & $c.tupleIndex - else: c.tupleType.n.sons[c.tupleIndex].sym.name.s - result = newStrNode(nkStrLit, fieldName) - return - # other fields: - for i in ord(c.replaceByFieldName)..L-3: - if n.ident.id == forLoop[i].ident.id: - var call = forLoop.sons[L-2] - var tupl = call.sons[i+1-ord(c.replaceByFieldName)] - if c.field.isNil: - result = newNodeI(nkBracketExpr, n.info) - result.add(tupl) - result.add(newIntNode(nkIntLit, c.tupleIndex)) - else: - result = newNodeI(nkDotExpr, n.info) - result.add(tupl) - result.add(newSymNode(c.field, n.info)) - break - else: - if n.kind == nkContinueStmt: - localError(n.info, errGenerated, - "'continue' not supported in a 'fields' loop") - result = copyNode(n) - newSons(result, sonsLen(n)) - for i in countup(0, sonsLen(n)-1): - result.sons[i] = instFieldLoopBody(c, n.sons[i], forLoop) - -type - TFieldsCtx = object - c: PContext - m: TMagic - -proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) = - case typ.kind - of nkSym: - var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid - fc.field = typ.sym - fc.replaceByFieldName = c.m == mFieldPairs - openScope(c.c) - inc c.c.inUnrolledContext - let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop) - father.add(semStmt(c.c, body)) - dec c.c.inUnrolledContext - closeScope(c.c) - of nkNilLit: discard - of nkRecCase: - let L = forLoop.len - let call = forLoop.sons[L-2] - if call.len > 2: - localError(forLoop.info, errGenerated, - "parallel 'fields' iterator does not work for 'case' objects") - return - # iterate over the selector: - semForObjectFields(c, typ[0], forLoop, father) - # we need to generate a case statement: - var caseStmt = newNodeI(nkCaseStmt, forLoop.info) - # generate selector: - var access = newNodeI(nkDotExpr, forLoop.info, 2) - access.sons[0] = call.sons[1] - access.sons[1] = newSymNode(typ.sons[0].sym, forLoop.info) - caseStmt.add(semExprWithType(c.c, access)) - # copy the branches over, but replace the fields with the for loop body: - for i in 1 .. <typ.len: - var branch = copyTree(typ[i]) - let L = branch.len - branch.sons[L-1] = newNodeI(nkStmtList, forLoop.info) - semForObjectFields(c, typ[i].lastSon, forLoop, branch[L-1]) - caseStmt.add(branch) - father.add(caseStmt) - of nkRecList: - for t in items(typ): semForObjectFields(c, t, forLoop, father) - else: - illFormedAst(typ) - -proc semForFields(c: PContext, n: PNode, m: TMagic): PNode = - # so that 'break' etc. work as expected, we produce - # a 'while true: stmt; break' loop ... - result = newNodeI(nkWhileStmt, n.info, 2) - var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true") - if trueSymbol == nil: - localError(n.info, errSystemNeeds, "true") - trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(), n.info) - trueSymbol.typ = getSysType(tyBool) - - result.sons[0] = newSymNode(trueSymbol, n.info) - var stmts = newNodeI(nkStmtList, n.info) - result.sons[1] = stmts - - var length = sonsLen(n) - var call = n.sons[length-2] - if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs): - localError(n.info, errWrongNumberOfVariables) - return result - - var tupleTypeA = skipTypes(call.sons[1].typ, abstractVar-{tyTypeDesc}) - if tupleTypeA.kind notin {tyTuple, tyObject}: - localError(n.info, errGenerated, "no object or tuple type") - return result - for i in 1..call.len-1: - var tupleTypeB = skipTypes(call.sons[i].typ, abstractVar-{tyTypeDesc}) - if not sameType(tupleTypeA, tupleTypeB): - typeMismatch(call.sons[i], tupleTypeA, tupleTypeB) - - inc(c.p.nestedLoopCounter) - if tupleTypeA.kind == tyTuple: - var loopBody = n.sons[length-1] - for i in 0..sonsLen(tupleTypeA)-1: - openScope(c) - var fc: TFieldInstCtx - fc.tupleType = tupleTypeA - fc.tupleIndex = i - fc.replaceByFieldName = m == mFieldPairs - var body = instFieldLoopBody(fc, loopBody, n) - inc c.inUnrolledContext - stmts.add(semStmt(c, body)) - dec c.inUnrolledContext - closeScope(c) - else: - var fc: TFieldsCtx - fc.m = m - fc.c = c - semForObjectFields(fc, tupleTypeA.n, n, stmts) - dec(c.p.nestedLoopCounter) - # for TR macros this 'while true: ...; break' loop is pretty bad, so - # we avoid it now if we can: - if hasSonWith(stmts, nkBreakStmt): - var b = newNodeI(nkBreakStmt, n.info) - b.add(ast.emptyNode) - stmts.add(b) - else: - result = stmts +include semfields proc addForVarDecl(c: PContext, v: PSym) = if warnShadowIdent in gNotes: |