VPPAPIGEN: vppapigen replacement in Python PLY.

This is a version of the VPP API generator in Python PLY. It supports
the existing language, and has a plugin architecture for generators.
Currently C and JSON are supported.

Changes:
 - vl_api_version to option version = "major.minor.patch"
 - enum support
 - Added error checking and reporting
 - import support (removed the C pre-processor)
 - services (tying request/reply together)

Version:
 option version = "1.0.0";

Enum:
 enum colours {
   RED,
   BLUE = 50,
 };
 define foo {
  vl_api_colours_t colours;
 };

Services:
 service {
  rpc foo returns foo_reply;
  rpc foo_dump returns stream foo_details;
  rpc want_stats returns want_stats_reply
      events ip4_counters, ip6_counters;
 };

Future planned features:
 - unions
 - bool, text
 - array support (including length)
 - proto3 output plugin
 - Refactor C/C++ generator as a plugin
 - Refactor Java generator as a plugin

Change-Id: Ifa289966c790e1b1a8e2938a91e69331e3a58bdf
Signed-off-by: Ole Troan <ot@cisco.com>
diff --git a/src/tools/vppapigen/JSON.py b/src/tools/vppapigen/JSON.py
new file mode 100644
index 0000000..d1f47eb
--- /dev/null
+++ b/src/tools/vppapigen/JSON.py
@@ -0,0 +1,66 @@
+# JSON generation
+import json
+
+
+def walk_enums(s):
+    r = []
+    for e in s:
+        d = []
+        d.append(e.name)
+        for b in e.block:
+            d.append(b)
+        d.append({'enumtype': e.enumtype})
+        r.append(d)
+    return r
+
+
+def walk_services(s):
+    r = []
+    for e in s:
+        d = {'reply': e.reply}
+        if e.stream:
+            d['stream'] = True
+        if e.events:
+            d['events'] = e.events
+        r.append({e.caller: d})
+    return r
+
+
+def walk_defs(s):
+    r = []
+    for t in s:
+        d = []
+        d.append(t.name)
+        for b in t.block:
+            f = []
+            if b.type == 'Field':
+                f = [b.fieldtype, b.fieldname]
+            elif b.type == 'Array':
+                if b.lengthfield:
+                    f = [b.fieldtype, b.fieldname, b.length, b.lengthfield]
+                else:
+                    f = [b.fieldtype, b.fieldname, b.length]
+            else:
+                raise ValueError("Error in processing array type %s" % b)
+            d.append(f)
+        if t.crc:
+            c = {}
+            c['crc'] = "{0:#0{1}x}".format(t.crc, 10)
+            d.append(c)
+
+        r.append(d)
+    return r
+
+
+#
+# Plugin entry point
+#
+def run(filename, s, file_crc):
+    j = {}
+
+    j['types'] = walk_defs(s['typedefs'])
+    j['messages'] = walk_defs(s['defines'])
+    j['enums'] = walk_enums(s['enums'])
+    j['services'] = walk_services(s['services'])
+    j['vl_api_version'] = hex(file_crc)
+    return json.dumps(j, indent=4, separators=(',', ': '))