181dab213SAndrew Lindesay#!/usr/bin/python 281dab213SAndrew Lindesay 381dab213SAndrew Lindesay# ===================================== 445f8be41SAndrew Lindesay# Copyright 2017-2023, Andrew Lindesay 581dab213SAndrew Lindesay# Distributed under the terms of the MIT License. 681dab213SAndrew Lindesay# ===================================== 781dab213SAndrew Lindesay 881dab213SAndrew Lindesay# This simple tool will read a JSON schema and will then generate 981dab213SAndrew Lindesay# some model objects that can be used to hold the data-structure 1081dab213SAndrew Lindesay# in the C++ environment. 1181dab213SAndrew Lindesay 1281dab213SAndrew Lindesayimport json 1381dab213SAndrew Lindesayimport argparse 1481dab213SAndrew Lindesayimport os 1545f8be41SAndrew Lindesayimport hdsjsonschemacommon 1645f8be41SAndrew Lindesayimport ustache 1781dab213SAndrew Lindesay 1881dab213SAndrew Lindesay 1945f8be41SAndrew LindesayHEADER_TEMPLATE = """ 2045f8be41SAndrew Lindesay/* 212174e23fSAndrew Lindesay * Generated Model Object for {{cppname}} 2245f8be41SAndrew Lindesay */ 2381dab213SAndrew Lindesay 2445f8be41SAndrew Lindesay#ifndef GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H 2545f8be41SAndrew Lindesay#define GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H 2681dab213SAndrew Lindesay 27dc8d6e73SAndrew Lindesay#include <ObjectList.h> 289295c1f6SAndrew Lindesay#include <String.h> 2981dab213SAndrew Lindesay 3045f8be41SAndrew Lindesay{{#referencedclasscpptypes}}#include "{{.}}.h" 3145f8be41SAndrew Lindesay{{/referencedclasscpptypes}} 3281dab213SAndrew Lindesay 33*ba1465ccSAndrew Lindesay 3445f8be41SAndrew Lindesayclass {{cppname}} { 3581dab213SAndrew Lindesaypublic: 3645f8be41SAndrew Lindesay {{cppname}}(); 3745f8be41SAndrew Lindesay virtual ~{{cppname}}(); 38*ba1465ccSAndrew Lindesay 39*ba1465ccSAndrew Lindesay void Reset(); 4045f8be41SAndrew Lindesay{{#propertyarray}}{{#property.iscppscalartype}} 4145f8be41SAndrew Lindesay {{property.cpptype}} {{property.cppname}}(); 4245f8be41SAndrew Lindesay void Set{{property.cppname}}({{property.cpptype}} value); 4345f8be41SAndrew Lindesay void Set{{property.cppname}}Null(); 4445f8be41SAndrew Lindesay bool {{property.cppname}}IsNull(); 4545f8be41SAndrew Lindesay{{/property.iscppscalartype}}{{#property.isarray}} 4645f8be41SAndrew Lindesay void AddTo{{property.cppname}}({{property.items.cpptype}}* value); 4745f8be41SAndrew Lindesay void Set{{property.cppname}}({{property.cpptype}}* value); 4845f8be41SAndrew Lindesay int32 Count{{property.cppname}}(); 4945f8be41SAndrew Lindesay {{property.items.cpptype}}* {{property.cppname}}ItemAt(int32 index); 5045f8be41SAndrew Lindesay bool {{property.cppname}}IsNull(); 5145f8be41SAndrew Lindesay{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}} 5245f8be41SAndrew Lindesay {{property.cpptype}}* {{property.cppname}}(); 5345f8be41SAndrew Lindesay void Set{{property.cppname}}({{property.cpptype}}* value); 5445f8be41SAndrew Lindesay void Set{{property.cppname}}Null(); 5545f8be41SAndrew Lindesay bool {{property.cppname}}IsNull(); 5645f8be41SAndrew Lindesay{{/property.iscppnonscalarnoncollectiontype}} 5745f8be41SAndrew Lindesay{{/propertyarray}} 58*ba1465ccSAndrew Lindesay 59*ba1465ccSAndrew Lindesaypublic: 60*ba1465ccSAndrew Lindesay{{#propertyarray}} static const uint16 k{{property.cppname}}Bitmask; 61*ba1465ccSAndrew Lindesay{{/propertyarray}} 62*ba1465ccSAndrew Lindesay 6345f8be41SAndrew Lindesayprivate: 64*ba1465ccSAndrew Lindesay uint16 fHasValueBitmask; 65*ba1465ccSAndrew Lindesay{{#propertyarray}} {{property.cpptype}}{{^property.iscppscalartype}}*{{/property.iscppscalartype}} {{property.cppmembername}}; 6645f8be41SAndrew Lindesay{{/propertyarray}} 6745f8be41SAndrew Lindesay}; 6845f8be41SAndrew Lindesay 6945f8be41SAndrew Lindesay#endif // GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H 7045f8be41SAndrew Lindesay""" 7145f8be41SAndrew Lindesay 7245f8be41SAndrew LindesayIMPLEMENTATION_TEMPLATE = """ 7345f8be41SAndrew Lindesay/* 742174e23fSAndrew Lindesay * Generated Model Object for {{cppname}} 7545f8be41SAndrew Lindesay */ 7645f8be41SAndrew Lindesay 7745f8be41SAndrew Lindesay#include "{{cppname}}.h" 7881dab213SAndrew Lindesay 7981dab213SAndrew Lindesay 80*ba1465ccSAndrew Lindesay{{#propertyarray}}/*static*/ const uint16 {{cppname}}::k{{property.cppname}}Bitmask = {{cppbitmaskexpression}}; 81*ba1465ccSAndrew Lindesay{{/propertyarray}} 82*ba1465ccSAndrew Lindesay 83*ba1465ccSAndrew Lindesay 8445f8be41SAndrew Lindesay{{cppname}}::{{cppname}}() 8545f8be41SAndrew Lindesay : 86*ba1465ccSAndrew Lindesay fHasValueBitmask(0), 87*ba1465ccSAndrew Lindesay{{#propertyarray}} {{property.cppmembername}}({{property.cppdefaultvalue}}){{^islast}},{{/islast}} 8845f8be41SAndrew Lindesay{{/propertyarray}}{ 8945f8be41SAndrew Lindesay} 9081dab213SAndrew Lindesay 9181dab213SAndrew Lindesay 9245f8be41SAndrew Lindesay{{cppname}}::~{{cppname}}() 9345f8be41SAndrew Lindesay{ 94*ba1465ccSAndrew Lindesay Reset(); 95*ba1465ccSAndrew Lindesay} 96*ba1465ccSAndrew Lindesay 97*ba1465ccSAndrew Lindesay 98*ba1465ccSAndrew Lindesayvoid 99*ba1465ccSAndrew Lindesay{{cppname}}::Reset() 100*ba1465ccSAndrew Lindesay{ 101*ba1465ccSAndrew Lindesay{{#propertyarray}}{{#property.isstring}} delete {{property.cppmembername}}; 102*ba1465ccSAndrew Lindesay{{/property.isstring}}{{#property.isobject}} delete {{property.cppmembername}}; 103*ba1465ccSAndrew Lindesay{{/property.isobject}}{{#property.isarray}} 104*ba1465ccSAndrew Lindesay if ({{property.cppmembername}} != NULL) { 10545f8be41SAndrew Lindesay for (int i = {{property.cppmembername}}->CountItems() - 1; i >= 0; i--) 10645f8be41SAndrew Lindesay delete {{property.cppmembername}}->ItemAt(i); 10745f8be41SAndrew Lindesay delete {{property.cppmembername}}; 10845f8be41SAndrew Lindesay } 109*ba1465ccSAndrew Lindesay{{/property.isarray}} {{property.cppmembername}} = {{property.cppdefaultvalue}}; 110*ba1465ccSAndrew Lindesay{{/propertyarray}} 111*ba1465ccSAndrew Lindesay fHasValueBitmask = 0; 112*ba1465ccSAndrew Lindesay} 11381dab213SAndrew Lindesay 11445f8be41SAndrew Lindesay{{#propertyarray}}{{#property.iscppscalartype}}{{property.cpptype}} 11545f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}() 11645f8be41SAndrew Lindesay{ 117*ba1465ccSAndrew Lindesay return {{property.cppmembername}}; 11845f8be41SAndrew Lindesay} 11981dab213SAndrew Lindesay 12081dab213SAndrew Lindesay 12145f8be41SAndrew Lindesayvoid 12245f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}} value) 12345f8be41SAndrew Lindesay{ 124*ba1465ccSAndrew Lindesay fHasValueBitmask |= k{{property.cppname}}Bitmask; 125*ba1465ccSAndrew Lindesay {{property.cppmembername}} = value; 12645f8be41SAndrew Lindesay} 12781dab213SAndrew Lindesay 12881dab213SAndrew Lindesay 12945f8be41SAndrew Lindesayvoid 13045f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}Null() 13145f8be41SAndrew Lindesay{ 132*ba1465ccSAndrew Lindesay fHasValueBitmask &= ~k{{property.cppname}}Bitmask; 133*ba1465ccSAndrew Lindesay {{property.cppmembername}} = {{property.cppdefaultvalue}}; 13445f8be41SAndrew Lindesay} 13581dab213SAndrew Lindesay 13681dab213SAndrew Lindesay 13745f8be41SAndrew Lindesaybool 13845f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}IsNull() 13945f8be41SAndrew Lindesay{ 140*ba1465ccSAndrew Lindesay return 0 == (fHasValueBitmask & k{{property.cppname}}Bitmask); 14145f8be41SAndrew Lindesay} 14281dab213SAndrew Lindesay 14345f8be41SAndrew Lindesay{{/property.iscppscalartype}}{{#property.isarray}}void 14445f8be41SAndrew Lindesay{{cppobjectname}}::AddTo{{property.cppname}}({{property.items.cpptype}}* value) 14545f8be41SAndrew Lindesay{ 14645f8be41SAndrew Lindesay if ({{property.cppmembername}} == NULL) 14745f8be41SAndrew Lindesay {{property.cppmembername}} = new {{property.cpptype}}(); 14845f8be41SAndrew Lindesay {{property.cppmembername}}->AddItem(value); 14945f8be41SAndrew Lindesay} 15081dab213SAndrew Lindesay 15181dab213SAndrew Lindesay 15245f8be41SAndrew Lindesayvoid 15345f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}}* value) 15445f8be41SAndrew Lindesay{ 15545f8be41SAndrew Lindesay if ({{property.cppmembername}} != NULL) { 15645f8be41SAndrew Lindesay delete {{property.cppmembername}}; 15745f8be41SAndrew Lindesay } 15845f8be41SAndrew Lindesay {{property.cppmembername}} = value; 15945f8be41SAndrew Lindesay} 16081dab213SAndrew Lindesay 16145f8be41SAndrew Lindesay 16245f8be41SAndrew Lindesayint32 16345f8be41SAndrew Lindesay{{cppobjectname}}::Count{{property.cppname}}() 16445f8be41SAndrew Lindesay{ 16545f8be41SAndrew Lindesay if ({{property.cppmembername}} == NULL) 16645f8be41SAndrew Lindesay return 0; 16745f8be41SAndrew Lindesay return {{property.cppmembername}}->CountItems(); 16845f8be41SAndrew Lindesay} 16945f8be41SAndrew Lindesay 17045f8be41SAndrew Lindesay 17145f8be41SAndrew Lindesay{{property.items.cpptype}}* 17245f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}ItemAt(int32 index) 17345f8be41SAndrew Lindesay{ 17445f8be41SAndrew Lindesay return {{property.cppmembername}}->ItemAt(index); 17545f8be41SAndrew Lindesay} 17645f8be41SAndrew Lindesay 17745f8be41SAndrew Lindesay 17845f8be41SAndrew Lindesaybool 17945f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}IsNull() 18045f8be41SAndrew Lindesay{ 18145f8be41SAndrew Lindesay return {{property.cppmembername}} == NULL; 18245f8be41SAndrew Lindesay} 18345f8be41SAndrew Lindesay 18445f8be41SAndrew Lindesay{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}}{{property.cpptype}}* 18545f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}() 18645f8be41SAndrew Lindesay{ 18745f8be41SAndrew Lindesay return {{property.cppmembername}}; 18845f8be41SAndrew Lindesay} 18945f8be41SAndrew Lindesay 19045f8be41SAndrew Lindesay 19145f8be41SAndrew Lindesayvoid 19245f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}}* value) 19345f8be41SAndrew Lindesay{ 19445f8be41SAndrew Lindesay {{property.cppmembername}} = value; 19545f8be41SAndrew Lindesay} 19645f8be41SAndrew Lindesay 19745f8be41SAndrew Lindesay 19845f8be41SAndrew Lindesayvoid 19945f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}Null() 20045f8be41SAndrew Lindesay{ 20145f8be41SAndrew Lindesay if (!{{property.cppname}}IsNull()) { 20245f8be41SAndrew Lindesay delete {{property.cppmembername}}; 20345f8be41SAndrew Lindesay {{property.cppmembername}} = NULL; 20445f8be41SAndrew Lindesay } 20545f8be41SAndrew Lindesay} 20645f8be41SAndrew Lindesay 20745f8be41SAndrew Lindesay 20845f8be41SAndrew Lindesaybool 20945f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}IsNull() 21045f8be41SAndrew Lindesay{ 21145f8be41SAndrew Lindesay return {{property.cppmembername}} == NULL; 21245f8be41SAndrew Lindesay} 21345f8be41SAndrew Lindesay 21445f8be41SAndrew Lindesay{{/property.iscppnonscalarnoncollectiontype}} 21545f8be41SAndrew Lindesay{{/propertyarray}} 21645f8be41SAndrew Lindesay""" 21745f8be41SAndrew Lindesay 21845f8be41SAndrew Lindesay 21945f8be41SAndrew Lindesaydef write_models_for_schema(schema: dict[str, any], output_directory: str) -> None: 22045f8be41SAndrew Lindesay 22145f8be41SAndrew Lindesay def write_model_object(obj: dict[str, any]) -> None: 22245f8be41SAndrew Lindesay cpp_name = obj["cppname"] 22345f8be41SAndrew Lindesay cpp_header_filename = os.path.join(output_directory, cpp_name + '.h') 22445f8be41SAndrew Lindesay cpp_implementation_filename = os.path.join(output_directory, cpp_name + '.cpp') 22545f8be41SAndrew Lindesay 22645f8be41SAndrew Lindesay with open(cpp_header_filename, 'w') as cpp_h_file: 22745f8be41SAndrew Lindesay cpp_h_file.write(ustache.render( 22845f8be41SAndrew Lindesay HEADER_TEMPLATE, 22945f8be41SAndrew Lindesay obj, 23045f8be41SAndrew Lindesay escape= lambda x: x)) 23145f8be41SAndrew Lindesay 23245f8be41SAndrew Lindesay with open(cpp_implementation_filename, 'w') as cpp_i_file: 23345f8be41SAndrew Lindesay cpp_i_file.write(ustache.render( 23445f8be41SAndrew Lindesay IMPLEMENTATION_TEMPLATE, 23545f8be41SAndrew Lindesay obj, 23645f8be41SAndrew Lindesay escape= lambda x: x)) 23745f8be41SAndrew Lindesay 2382174e23fSAndrew Lindesay for obj in hdsjsonschemacommon.collect_all_objects(schema): 23945f8be41SAndrew Lindesay write_model_object(obj) 24045f8be41SAndrew Lindesay 24181dab213SAndrew Lindesay 24281dab213SAndrew Lindesaydef main(): 24345f8be41SAndrew Lindesay parser = argparse.ArgumentParser( 24445f8be41SAndrew Lindesay description='Convert JSON schema to Haiku C++ Models') 24545f8be41SAndrew Lindesay parser.add_argument( 24645f8be41SAndrew Lindesay '-i', '--inputfile', 24745f8be41SAndrew Lindesay required=True, 24845f8be41SAndrew Lindesay help='The input filename containing the JSON schema') 24945f8be41SAndrew Lindesay parser.add_argument( 25045f8be41SAndrew Lindesay '--outputdirectory', 25145f8be41SAndrew Lindesay help='The output directory where the C++ files should be written') 25281dab213SAndrew Lindesay 25381dab213SAndrew Lindesay args = parser.parse_args() 25481dab213SAndrew Lindesay 25545f8be41SAndrew Lindesay output_directory = args.outputdirectory 25681dab213SAndrew Lindesay 25745f8be41SAndrew Lindesay if not output_directory: 25845f8be41SAndrew Lindesay output_directory = '.' 25981dab213SAndrew Lindesay 26081dab213SAndrew Lindesay with open(args.inputfile) as inputfile: 26181dab213SAndrew Lindesay schema = json.load(inputfile) 26245f8be41SAndrew Lindesay hdsjsonschemacommon.augment_schema(schema) 26345f8be41SAndrew Lindesay write_models_for_schema(schema, output_directory) 26445f8be41SAndrew Lindesay 26581dab213SAndrew Lindesay 26681dab213SAndrew Lindesayif __name__ == "__main__": 26781dab213SAndrew Lindesay main() 26881dab213SAndrew Lindesay 269