Add JSON encoding for serializing package and AST nodes
This commit is contained in:
parent
f0535f0f00
commit
3c50ee8c84
2 changed files with 71 additions and 2 deletions
|
@ -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()))
|
||||
|
|
67
tools/cocopy/lib/encoding.py
Normal file
67
tools/cocopy/lib/encoding.py
Normal 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)
|
||||
|
Loading…
Reference in a new issue