configurator.nim 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import macros
  2. proc createRefType(ident: NimIdent, identDefs: seq[NimNode]): NimNode =
  3. result = newTree(nnkTypeSection,
  4. newTree(nnkTypeDef,
  5. newIdentNode(ident),
  6. newEmptyNode(),
  7. newTree(nnkRefTy,
  8. newTree(nnkObjectTy,
  9. newEmptyNode(),
  10. newEmptyNode(),
  11. newTree(nnkRecList,
  12. identDefs
  13. )
  14. )
  15. )
  16. )
  17. )
  18. proc toIdentDefs(stmtList: NimNode): seq[NimNode] =
  19. expectKind(stmtList, nnkStmtList)
  20. result = @[]
  21. for child in stmtList:
  22. expectKind(child, nnkCall)
  23. result.add(newIdentDefs(child[0], child[1][0]))
  24. template constructor(ident: untyped): untyped =
  25. proc `new ident`(): `ident` =
  26. new result
  27. proc createLoadProc(typeName: NimIdent, identDefs: seq[NimNode]): NimNode =
  28. var cfgIdent = newIdentNode("cfg")
  29. var filenameIdent = newIdentNode("filename")
  30. var objIdent = newIdentNode("obj")
  31. var body = newStmtList()
  32. body.add quote do:
  33. var `objIdent` = parseFile(`filenameIdent`)
  34. for identDef in identDefs:
  35. let fieldNameIdent = identDef[0]
  36. let fieldName = $fieldNameIdent.ident
  37. case $identDef[1].ident
  38. of "string":
  39. body.add quote do:
  40. `cfgIdent`.`fieldNameIdent` = `objIdent`[`fieldName`].getStr
  41. of "int":
  42. body.add quote do:
  43. `cfgIdent`.`fieldNameIdent` = `objIdent`[`fieldName`].getNum().int
  44. else:
  45. doAssert(false, "Not Implemented")
  46. return newProc(newIdentNode("load"),
  47. [newEmptyNode(),
  48. newIdentDefs(cfgIdent, newIdentNode(typeName)),
  49. newIdentDefs(filenameIdent, newIdentNode("string"))],
  50. body)
  51. macro config*(typeName: untyped, fields: untyped): untyped =
  52. result = newStmtList()
  53. let identDefs = toIdentDefs(fields)
  54. result.add createRefType(typeName.ident, identDefs)
  55. result.add getAst(constructor(typeName.ident))
  56. result.add createLoadProc(typeName.ident, identDefs)
  57. echo treeRepr(typeName)
  58. echo treeRepr(fields)
  59. echo treeRepr(result)
  60. echo toStrLit(result)
  61. # TODO: Verify that we can export fields in config type so that it can be
  62. # used in another module.
  63. import json
  64. config MyAppConfig:
  65. address: string
  66. port: int
  67. var myConf = newMyAppConfig()
  68. myConf.load("myappconfig.cfg")
  69. echo("Address: ", myConf.address)
  70. echo("Port: ", myConf.port)