Mercurial > hg > orthanc-stone
comparison Resources/CodeGeneration/stonegentool.py @ 628:84af39146e76 am-dev
CodeGeneration: support default values
author | Alain Mazy <alain@mazy.be> |
---|---|
date | Wed, 08 May 2019 16:32:57 +0200 |
parents | 8432926e9db9 |
children | 5dd496343fad |
comparison
equal
deleted
inserted
replaced
627:b7fd0471281c | 628:84af39146e76 |
---|---|
67 with open(path, "r") as fp: | 67 with open(path, "r") as fp: |
68 fileContent = fp.read() | 68 fileContent = fp.read() |
69 fileContent = JsonHelpers.removeCommentsFromJsonContent(fileContent) | 69 fileContent = JsonHelpers.removeCommentsFromJsonContent(fileContent) |
70 return json.loads(fileContent) | 70 return json.loads(fileContent) |
71 | 71 |
72 class FieldDefinition: | |
73 | |
74 def __init__(self, name: str, type: str, defaultValue: str): | |
75 self.name = name | |
76 self.type = type | |
77 self.defaultValue = defaultValue | |
78 | |
79 @staticmethod | |
80 def fromKeyValue(key: str, value: str): | |
81 | |
82 if "=" in value: | |
83 splitValue = value.split(sep="=") | |
84 type = splitValue[0].strip(" ") | |
85 defaultValue = splitValue[1].strip(" ") | |
86 else: | |
87 type = value | |
88 defaultValue = None | |
89 | |
90 return FieldDefinition(name = key, type = type, defaultValue = defaultValue) | |
91 | |
72 | 92 |
73 def LoadSchemaFromJson(filePath): | 93 def LoadSchemaFromJson(filePath): |
74 return JsonHelpers.loadJsonWithComments(filePath) | 94 return JsonHelpers.loadJsonWithComments(filePath) |
75 | 95 |
76 def CanonToCpp(canonicalTypename): | 96 def CanonToCpp(canonicalTypename): |
127 return True | 147 return True |
128 | 148 |
129 def NeedsCppConstruction(canonTypename): | 149 def NeedsCppConstruction(canonTypename): |
130 return False | 150 return False |
131 | 151 |
152 def DefaultValueToTs(enums, field:FieldDefinition): | |
153 tsType = CanonToTs(field.type) | |
154 | |
155 enumNames = [] | |
156 for enum in enums: | |
157 enumNames.append(enum['name']) | |
158 | |
159 if tsType in enumNames: | |
160 return tsType + "." + field.defaultValue | |
161 else: | |
162 return field.defaultValue | |
163 | |
164 def DefaultValueToCpp(root, enums, field:FieldDefinition): | |
165 cppType = CanonToCpp(field.type) | |
166 | |
167 enumNames = [] | |
168 for enum in enums: | |
169 enumNames.append(enum['name']) | |
170 | |
171 if cppType in enumNames: | |
172 return root + "::" + cppType + "_" + field.defaultValue | |
173 else: | |
174 return field.defaultValue | |
175 | |
132 def RegisterTemplateFunction(template,func): | 176 def RegisterTemplateFunction(template,func): |
133 """Makes a function callable by a jinja2 template""" | 177 """Makes a function callable by a jinja2 template""" |
134 template.globals[func.__name__] = func | 178 template.globals[func.__name__] = func |
135 return func | 179 return func |
136 | 180 |
138 template = Template(templateStr) | 182 template = Template(templateStr) |
139 RegisterTemplateFunction(template,CanonToCpp) | 183 RegisterTemplateFunction(template,CanonToCpp) |
140 RegisterTemplateFunction(template,CanonToTs) | 184 RegisterTemplateFunction(template,CanonToTs) |
141 RegisterTemplateFunction(template,NeedsTsConstruction) | 185 RegisterTemplateFunction(template,NeedsTsConstruction) |
142 RegisterTemplateFunction(template,NeedsCppConstruction) | 186 RegisterTemplateFunction(template,NeedsCppConstruction) |
187 RegisterTemplateFunction(template, DefaultValueToTs) | |
188 RegisterTemplateFunction(template, DefaultValueToCpp) | |
143 return template | 189 return template |
144 | 190 |
145 def MakeTemplateFromFile(templateFileName): | 191 def MakeTemplateFromFile(templateFileName): |
146 templateFile = open(templateFileName, "r") | 192 |
147 templateFileContents = templateFile.read() | 193 with open(templateFileName, "r") as templateFile: |
148 return MakeTemplate(templateFileContents) | 194 templateFileContents = templateFile.read() |
149 templateFile.close() | 195 return MakeTemplate(templateFileContents) |
196 | |
150 | 197 |
151 def EatToken(sentence): | 198 def EatToken(sentence): |
152 """splits "A,B,C" into "A" and "B,C" where A, B and C are type names | 199 """splits "A,B,C" into "A" and "B,C" where A, B and C are type names |
153 (including templates) like "int32", "TotoTutu", or | 200 (including templates) like "int32", "TotoTutu", or |
154 "map<map<int32,vector<string>>,map<string,int32>>" """ | 201 "map<map<int32,vector<string>>,map<string,int32>>" """ |
361 if fieldDict == None: | 408 if fieldDict == None: |
362 return fieldDict | 409 return fieldDict |
363 ret = {} | 410 ret = {} |
364 for k,v in fieldDict.items(): | 411 for k,v in fieldDict.items(): |
365 if k != "__handler": | 412 if k != "__handler": |
366 ret[k] = v | 413 ret[k] = FieldDefinition.fromKeyValue(k, v) |
367 if k.startswith("__") and k != "__handler": | 414 if k.startswith("__") and k != "__handler": |
368 raise RuntimeError("Fields starting with __ (double underscore) are reserved names!") | 415 raise RuntimeError("Fields starting with __ (double underscore) are reserved names!") |
369 return ret | 416 return ret |
370 | 417 |
371 def GetStructMetadata(fieldDict): | 418 def GetStructMetadata(fieldDict): |
471 # TL;DR: all 256 values are mapped to characters in latin-1 so the file | 518 # TL;DR: all 256 values are mapped to characters in latin-1 so the file |
472 # contents never cause an error. | 519 # contents never cause an error. |
473 with open(fn, 'r', encoding='latin-1') as f: | 520 with open(fn, 'r', encoding='latin-1') as f: |
474 schemaText = f.read() | 521 schemaText = f.read() |
475 assert(type(schemaText) == str) | 522 assert(type(schemaText) == str) |
523 return LoadSchemaFromString(schemaText = schemaText) | |
524 | |
525 def LoadSchemaFromString(schemaText:str): | |
476 # ensure there is a space after each colon. Otherwise, dicts could be | 526 # ensure there is a space after each colon. Otherwise, dicts could be |
477 # erroneously recognized as an array of strings containing ':' | 527 # erroneously recognized as an array of strings containing ':' |
478 for i in range(len(schemaText)-1): | 528 for i in range(len(schemaText)-1): |
479 ch = schemaText[i] | 529 ch = schemaText[i] |
480 nextCh = schemaText[i+1] | 530 nextCh = schemaText[i+1] |
481 if ch == ':': | 531 if ch == ':': |
482 if not (nextCh == ' ' or nextCh == '\n'): | 532 if not (nextCh == ' ' or nextCh == '\n'): |
483 lineNumber = schemaText.count("\n",0,i) + 1 | 533 lineNumber = schemaText.count("\n",0,i) + 1 |
484 raise RuntimeError("Error at line " + str(lineNumber) + " in the schema: colons must be followed by a space or a newline!") | 534 raise RuntimeError("Error at line " + str(lineNumber) + " in the schema: colons must be followed by a space or a newline!") |
485 schema = yaml.load(schemaText) | 535 schema = yaml.load(schemaText) |
486 return schema | 536 return schema |
487 | 537 |
488 def GetTemplatingDictFromSchemaFilename(fn): | 538 def GetTemplatingDictFromSchemaFilename(fn): |
489 obj = LoadSchema(fn) | 539 return GetTemplatingDictFromSchema(LoadSchema(fn)) |
490 genOrder = ComputeRequiredDeclarationOrder(obj) | 540 |
491 templatingDict = ProcessSchema(obj, genOrder) | 541 def GetTemplatingDictFromSchema(schema): |
542 genOrder = ComputeRequiredDeclarationOrder(schema) | |
543 templatingDict = ProcessSchema(schema, genOrder) | |
492 currentDT = datetime.datetime.now() | 544 currentDT = datetime.datetime.now() |
493 templatingDict['currentDatetime'] = str(currentDT) | 545 templatingDict['currentDatetime'] = str(currentDT) |
494 return templatingDict | 546 return templatingDict |
495 | 547 |
496 # +-----------------------+ | 548 # +-----------------------+ |