Add JSON encoding for serializing package and AST nodes

This commit is contained in:
joeduffy 2017-04-07 10:38:17 -07:00
parent f0535f0f00
commit 3c50ee8c84
2 changed files with 71 additions and 2 deletions

View file

@ -6,7 +6,7 @@
"""Coconut's Python compiler."""
import argparse
from cocopy.lib import compiler
from cocopy.lib import compiler, encoding
import json
import pythonparser
import sys
@ -16,7 +16,9 @@ parser.add_argument("file", help="CocoPy filename")
def main(args):
pkg = compiler.compile(args.file)
print(json.dumps(pkg.__dict__))
jsonobj = encoding.to_serializable(
pkg, skip_nones=True, key_mangler=encoding.underscore_to_camel_case)
print(json.dumps(jsonobj, indent=4))
if __name__ == "__main__":
sys.exit(main(parser.parse_args()))

View file

@ -0,0 +1,67 @@
# Copyright 2017 Pulumi, Inc. All rights reserved.
def underscore_to_camel_case(key):
# Quickly check to see if there is no _; in that case, just return the key as-is.
has = False
for c in key:
if c == "_":
has = True
break
if not has:
return key
# If there's an underscore, accumulate the contents into a buffer, swapping _s with camelCased strings.
new = ""
next_case = False
for c in key:
if c == "_" and new != "":
next_case = True # skip and capitalize the next character.
else:
if next_case:
c = c.upper()
next_case = False
new += c
return new
def to_serializable(obj, skip_nones=False, key_mangler=None):
"""
This routine converts an acyclic object graph into a dictionary of serializable attributes. This avoids needing to
do custom serialization. During this translation, name conversion can be performed, to ensure that, for instance,
`underscore_cased` names are transformed into `camelCased` names, if appropriate.
"""
return to_serializable_dict(obj.__dict__, skip_nones, key_mangler)
def to_serializable_dict(m, skip_nones=False, key_mangler=None):
"""This routine converts a simple dictionary into a JSON-serializable map."""
d = dict()
for attr in m:
v = to_serializable_value(m[attr], skip_nones)
if v is not None or not skip_nones:
key = attr
if key_mangler is not None:
key = key_mangler(key)
d[key] = v
return d
def to_serializable_value(v, skip_nones=False, key_mangler=None):
"""This routine converts a singular value into its JSON-serializable equivalent."""
if (isinstance(v, str) or isinstance(v, unicode) or
isinstance(v, int) or isinstance(v, long) or isinstance(v, float) or
isinstance(v, bool) or v is None):
# Simple serializable values can be stored without any translation.
return v
elif isinstance(v, list) or isinstance(v, set):
# For lists (or sets), just convert to a list of the values.
if isinstance(v, set):
v = list(v) # convert the set to a list.
a = list()
for e in v:
a.append(to_serializable_value(e, skip_nones))
return a
elif isinstance(v, dict):
# For a map, just recurse into the map routing above, which copies all key/values.
return to_serializable_dict(v, skip_nones)
else:
# For all others, assume it is an object, and serialize its keys directly.
return to_serializable(v, skip_nones)