summary refs log tree commit diff stats
path: root/tests/vm/meta.nim
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2016-05-29 21:01:15 +0200
committerAndreas Rumpf <rumpf_a@web.de>2016-05-29 21:01:15 +0200
commit552b13efe4d65c2381d74d4fcaf9237a8730db1c (patch)
treeefd07f0663f676a02e04ebcedb23e20b3cbef6ae /tests/vm/meta.nim
parente65c89ee28a8b03e00f5dba9ff181918764d72c0 (diff)
downloadNim-552b13efe4d65c2381d74d4fcaf9237a8730db1c.tar.gz
fixes #3729
Diffstat (limited to 'tests/vm/meta.nim')
-rw-r--r--tests/vm/meta.nim240
1 files changed, 240 insertions, 0 deletions
diff --git a/tests/vm/meta.nim b/tests/vm/meta.nim
new file mode 100644
index 000000000..2aa01b5b3
--- /dev/null
+++ b/tests/vm/meta.nim
@@ -0,0 +1,240 @@
+#
+# meta.nim
+#
+
+import tables
+import macros
+
+type
+  NodeSeq* = seq[NimNode]
+  Ident* = tuple[name: string, exported: bool]
+  Bracket* = seq[Ident]
+  Field* = tuple[identifier: Ident, type_name: string, default: string]
+  FieldSeq* = seq[Field]
+  TypeDef* = object
+    identifier*: Ident
+    fields*: FieldSeq
+    is_ref*: bool
+    object_type*: string
+    base_type*: string
+  TypeDefSeq* = seq[TypeDef]
+  Proc* = tuple[identifier: Ident, params: FieldSeq,
+                returns: Ident, generics: FieldSeq, body: NimNode]
+  ProcSeq* = seq[Proc]
+
+# Ident procs
+proc newIdent*(name: string, exported = false): Ident =
+  result.name = name
+  result.exported = exported
+
+proc newIdent*(node: NimNode): Ident =
+  case node.kind:
+    of nnkPostfix:
+      result = newIdent(node[1])
+      result.exported = true
+    of nnkIdent, nnkSym:
+      result.name = $(node)
+    else:
+      let msg = "newIdent cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(i: Ident): NimNode {.compileTime.} =
+  if i.name == nil:
+    return newNimNode(nnkEmpty)
+
+  if i.exported:
+    result = newNimNode(nnkPostfix)
+    result.add(ident "*")
+    result.add(ident i.name)
+  else:
+    result = ident i.name
+
+proc `$`*(identifier: Ident): string = identifier.name
+
+converter toString*(x: Ident): string = x.name
+
+proc newBracket*(node: NimNode): Bracket =
+  result = @[]
+  case node.kind:
+    of nnkBracket:
+      for child in node:
+        if child.kind != nnkIdent:
+          let msg = "Bracket members can only be nnkIdent not kind: " & $(node.kind)
+          raise newException(ValueError, msg)
+        result.add(newIdent(child))
+    else:
+      let msg = "newBracket must initialize from node kind nnkBracket not: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+# Field procs
+proc newField*(identifier: Ident, type_name: string, default: string = nil): Field =
+  result.identifier = identifier
+  result.type_name = type_name
+  result.default = default
+
+proc newField*(node: NimNode): Field =
+  case node.kind:
+    of nnkIdentDefs:
+      if node.len > 3:
+        let msg = "newField cannot initialize from nnkIdentDefs with multiple names"
+        raise newException(ValueError, msg)
+      result.identifier = newIdent(node[0])
+      result.type_name = $(node[1])
+      case node[2].kind:
+        of nnkIdent:
+          result.default = $(node[2])
+        else:
+          result.default = nil
+    else:
+      let msg = "newField cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+# FieldSeq procs
+proc newFieldSeq*(node: NimNode): FieldSeq =
+  result = @[]
+  case node.kind:
+    of nnkIdentDefs:
+      let
+        type_name = $(node[node.len - 2])
+        default_node = node[node.len - 1]
+      var default: string
+      case default_node.kind:
+        of nnkIdent:
+          default = $(default_node)
+        else:
+          default = nil
+      for i in 0..node.len - 3:
+        let name = newIdent(node[i])
+        result.add(newField(name, type_name, default))
+    of nnkRecList, nnkVarSection, nnkGenericParams:
+      for child in node:
+        result = result & newFieldSeq(child)
+    else:
+      let msg = "newFieldSeq cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(f: Field): NimNode {.compileTime.} =
+  let identifier = f.identifier.render()
+  let type_name = if f.type_name != nil: ident(f.type_name) else: newEmptyNode()
+  let default = if f.default != nil: ident(f.default) else: newEmptyNode()
+  newIdentDefs(identifier, type_name, default)
+
+proc render*(fs: FieldSeq): NimNode {.compileTime.} =
+  result = newNimNode(nnkRecList)
+  for field in fs:
+    result.add(field.render())
+
+# TypeDef procs
+proc newTypeDef*(identifier: Ident, is_ref = false,
+                object_type = "object",
+                base_type: string = nil): TypeDef {.compileTime.} =
+  result.identifier = identifier
+  result.fields = @[]
+  result.is_ref = is_ref
+  result.object_type = "object"
+  result.base_type = base_type
+
+proc newTypeDef*(node: NimNode): TypeDef {.compileTime.} =
+  case node.kind:
+    of nnkTypeDef:
+      result.identifier = newIdent($(node[0]))
+      var object_node: NimNode
+      case node[2].kind:
+        of nnkRefTy:
+          object_node = node[2][0]
+          result.is_ref = true
+        of nnkObjectTy:
+          object_node = node[2]
+          result.is_ref = false
+        else:
+          let msg = "newTypeDef could not parse RefTy/ObjectTy, found: " & $(node[2].kind)
+          raise newException(ValueError, msg)
+      case object_node[1].kind:
+        of nnkOfInherit:
+          result.base_type = $(object_node[1][0])
+        else:
+          result.base_type = "object"
+      result.fields = newFieldSeq(object_node[2])
+    else:
+      let msg = "newTypeDef cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(typedef: TypeDef): NimNode {.compileTime.} =
+  result = newNimNode(nnkTypeDef)
+  result.add(typedef.identifier.render)
+  result.add(newEmptyNode())
+  let object_node = newNimNode(nnkObjectTy)
+  object_node.add(newEmptyNode())
+  if typedef.base_type == nil:
+    object_node.add(newEmptyNode())
+  else:
+    var base_type = newNimNode(nnkOfInherit)
+    base_type.add(ident(typedef.base_type))
+    object_node.add(base_type)
+  let fields = typedef.fields.render()
+  object_node.add(fields)
+  if typedef.is_ref:
+    let ref_node = newNimNode(nnkRefTy)
+    ref_node.add(object_node)
+    result.add(ref_node)
+  else:
+    result.add(object_node)
+
+proc newTypeDefSeq*(node: NimNode): TypeDefSeq =
+  result = @[]
+  case node.kind:
+    of nnkTypeSection:
+      for child in node:
+        result.add(newTypeDef(child))
+    else:
+      let msg = "newTypeSection could not parse TypeDef, found: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(typeseq: TypeDefSeq): NimNode {.compileTime.} =
+  result = newNimNode(nnkTypeSection)
+  for typedef in typeseq:
+    result.add(typedef.render())
+
+proc newProc*(identifier: Ident, params: FieldSeq = nil,
+              returns: Ident, generics: FieldSeq = nil): Proc =
+  result.identifier = identifier
+  result.params = params
+  result.returns = returns
+  result.generics = generics
+
+proc newProc*(node: NimNode): Proc =
+  case node.kind:
+    of nnkProcDef, nnkMethodDef:
+      result.identifier = newIdent(node[0])
+      case node[2].kind:
+        of nnkGenericParams:
+          result.generics = newFieldSeq(node[2])
+        else: result.generics = nil
+      let formal_params = node[3]
+      case formal_params[0].kind:
+        of nnkIdent:
+          result.returns = newIdent(formal_params[0])
+        else: discard
+      result.params = @[]
+      for i in 1..formal_params.len - 1:
+        let param = formal_params[i]
+        for field in newFieldSeq(param):
+          result.params.add(field)
+      result.body = node[6]
+    else:
+      let msg = "newProc cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(procdef: Proc): NimNode {.compileTime.} =
+  result = newNimNode(nnkProcDef)
+  result.add(procdef.identifier.render())
+  result.add(newEmptyNode())
+  result.add(newEmptyNode())
+  let formal_params = newNimNode(nnkFormalParams)
+  formal_params.add(procdef.returns.render())
+  for param in procdef.params:
+    formal_params.add(param.render())
+  result.add(formal_params)
+  result.add(newEmptyNode())
+  result.add(newEmptyNode())
+  result.add(procdef.body)