summary refs log tree commit diff stats
path: root/compiler/semfields.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/semfields.nim')
-rw-r--r--compiler/semfields.nim118
1 files changed, 62 insertions, 56 deletions
diff --git a/compiler/semfields.nim b/compiler/semfields.nim
index 6002705b3..874055cdc 100644
--- a/compiler/semfields.nim
+++ b/compiler/semfields.nim
@@ -16,26 +16,29 @@ type
     tupleIndex: int
     field: PSym
     replaceByFieldName: bool
+    c: PContext
 
 proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
+  if c.field != nil and isEmptyType(c.field.typ):
+    result = newNode(nkEmpty)
+    return
   case n.kind
-  of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
+  of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = copyNode(n)
   of nkIdent, nkSym:
     result = n
-    let ident = considerQuotedIdent(n)
-    var L = sonsLen(forLoop)
+    let ident = considerQuotedIdent(c.c, n)
     if c.replaceByFieldName:
-      if ident.id == considerQuotedIdent(forLoop[0]).id:
+      if ident.id == considerQuotedIdent(c.c, forLoop[0]).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
+                        else: c.tupleType.n[c.tupleIndex].sym.name.s
         result = newStrNode(nkStrLit, fieldName)
         return
     # other fields:
-    for i in ord(c.replaceByFieldName)..L-3:
-      if ident.id == considerQuotedIdent(forLoop[i]).id:
-        var call = forLoop.sons[L-2]
-        var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
+    for i in ord(c.replaceByFieldName)..<forLoop.len-2:
+      if ident.id == considerQuotedIdent(c.c, forLoop[i]).id:
+        var call = forLoop[^2]
+        var tupl = call[i+1-ord(c.replaceByFieldName)]
         if c.field.isNil:
           result = newNodeI(nkBracketExpr, n.info)
           result.add(tupl)
@@ -47,12 +50,11 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
         break
   else:
     if n.kind == nkContinueStmt:
-      localError(n.info, errGenerated,
+      localError(c.c.config, n.info,
                  "'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)
+    result = shallowCopy(n)
+    for i in 0..<n.len:
+      result[i] = instFieldLoopBody(c, n[i], forLoop)
 
 type
   TFieldsCtx = object
@@ -62,21 +64,23 @@ type
 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
+    # either 'tup[i]' or 'field' is valid
+    var fc = TFieldInstCtx(
+      c: c.c,
+      field: typ.sym,
+      replaceByFieldName: c.m == mFieldPairs
+    )
     openScope(c.c)
     inc c.c.inUnrolledContext
     let body = instFieldLoopBody(fc, lastSon(forLoop), forLoop)
-    father.add(semStmt(c.c, body))
+    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]
+    let call = forLoop[^2]
     if call.len > 2:
-      localError(forLoop.info, errGenerated,
+      localError(c.c.config, forLoop.info,
                  "parallel 'fields' iterator does not work for 'case' objects")
       return
     # iterate over the selector:
@@ -85,81 +89,83 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
     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)
+    access[0] = call[1]
+    access[1] = newSymNode(typ[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:
+    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])
+      branch[^1] = newNodeI(nkStmtList, forLoop.info)
+      semForObjectFields(c, typ[i].lastSon, forLoop, branch[^1])
       caseStmt.add(branch)
     father.add(caseStmt)
   of nkRecList:
     for t in items(typ): semForObjectFields(c, t, forLoop, father)
   else:
-    illFormedAstLocal(typ)
+    illFormedAstLocal(typ, c.c.config)
 
 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")
+  var trueSymbol = systemModuleSym(c.graph, getIdent(c.cache, "true"))
   if trueSymbol == nil:
-    localError(n.info, errSystemNeeds, "true")
-    trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(c), n.info)
-    trueSymbol.typ = getSysType(tyBool)
+    localError(c.config, n.info, "system needs: 'true'")
+    trueSymbol = newSym(skUnknown, getIdent(c.cache, "true"), c.idgen, getCurrOwner(c), n.info)
+    trueSymbol.typ = getSysType(c.graph, n.info, tyBool)
 
-  result.sons[0] = newSymNode(trueSymbol, n.info)
+  result[0] = newSymNode(trueSymbol, n.info)
   var stmts = newNodeI(nkStmtList, n.info)
-  result.sons[1] = stmts
+  result[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)
+  var call = n[^2]
+  if n.len-2 != call.len-1 + ord(m==mFieldPairs):
+    localError(c.config, n.info, errWrongNumberOfVariables)
     return result
 
   const skippedTypesForFields = abstractVar - {tyTypeDesc} + tyUserTypeClasses
-  var tupleTypeA = skipTypes(call.sons[1].typ, skippedTypesForFields)
+  var tupleTypeA = skipTypes(call[1].typ, skippedTypesForFields)
   if tupleTypeA.kind notin {tyTuple, tyObject}:
-    localError(n.info, errGenerated, "no object or tuple type")
+    localError(c.config, n.info, errGenerated, "no object or tuple type")
     return result
-  for i in 1..call.len-1:
-    var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields)
+  for i in 1..<call.len:
+    let calli = call[i]
+    var tupleTypeB = skipTypes(calli.typ, skippedTypesForFields)
     if not sameType(tupleTypeA, tupleTypeB):
-      typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB)
+      typeMismatch(c.config, calli.info, tupleTypeA, tupleTypeB, calli)
 
   inc(c.p.nestedLoopCounter)
+  let oldBreakInLoop = c.p.breakInLoop
+  c.p.breakInLoop = true
   if tupleTypeA.kind == tyTuple:
-    var loopBody = n.sons[length-1]
-    for i in 0..sonsLen(tupleTypeA)-1:
+    var loopBody = n[^1]
+    for i in 0..<tupleTypeA.len:
       openScope(c)
-      var fc: TFieldInstCtx
-      fc.tupleType = tupleTypeA
-      fc.tupleIndex = i
-      fc.replaceByFieldName = m == mFieldPairs
+      var fc = TFieldInstCtx(
+          tupleType: tupleTypeA,
+          tupleIndex: i,
+          c: c,
+          replaceByFieldName: m == mFieldPairs
+      )
       var body = instFieldLoopBody(fc, loopBody, n)
       inc c.inUnrolledContext
-      stmts.add(semStmt(c, body))
+      stmts.add(semStmt(c, body, {}))
       dec c.inUnrolledContext
       closeScope(c)
   else:
-    var fc: TFieldsCtx
-    fc.m = m
-    fc.c = c
+    var fc = TFieldsCtx(m: m, c: c)
     var t = tupleTypeA
     while t.kind == tyObject:
       semForObjectFields(fc, t.n, n, stmts)
-      if t.sons[0] == nil: break
-      t = skipTypes(t.sons[0], skipPtrs)
+      if t.baseClass == nil: break
+      t = skipTypes(t.baseClass, skipPtrs)
+  c.p.breakInLoop = oldBreakInLoop
   dec(c.p.nestedLoopCounter)
   # for TR macros this 'while true: ...; break' loop is pretty bad, so
   # we avoid it now if we can:
   if containsNode(stmts, {nkBreakStmt}):
     var b = newNodeI(nkBreakStmt, n.info)
-    b.add(ast.emptyNode)
+    b.add(newNodeI(nkEmpty, n.info))
     stmts.add(b)
   else:
     result = stmts