Mercurial > hg > orthanc-stone
comparison Resources/CodeGeneration/stonegentool.py @ 473:628941d63b8c bgo-commands-codegen
Ongoing work. Parsing tests work
author | bgo-osimis |
---|---|
date | Wed, 13 Feb 2019 12:07:00 +0100 |
parents | 3db3289e1c25 |
children | 38997ceb9bc6 |
comparison
equal
deleted
inserted
replaced
472:3db3289e1c25 | 473:628941d63b8c |
---|---|
1 from typing import List,Dict,Set | |
2 import sys | |
3 import json | 1 import json |
4 import re | 2 import re |
3 import sys | |
4 from typing import Dict, List, Set | |
5 | |
5 | 6 |
6 """ | 7 """ |
7 1 2 3 4 5 6 7 | 8 1 2 3 4 5 6 7 |
8 12345678901234567890123456789012345678901234567890123456789012345678901234567890 | 9 12345678901234567890123456789012345678901234567890123456789012345678901234567890 |
9 """ | 10 """ |
10 | 11 |
11 def LoadSchema(file_path : str): | 12 import json |
12 with open(file_path, 'r') as fp: | 13 import re |
13 obj = json.load(fp) | 14 |
14 return obj | 15 """A set of utilities to perform JSON operation""" |
16 | |
17 class JsonHelpers: | |
18 @staticmethod | |
19 def removeCommentsFromJsonContent(string): | |
20 """ | |
21 remove comments from a JSON file | |
22 | |
23 Comments are not allowed in JSON but, i.e., Orthanc configuration files contains C++ like comments that we need to remove before python can parse the file | |
24 """ | |
25 string = re.sub(re.compile("/\*.*?\*/", re.DOTALL), "", | |
26 string) # remove all occurance streamed comments (/*COMMENT */) from string | |
27 string = re.sub(re.compile("//.*?\n"), "", | |
28 string) # remove all occurance singleline comments (//COMMENT\n ) from string | |
29 return string | |
30 | |
31 @staticmethod | |
32 def loadJsonWithComments(path): | |
33 """ | |
34 reads a JSON file that may contain C++ like comments | |
35 """ | |
36 with open(path, 'r') as fp: | |
37 fileContent = fp.read() | |
38 fileContent = JsonHelpers.removeCommentsFromJsonContent(fileContent) | |
39 return json.loads(fileContent) | |
40 | |
41 | |
42 def LoadSchema(filePath : str): | |
43 return JsonHelpers.loadJsonWithComments(filePath) | |
15 | 44 |
16 # class Type: | 45 # class Type: |
17 # def __init__(self, canonicalTypeName:str, kind:str): | 46 # def __init__(self, canonicalTypeName:str, kind:str): |
18 # allowedTypeKinds = ["primitive","enum","struct","collection"] | 47 # allowedTypeKinds = ["primitive","enum","struct","collection"] |
19 # """dependent type is the list of canonical types this type depends on. | 48 # """dependent type is the list of canonical types this type depends on. |
61 # self.rootName : str = root_prefix | 90 # self.rootName : str = root_prefix |
62 # self.definedTypes : str = defined_types | 91 # self.definedTypes : str = defined_types |
63 | 92 |
64 def CheckTypeSchema(definedType : Dict) -> None: | 93 def CheckTypeSchema(definedType : Dict) -> None: |
65 allowedDefinedTypeKinds = ["enum","struct"] | 94 allowedDefinedTypeKinds = ["enum","struct"] |
66 if not definedType.has_key('name'): | 95 if not 'name' in definedType: |
67 raise Exception("type lacks the 'name' key") | 96 raise Exception("type lacks the 'name' key") |
68 name = definedType['name'] | 97 name = definedType['name'] |
69 if not definedType.has_key('kind'): | 98 if not 'kind' in definedType: |
70 raise Exception(f"type {name} lacks the 'kind' key") | 99 raise Exception(f"type {name} lacks the 'kind' key") |
71 kind = definedType['kind'] | 100 kind = definedType['kind'] |
72 if not (kind in allowedDefinedTypeKinds): | 101 if not (kind in allowedDefinedTypeKinds): |
73 raise Exception(f"type {name} : kind {kind} is not allowed. " + | 102 raise Exception(f"type {name} : kind {kind} is not allowed. " + |
74 f"It must be one of {allowedDefinedTypeKinds}") | 103 f"It must be one of {allowedDefinedTypeKinds}") |
75 | 104 |
76 if not definedType.has_key('fields'): | 105 if not 'fields' in definedType: |
77 raise Exception("type {name} lacks the 'fields' key") | 106 raise Exception("type {name} lacks the 'fields' key") |
78 | 107 |
79 # generic check on all kinds of types | 108 # generic check on all kinds of types |
80 fields = definedType['fields'] | 109 fields = definedType['fields'] |
81 for field in fields: | 110 for field in fields: |
82 fieldName = field['name'] | 111 fieldName = field['name'] |
83 if not field.has_key('name'): | 112 if not 'name' in field: |
84 raise Exception("field in type {name} lacks the 'name' key") | 113 raise Exception("field in type {name} lacks the 'name' key") |
85 | 114 |
86 # fields in struct must have types | 115 # fields in struct must have types |
87 if kind == 'struct': | 116 if kind == 'struct': |
88 for field in fields: | 117 for field in fields: |
89 fieldName = field['name'] | 118 fieldName = field['name'] |
90 if not field.has_key('type'): | 119 if not 'type' in field: |
91 raise Exception(f"field {fieldName} in type {name} " | 120 raise Exception(f"field {fieldName} in type {name} " |
92 + "lacks the 'type' key") | 121 + "lacks the 'type' key") |
93 | 122 |
94 def CheckSchemaSchema(schema : Dict) -> None: | 123 def CheckSchemaSchema(schema : Dict) -> None: |
95 if not schema.has_key('root_name'): | 124 if not 'root_name' in schema: |
96 raise Exception("schema lacks the 'root_name' key") | 125 raise Exception("schema lacks the 'root_name' key") |
97 if not schema.has_key('types'): | 126 if not 'types' in schema: |
98 raise Exception("schema lacks the 'types' key") | 127 raise Exception("schema lacks the 'types' key") |
99 for definedType in schema['types']: | 128 for definedType in schema['types']: |
100 CheckTypeSchema(definedType) | 129 CheckTypeSchema(definedType) |
101 | 130 |
102 # def CreateAndCacheTypeObject(allTypes : Dict[str,Type], typeDict : Dict) -> None: | 131 # def CreateAndCacheTypeObject(allTypes : Dict[str,Type], typeDict : Dict) -> None: |
103 # """This does not set the dependentTypes field""" | 132 # """This does not set the dependentTypes field""" |
104 # typeName : str = typeDict['name'] | 133 # typeName : str = typeDict['name'] |
105 # if allTypes.has_key(typeName): | 134 # if typeName in allTypes: |
106 # raise Exception(f'Type {typeName} is defined more than once!') | 135 # raise Exception(f'Type {typeName} is defined more than once!') |
107 # else: | 136 # else: |
108 # typeObject = Type(typeName, typeDict['kind']) | 137 # typeObject = Type(typeName, typeDict['kind']) |
109 # allTypes[typeName] = typeObject | 138 # allTypes[typeName] = typeObject |
110 | 139 |
117 raise Exception(f"Error in the partial template type list {sentence}." | 146 raise Exception(f"Error in the partial template type list {sentence}." |
118 + " The number of < and > do not match!") | 147 + " The number of < and > do not match!") |
119 | 148 |
120 # the template level we're currently in | 149 # the template level we're currently in |
121 templateLevel = 0 | 150 templateLevel = 0 |
122 for i in len(sentence): | 151 for i in range(len(sentence)): |
123 if (sentence[i] == ",") and (templateLevel == 0): | 152 if (sentence[i] == ",") and (templateLevel == 0): |
124 return (sentence[0:i],sentence[i+1:]) | 153 return (sentence[0:i],sentence[i+1:]) |
125 elif (sentence[i] == "<"): | 154 elif (sentence[i] == "<"): |
126 templateLevel += 1 | 155 templateLevel += 1 |
127 elif (sentence[i] == ">"): | 156 elif (sentence[i] == ">"): |
142 tokenList = [] | 171 tokenList = [] |
143 restOfString = typeName | 172 restOfString = typeName |
144 while stillStuffToEat: | 173 while stillStuffToEat: |
145 firstToken,restOfString = EatToken(restOfString) | 174 firstToken,restOfString = EatToken(restOfString) |
146 tokenList.append(firstToken) | 175 tokenList.append(firstToken) |
176 if restOfString == "": | |
177 stillStuffToEat = False | |
147 return tokenList | 178 return tokenList |
148 | 179 |
149 templateRegex = \ | 180 templateRegex = \ |
150 re.compile(r"([a-zA-Z0-9_]*[a-zA-Z0-9_]*)<([a-zA-Z0-9_,:<>]+)>") | 181 re.compile(r"([a-zA-Z0-9_]*[a-zA-Z0-9_]*)<([a-zA-Z0-9_,:<>]+)>") |
151 | 182 |
165 # we need to split with the commas that are outside of the defined types | 196 # we need to split with the commas that are outside of the defined types |
166 # simply splitting at commas won't work | 197 # simply splitting at commas won't work |
167 listOfDependentTypes = SplitListOfTypes(matches.group(2)) | 198 listOfDependentTypes = SplitListOfTypes(matches.group(2)) |
168 return (True,matches.group(1),listOfDependentTypes) | 199 return (True,matches.group(1),listOfDependentTypes) |
169 | 200 |
170 | |
171 # def GetPrimitiveType(typeName : str) -> Type: | 201 # def GetPrimitiveType(typeName : str) -> Type: |
172 # if allTypes.has_key(typeName): | 202 # if typeName in allTypes: |
173 # return allTypes[typeName] | 203 # return allTypes[typeName] |
174 # else: | 204 # else: |
175 # primitiveTypes = ['int32', 'float32', 'float64', 'string'] | 205 # primitiveTypes = ['int32', 'float32', 'float64', 'string'] |
176 # if not (typeName in primitiveTypes): | 206 # if not (typeName in primitiveTypes): |
177 # raise Exception(f"Type {typeName} is unknown.") | 207 # raise Exception(f"Type {typeName} is unknown.") |
200 # childAncestors = ancestors.copy() NO TEMPLATE ANCESTOR!!! | 230 # childAncestors = ancestors.copy() NO TEMPLATE ANCESTOR!!! |
201 # childAncestors.append(typeName) | 231 # childAncestors.append(typeName) |
202 ProcessTypeTree(ancestors, genOrderQueue, | 232 ProcessTypeTree(ancestors, genOrderQueue, |
203 structTypes, dependentTypeName) | 233 structTypes, dependentTypeName) |
204 else: | 234 else: |
205 if structTypes.has_key(typeName): | 235 if typeName in structTypes: |
206 ProcessStructType_DepthFirstRecursive(genOrderQueue, structTypes, | 236 ProcessStructType_DepthFirstRecursive(genOrderQueue, structTypes, |
207 structTypes[typeName]) | 237 structTypes[typeName]) |
208 | 238 |
209 def ProcessStructType_DepthFirstRecursive( | 239 def ProcessStructType_DepthFirstRecursive( |
210 genOrderQueue : List[str], structTypes : Dict[str,Dict] | 240 genOrderQueue : List[str], structTypes : Dict[str,Dict] |