summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorenurlyx <enurlyx@gmail.com>2014-05-31 16:02:15 +0200
committerenurlyx <enurlyx@gmail.com>2014-05-31 16:02:15 +0200
commit33eeb66ea276a532782464638aff6d001fbef4de (patch)
tree5442e7a4a0d99b14935f1da1742a6a14863fe6b8
parent1bb0bdec246dbc9ed3bc967ca4e1e70b6fbb35bd (diff)
downloadNim-33eeb66ea276a532782464638aff6d001fbef4de.tar.gz
Add support for structs/unions defined in structs/unions
-rw-r--r--compiler/c2nim/cparse.nim134
1 files changed, 100 insertions, 34 deletions
diff --git a/compiler/c2nim/cparse.nim b/compiler/c2nim/cparse.nim
index 52d50ca39..09b2c01f1 100644
--- a/compiler/c2nim/cparse.nim
+++ b/compiler/c2nim/cparse.nim
@@ -19,7 +19,7 @@
 
 import 
   os, llstream, renderer, clex, idents, strutils, pegs, ast, astalgo, msgs,
-  options, strtabs
+  options, strtabs, times
 
 type 
   TParserFlag = enum
@@ -63,6 +63,15 @@ type
 
   ERetryParsing = object of ESynch
 
+
+
+proc addTypeDef(section, name, t: PNode)
+proc parseStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode
+proc parseStructBody(p: var TParser, stmtList: PNode, isUnion: bool,
+                     kind: TNodeKind = nkRecList): PNode
+
+
+
 proc newParserOptions*(): PParserOptions = 
   new(result)
   result.prefixes = @[]
@@ -682,12 +691,78 @@ proc parseField(p: var TParser, kind: TNodeKind): PNode =
     else: result = mangledIdent(p.tok.s, p)
     getTok(p, result)
 
-proc parseStructBody(p: var TParser, isUnion: bool,
+proc getNewModuleWideId(): int =
+  var id {.global.} = 0
+  id.inc
+  id
+
+proc structPragmas(p: TParser, name: PNode, origName: string): PNode = 
+  assert name.kind == nkIdent
+  result = newNodeP(nkPragmaExpr, p)
+  addSon(result, exportSym(p, name, origName))
+  var pragmas = newNodeP(nkPragma, p)
+  #addSon(pragmas, newIdentNodeP("pure", p), newIdentNodeP("final", p))
+  if p.options.header.len > 0:
+    addSon(pragmas, newIdentStrLitPair("importc", origName, p),
+                    newIdentStrLitPair("header", p.options.header, p))
+  if pragmas.len > 0: addSon(result, pragmas)
+  else: addSon(result, ast.emptyNode)
+
+proc parseInnerStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode =
+  getTok(p, nil)
+  if p.tok.xkind != pxCurlyLe:
+    parMessage(p, errUser, "Expected '{' but found '" & $(p.tok[]) & "'")
+  
+  let time = getTime().int
+  let id = getNewModuleWideId()
+  let structName =  if isUnion: "INNER_C_UNION_" & $time & "_" & $id
+                    else: "INNER_C_STRUCT_" & $time & "_" & $id
+  let typeSection = newNodeP(nkTypeSection, p)
+  let newStruct = newNodeP(nkObjectTy, p)
+  var pragmas = ast.emptyNode
+  if isUnion:
+    pragmas = newNodeP(nkPragma, p)
+    addSon(pragmas, newIdentNodeP("union", p))
+  addSon(newStruct, pragmas, ast.emptyNode) # no inheritance 
+  result = newNodeP(nkIdent, p)
+  result.ident = getIdent(structName)
+  let struct = parseStructBody(p, stmtList, isUnion)
+  let defName = newNodeP(nkIdent, p)
+  defName.ident = getIdent(structName)
+  addSon(newStruct, struct)
+  addTypeDef(typeSection, structPragmas(p, defName, "no_name"), newStruct)
+  addSon(stmtList, typeSection)
+
+proc parseStructBody(p: var TParser, stmtList: PNode, isUnion: bool,
                      kind: TNodeKind = nkRecList): PNode =
   result = newNodeP(kind, p)
   eat(p, pxCurlyLe, result)
   while p.tok.xkind notin {pxEof, pxCurlyRi}:
-    var baseTyp = typeAtom(p)
+    skipConst(p)
+    var baseTyp: PNode
+    if p.tok.xkind == pxSymbol and (p.tok.s == "struct" or p.tok.s == "union"):
+      let gotUnion = if p.tok.s == "union": true   else: false
+      saveContext(p)
+      getTok(p, nil)
+      if p.tok.xkind == pxSymbol:
+        backtrackContext(p)
+        baseTyp = typeAtom(p)
+      else:
+        backtrackContext(p)
+        baseTyp = parseInnerStruct(p, stmtList, gotUnion)
+        if p.tok.xkind == pxSemiColon:
+          let id = getNewModuleWideId()
+          let def = newNodeP(nkIdentDefs, p)
+          var t = pointer(p, baseTyp)
+          let i = fieldIdent("ano_" & $id, p)
+          t = parseTypeSuffix(p, t)
+          addSon(def, i, t, ast.emptyNode)
+          addSon(result, def)
+          getTok(p, nil)
+          continue
+    else:
+      baseTyp = typeAtom(p)
+    
     while true:
       var def = newNodeP(nkIdentDefs, p)
       var t = pointer(p, baseTyp)
@@ -700,18 +775,6 @@ proc parseStructBody(p: var TParser, isUnion: bool,
     eat(p, pxSemicolon, lastSon(result))
   eat(p, pxCurlyRi, result)
 
-proc structPragmas(p: TParser, name: PNode, origName: string): PNode = 
-  assert name.kind == nkIdent
-  result = newNodeP(nkPragmaExpr, p)
-  addSon(result, exportSym(p, name, origName))
-  var pragmas = newNodeP(nkPragma, p)
-  #addSon(pragmas, newIdentNodeP("pure", p), newIdentNodeP("final", p))
-  if p.options.header.len > 0:
-    addSon(pragmas, newIdentStrLitPair("importc", origName, p),
-                    newIdentStrLitPair("header", p.options.header, p))
-  if pragmas.len > 0: addSon(result, pragmas)
-  else: addSon(result, ast.emptyNode)
-
 proc enumPragmas(p: TParser, name: PNode): PNode =
   result = newNodeP(nkPragmaExpr, p)
   addSon(result, name)
@@ -722,7 +785,7 @@ proc enumPragmas(p: TParser, name: PNode): PNode =
   addSon(pragmas, e)
   addSon(result, pragmas)
 
-proc parseStruct(p: var TParser, isUnion: bool): PNode =
+proc parseStruct(p: var TParser, stmtList: PNode, isUnion: bool): PNode =
   result = newNodeP(nkObjectTy, p)
   var pragmas = ast.emptyNode
   if isUnion:
@@ -730,7 +793,7 @@ proc parseStruct(p: var TParser, isUnion: bool): PNode =
     addSon(pragmas, newIdentNodeP("union", p))
   addSon(result, pragmas, ast.emptyNode) # no inheritance 
   if p.tok.xkind == pxCurlyLe:
-    addSon(result, parseStructBody(p, isUnion))
+    addSon(result, parseStructBody(p, stmtList, isUnion))
   else: 
     addSon(result, newNodeP(nkRecList, p))
 
@@ -874,10 +937,10 @@ proc enumFields(p: var TParser): PNode =
     # allow trailing comma:
     if p.tok.xkind == pxCurlyRi: break
 
-proc parseTypedefStruct(p: var TParser, result: PNode, isUnion: bool) = 
+proc parseTypedefStruct(p: var TParser, result: PNode, stmtList: PNode, isUnion: bool) = 
   getTok(p, result)
   if p.tok.xkind == pxCurlyLe:
-    var t = parseStruct(p, isUnion)
+    var t = parseStruct(p, stmtList, isUnion)
     var origName = p.tok.s
     markTypeIdent(p, nil)
     var name = skipIdent(p)
@@ -890,7 +953,7 @@ proc parseTypedefStruct(p: var TParser, result: PNode, isUnion: bool) =
     var nameOrType = skipIdent(p)
     case p.tok.xkind 
     of pxCurlyLe:
-      var t = parseStruct(p, isUnion)
+      var t = parseStruct(p, stmtList, isUnion)
       if p.tok.xkind == pxSymbol: 
         # typedef struct tagABC {} abc, *pabc;
         # --> abc is a better type name than tagABC!
@@ -960,27 +1023,30 @@ proc parseTypedefEnum(p: var TParser, result: PNode) =
     expectIdent(p)
 
 proc parseTypeDef(p: var TParser): PNode =  
-  result = newNodeP(nkTypeSection, p)
+  result = newNodeP(nkStmtList, p)
+  var typeSection = newNodeP(nkTypeSection, p)
   while p.tok.xkind == pxSymbol and p.tok.s == "typedef":
-    getTok(p, result)
+    getTok(p, typeSection)
     inc(p.inTypeDef)
     expectIdent(p)
     case p.tok.s
-    of "struct": parseTypedefStruct(p, result, isUnion=false)
-    of "union": parseTypedefStruct(p, result, isUnion=true)
-    of "enum": parseTypedefEnum(p, result)
+    of "struct": parseTypedefStruct(p, typeSection, result, isUnion=false)
+    of "union": parseTypedefStruct(p, typeSection, result, isUnion=true)
+    of "enum": parseTypedefEnum(p, typeSection)
     of "class":
       if pfCpp in p.options.flags:
-        parseTypedefStruct(p, result, isUnion=false)
+        parseTypedefStruct(p, typeSection, result, isUnion=false)
       else:
         var t = typeAtom(p)
-        otherTypeDef(p, result, t)
+        otherTypeDef(p, typeSection, t)
     else: 
       var t = typeAtom(p)
-      otherTypeDef(p, result, t)
+      otherTypeDef(p, typeSection, t)
     eat(p, pxSemicolon)
     dec(p.inTypeDef)
-    
+  
+  addSon(result, typeSection)
+  
 proc skipDeclarationSpecifiers(p: var TParser) =
   while p.tok.xkind == pxSymbol:
     case p.tok.s
@@ -1608,8 +1674,8 @@ proc declarationOrStatement(p: var TParser): PNode =
       result = expressionStatement(p)
   assert result != nil
 
-proc parseTuple(p: var TParser, isUnion: bool): PNode = 
-  result = parseStructBody(p, isUnion, nkTupleTy)
+proc parseTuple(p: var TParser, statements: PNode, isUnion: bool): PNode = 
+  parseStructBody(p, statements, isUnion, nkTupleTy)
 
 proc parseTrailingDefinedIdents(p: var TParser, result, baseTyp: PNode) =
   var varSection = newNodeP(nkVarSection, p)
@@ -1640,13 +1706,13 @@ proc parseStandaloneStruct(p: var TParser, isUnion: bool): PNode =
   if p.tok.xkind in {pxCurlyLe, pxSemiColon}:
     if origName.len > 0: 
       var name = mangledIdent(origName, p)
-      var t = parseStruct(p, isUnion)
+      var t = parseStruct(p, result, isUnion)
       var typeSection = newNodeP(nkTypeSection, p)
       addTypeDef(typeSection, structPragmas(p, name, origName), t)
       addSon(result, typeSection)
       parseTrailingDefinedIdents(p, result, name)
     else:
-      var t = parseTuple(p, isUnion)
+      var t = parseTuple(p, result, isUnion)
       parseTrailingDefinedIdents(p, result, t)
   else:
     backtrackContext(p)
@@ -2034,7 +2100,7 @@ proc parseStandaloneClass(p: var TParser, isStruct: bool): PNode =
       addTypeDef(typeSection, structPragmas(p, name, origName), t)
       parseTrailingDefinedIdents(p, result, name)
     else:
-      var t = parseTuple(p, isUnion=false)
+      var t = parseTuple(p, result, isUnion=false)
       parseTrailingDefinedIdents(p, result, t)
   else:
     backtrackContext(p)