Skip to content

Commit

Permalink
[JsonGen] Automatic object lookup (#140)
Browse files Browse the repository at this point in the history
* [JsonGen] Automatic object lookup

* Allow const methods on interfaces

* Update emitter.py

* amend documentation
  • Loading branch information
sebaszm authored Dec 27, 2024
1 parent b7224e1 commit fa28644
Show file tree
Hide file tree
Showing 6 changed files with 724 additions and 537 deletions.
18 changes: 13 additions & 5 deletions JsonGenerator/source/documentation_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,25 @@ def _TableObj(name, obj, parentName="", parent=None, prefix="", parentOptional=F

if d["type"] == "string" or is_buffer:
str_text = "Decoded data" if d.get("encode") else "String"
val_text = "bytes" if d.get("encode") else "chars"

if d["range"][0]:
row += italics("%s length must be in range [%s..%s] chars." % (str_text, d["range"][0], d["range"][1]))
row += italics("%s length must be in range [%s..%s] %s." % (str_text, d["range"][0], d["range"][1], val_text))
else:
row += italics("%s length must be at most %s chars." % (str_text, d["range"][1]))
row += italics("%s length must be at most %s %s." % (str_text, d["range"][1], val_text))
else:
row += italics("Value must be in range [%s..%s]." % (d["range"][0], d["range"][1]))

if obj.get("@extract"):
row += " " + italics("(if only one element is present then the array will be omitted)")

MdRow([prefix, "opaque object" if obj.get("opaque") else "string (base64)" if obj.get("encode") else obj["type"], "optional" if optional else "mandatory", row])
if obj.get("@lookupid"):
row += "<br>"
row += italics("This item is an instance ID.")

obj_type = "opaque object" if obj.get("opaque") else ("string (%s)" % obj.get("encode")) if obj.get("encode") else obj["type"]

MdRow([prefix, obj_type, "optional" if optional else "mandatory", row])

if obj["type"] == "object":
if "required" not in obj and name and len(obj["properties"]) > 1:
Expand Down Expand Up @@ -398,13 +406,13 @@ def MethodDump(method, props, classname, section, header, is_notification=False,
props["result"]["description"] = props["summary"]

if "@lookup" in props:
MdParagraph("> The *%s* instance ID shell be passed within the designator, e.g. ``%s.1.%s%s``." % (props["@lookup"][2].lower(), classname, orig_method2.replace("::", "<%s>::" % props["@lookup"][2].lower()) , "@" + props["index"][0]["example"] if "index" in props else ""))
MdParagraph("> The *%s* instance ID shell be passed within the designator, e.g. ``%s.1.%s%s``." % (props["@lookup"]["prefix"].lower(), classname, orig_method2.replace("::", "<%s>::" % props["@lookup"][2].lower()) , "@" + props["index"][0]["example"] if "index" in props else ""))

else:
MdHeader("Parameters", 3)

if "@lookup" in props:
MdParagraph("> The *%s* argument shell be passed within the designator, e.g. ``%s.1.%s``" % (props["@lookup"][2], classname, method))
MdParagraph("> The *%s* instance ID shell be passed within the designator, e.g. ``%s.1.%s``." % (props["@lookup"]["prefix"].lower(), classname, method))

if "params" in props:
ParamTable("params", props["params"])
Expand Down
2 changes: 1 addition & 1 deletion JsonGenerator/source/emitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# limitations under the License.

class Emitter():
def __init__(self, file_name, indent_size, max_line_length = 220, autoindent=False):
def __init__(self, file_name, indent_size, max_line_length = 600, autoindent=False):
self.file = open(file_name, "w") if file_name else None
self.indent_size = indent_size
self.indent = 0
Expand Down
49 changes: 32 additions & 17 deletions JsonGenerator/source/header_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ def _EvaluateRpcFormat(obj):
if face.obj.is_json:
schema["mode"] = "auto"
rpc_format = _EvaluateRpcFormat(face.obj)
assert not face.obj.is_event
else:
rpc_format = config.RpcFormat.COLLAPSED

Expand Down Expand Up @@ -253,6 +254,8 @@ def compute_name(obj, arg, relay=None):

clash_msg = "JSON-RPC name clash detected"

passed_interfaces = []

event_interfaces = set()

for interface in face.obj.classes:
Expand Down Expand Up @@ -476,15 +479,20 @@ def GenerateObject(ctype, was_typdef):

return "object", { "properties": properties, "required": required }

if cppType.full_name == "::%s::Core::JSONRPC::Context" % config.FRAMEWORK_NAMESPACE:
result = "@context", {}
if "Core::JSONRPC::Context" in cppType.full_name:
result = [ "@context", {} ]
elif (cppType.vars and not cppType.methods) or not verify:
result = GenerateObject(cppType, isinstance(var.type.Type(), CppParser.Typedef))
elif cppType.is_json:
prefix = (cppType.name[1:] if cppType.name[0] == 'I' else cppType.name)
result = [ "integer", { "size": 32, "signed": False, "@lookupid": prefix } ]
if not [x for x in passed_interfaces if x["name"] == cppType.full_name]:
passed_interfaces.append({ "name": cppType.full_name, "id": "@generate", "type": "uint32_t", "prefix": prefix})
else:
if cppType.is_iterator:
raise CppParseError(var, "iterators must be passed by pointer: %s" % cppType.type)
else:
raise CppParseError(var, "unable to convert this C++ class to JSON type: %s (passing an interface is not possible)" % cppType.type)
raise CppParseError(var, "unable to convert this C++ class to JSON type: %s (passing a non-@json interface is not possible)" % cppType.type)

elif isinstance(cppType, CppParser.Optional):
result = ConvertType(cppType.optional, meta=var.meta)
Expand Down Expand Up @@ -737,8 +745,9 @@ def BuildResult(vars, is_property=False, test=False):
prefix = ""

faces = []
faces.append((None, prefix, face.obj.methods))
faces.append((prefix, face.obj.methods))

"""
for method in face.obj.methods:
if method.retval.meta.lookup:
var_type = ResolveTypedef(method.retval.type, method)
Expand All @@ -754,9 +763,9 @@ def BuildResult(vars, is_property=False, test=False):
schema["@lookups"].append(faces[-1][0][0])
else:
raise CppParseError(method, "lookup method for an unknown class")
"""


for lookup_method, prefix, _methods in faces:
for prefix, _methods in faces:
for method in _methods:

if not method.IsVirtual() or method.IsDestructor():
Expand Down Expand Up @@ -942,7 +951,7 @@ def BuildResult(vars, is_property=False, test=False):
else:
raise CppParseError(method, "property method must have one parameter")

elif not event_params and not method.retval.meta.lookup:
elif not event_params:
var_type = ResolveTypedef(method.retval.type)

if var_type and ((isinstance(var_type.Type(), CppParser.Integer) and (var_type.Type().size == "long")) or not verify):
Expand Down Expand Up @@ -976,9 +985,6 @@ def BuildResult(vars, is_property=False, test=False):
if method.retval.meta.details:
obj["description"] = method.retval.meta.details.strip()

if lookup_method:
obj["@lookup"] = lookup_method

if method.retval.meta.retval:
errors = []

Expand Down Expand Up @@ -1115,6 +1121,9 @@ def BuildResult(vars, is_property=False, test=False):

events[prefix + method_name] = obj

if passed_interfaces:
schema["@interfaces"] = passed_interfaces

if methods:
schema["methods"] = methods

Expand All @@ -1124,6 +1133,7 @@ def BuildResult(vars, is_property=False, test=False):
if events:
schema["events"] = events


return schema

schemas = []
Expand All @@ -1137,13 +1147,18 @@ def BuildResult(vars, is_property=False, test=False):
scanned.append(face.obj.full_name)

for s in schemas:
lookups = s["@lookups"] if "@lookups" in s else []
for l in lookups:
for s2 in schemas:
if StripFrameworkNamespace(s2["@fullname"]) == l:
del s2["@generated"]

schemas = [s for s in schemas if "@generated" in s]
for face in (s["@interfaces"] if "@interfaces" in s else []):
for ss in schemas:
if ss["@fullname"] == face["name"] and "methods" in ss:
methods = ss["methods"]
for k,_ in methods.items():
new_k = face["prefix"].lower() + "::" + k
s["methods"][new_k] = methods.pop(k)
s["methods"][new_k]["@lookup"] = face
ss["@generated"] = False


schemas = [s for s in schemas if s.get("@generated")]

return schemas, []

Expand Down
2 changes: 1 addition & 1 deletion JsonGenerator/source/json_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,7 @@ def _AddMethods(section, schema, ctor):
_AddMethods("events", schema, lambda name, obj, method: JsonNotification(name, obj, method))

if not self.methods:
raise JsonParseError("no methods, properties or events defined in %s" % self.print_name)
raise JsonParseError("no methods, properties or events defined in %s" % self.schema["@fullname"] if "@fullname" in self.schema else self.name)

@property
def root(self):
Expand Down
Loading

0 comments on commit fa28644

Please sign in to comment.