I am trying to use macro for automatic initializer proc generation, here is the 
code
    
    
    func typeMap(k: JsonNodeKind): string =
      case k:
      of JBool: "bool"
      of JInt: "int"
      of JFloat: "float"
      of JString: "string"
      else:
        error("Unsupported json kind: " & $k)
    
    func nodeMap(j: JsonNode): NimNode =
      case j.kind
      of JNull:
        result = newNilLit()
      of JBool:
        result = newLit(j.getBool())
      of JInt:
        result = newLit(j.getInt())
      of JFloat:
        result = newLit(j.getFloat())
      of JString:
        result = newLit(j.getStr())
      else:
        error("Unsupported json kind: " & $j)
    
    macro TABLE_FROM_JSON*(json: static string, name: untyped): untyped =
      result = newStmtList()
      
      let fields = parseJson(json).getFields().pairs.toSeq()
      
      let fieldsAst = nnkRecList.newTree(
        fields.mapIt(
          nnkIdentDefs.newTree(
            newTree(nnkPostfix, newIdentNode("*"), newIdentNode($it[0])),
            ident typeMap(it[1].kind),
            newEmptyNode()
          )
        )
      )
      
      
      
      # Generate the base type
      let baseType = newTree(nnkTypeSection,
        newTree(nnkTypeDef,
          newTree(nnkPostfix,
            newIdentNode("*"),
            newTree(nnkAccQuoted, name)
          ),
          newEmptyNode(),
          newTree(nnkObjectTy,
            newEmptyNode(),
            newEmptyNode(),
            # # Replace the specific AST with a generic one :
            fieldsAst
          )
        )
      )
      result.add(baseType)
      
      # Generate the table type
      let tableType = newTree(nnkTypeSection,
        newTree(nnkTypeDef,
          newTree(nnkPostfix,
            newIdentNode("*"),
            newTree(nnkAccQuoted,
              name,
              newIdentNode("Table")
            )
          ),
          newEmptyNode(),
          newTree(nnkObjectTy,
            newEmptyNode(),
            newEmptyNode(),
            newTree(nnkRecList,
              newTree(nnkIdentDefs,
                newTree(nnkPostfix, newIdentNode("*"), newIdentNode("list")),
                newTree(nnkBracketExpr,
                  newIdentNode("seq"),
                  newTree(nnkAccQuoted, name)
                ),
                newEmptyNode()
              )
            )
          )
        )
      )
      result.add(tableType)
     
     
     
     let InitStmt = newStmtList(
        newCall(
          newDotExpr(
            newDotExpr(newIdentNode("result"), newIdentNode("list")),
            newIdentNode("add")
          ),
          newTree(nnkObjConstr,
            newIdentNode(strVal(name)),
            
            # This way make Error: incorrect object construction syntax
            # nnkArgList.newColonExpr(
            #   fields.mapIt(
            #     newIdentNode($it[0]), nodeMap(it[1])
            #   )
            # )
            
            # working Example
            newColonExpr(newIdentNode("name"), newLit("Alice")),
            newColonExpr(newIdentNode("age"), newLit(30)),
            newColonExpr(newIdentNode("address"), newLit("23 Main St"))
          )
        )
      )
      
      let tableInit = newProc(
        name = newTree(nnkPostfix, newIdentNode("*"), newTree(nnkAccQuoted, 
newIdentNode("new") , name , newIdentNode("Table"))),
        # name = newIdentNode("newPersonTable"),
        # params = [newIdentNode("PersonTable")],
        params = [newTree(nnkAccQuoted, name , newIdentNode("Table"))],
        
        body = InitStmt
      
      )
      
      result.add(tableInit)
    
    
    Run

here is test code
    
    
    const exampleDataStr = """{"name": "JK", "age": 30, "address": "Tokyo"}"""
    
    
    TABLE_FROM_JSON(exampleDataStr, Person)
    
    
    var pt = newPersonTable()
    
    for p in pt.list:
        echo p.name, " is ", p.age, " years old and lives at ", p.address
    
    
    
    
    Run

Reply via email to