fixed: gcc8 compile issues
[opensg.git] / Tools / fcd2code / TemplateFiller.py
blob77be565bf5062fc9ff10581683b88b32e53b6699
2 import copy;
3 import logging;
4 import re;
6 from ListStack import ListStack;
8 class TemplateFiller:
9 """Fill in a template.
10 """
12 def __init__(self, templateLines):
13 """Create a new TemplateFiller, that fills the template given in
14 templateLines, which is a list of strings, as produced by readlines.
15 """
16 self.m_log = logging.getLogger("TemplateFiller");
17 self.m_inLines = templateLines;
18 self.m_outLines = [];
20 self.m_varRE = re.compile(r"@!([^!@]*)!@");
21 self.m_ifRE = re.compile(r"@@if[ \t]+(!|)([A-Za-z\.]*)");
22 self.m_elseRE = re.compile(r"@@else");
23 self.m_endifRE = re.compile(r"@@endif");
24 self.m_BeginFieldLoopRE = re.compile(r"@@BeginFieldLoop");
25 self.m_EndFieldLoopRE = re.compile(r"@@EndFieldLoop");
26 self.m_BeginSFFieldLoopRE = re.compile(r"@@BeginSFFieldLoop");
27 self.m_EndSFFieldLoopRE = re.compile(r"@@EndSFFieldLoop");
28 self.m_BeginMFFieldLoopRE = re.compile(r"@@BeginMFFieldLoop");
29 self.m_EndMFFieldLoopRE = re.compile(r"@@EndMFFieldLoop");
30 self.m_AdditionIncludesRE = re.compile(r"@@AdditionalIncludes");
31 self.m_AdditionPrioIncludesRE = re.compile(r"@@AdditionalPriorityIncludes");
33 def fill(self, dictList):
34 """Fill in a template using the contents of the dictionaries in
35 dictList.
36 """
37 self.m_outLines = [];
39 skipStack = ListStack();
40 skipCurrent = False;
41 inLoop = False;
42 loopLines = [];
44 # Go through template and find loops, collect their lines in loopLines.
45 # call _processLoop for the loopLines.
47 context = [d for d in dictList];
49 for lineNum, line in enumerate(self.m_inLines):
50 # handle @@BeginFieldLoop
51 matchBeginFieldLoop = self.m_BeginFieldLoopRE.search(line);
52 if (not skipCurrent) and (matchBeginFieldLoop != None):
53 #self.m_log.debug("fill: line %d -> BeginFieldLoop", lineNum);
54 inLoop = True;
55 continue;
57 # handle @@BeginSFFieldLoop
58 matchBeginSFFieldLoop = self.m_BeginSFFieldLoopRE.search(line);
59 if (not skipCurrent) and (matchBeginSFFieldLoop != None):
60 #self.m_log.debug("fill: line %d -> BeginSFFieldLoop", lineNum);
61 inLoop = True;
62 continue;
64 # handle @@BeginMFFieldLoop
65 matchBeginMFFieldLoop = self.m_BeginMFFieldLoopRE.search(line);
66 if (not skipCurrent) and (matchBeginMFFieldLoop != None):
67 #self.m_log.debug("fill: line %d -> BeginMFFieldLoop", lineNum);
68 inLoop = True;
69 continue;
71 # handle loops - do not bother with conditionals they are handled in
72 # _processLoop
73 if (not skipCurrent) and (inLoop == True):
74 # handle @@EndFieldLoop
75 matchEndFieldLoop = self.m_EndFieldLoopRE.search(line);
76 if matchEndFieldLoop != None:
77 #self.m_log.debug("fill: line %d -> EndFieldLoop", lineNum);
78 self._processLoop("Fields", loopLines, context);
79 inLoop = False;
80 loopLines = [];
81 continue;
83 # handle @@EndSFFieldLoop
84 matchEndSFFieldLoop = self.m_EndSFFieldLoopRE.search(line);
85 if matchEndSFFieldLoop != None:
86 #self.m_log.debug("fill: line %d -> EndSFFieldLoop", lineNum);
87 self._processLoop("SFields", loopLines, context);
88 inLoop = False;
89 loopLines = [];
90 continue;
92 # handle @@EndMFFieldLoop
93 matchEndMFFieldLoop = self.m_EndMFFieldLoopRE.search(line);
94 if matchEndMFFieldLoop != None:
95 #self.m_log.debug("fill: line %d -> EndMFFieldLoop", lineNum);
96 self._processLoop("MFields", loopLines, context);
97 inLoop = False;
98 loopLines = [];
99 continue;
101 loopLines.append(line);
102 continue;
104 # handle @@AdditionalIncludes
105 matchAdditionalIncludes = self.m_AdditionIncludesRE.search(line);
106 if matchAdditionalIncludes != None:
107 self._processAdditionalIncludes(dictList);
108 continue;
110 # handle @@AdditionalIncludes
111 matchAdditionalPrioIncludes = self.m_AdditionPrioIncludesRE.search(line);
112 if matchAdditionalPrioIncludes != None:
113 self._processAdditionalPrioIncludes(dictList);
114 continue;
116 # conditionals outside of loops must be treated here
118 # handle @@if
119 matchIf = self.m_ifRE.search(line);
120 if matchIf != None:
121 #self.m_log.debug("fill: line %d -> if", lineNum);
122 skipStack.push(copy.copy(skipCurrent));
124 if skipStack.top() == False:
125 if self._lookup(matchIf.group(2), dictList) == True:
126 skipCurrent = False;
127 else:
128 skipCurrent = True;
130 if matchIf.group(1) == "!":
131 skipCurrent = not skipCurrent;
132 continue;
134 # handle @@else
135 matchElse = self.m_elseRE.search(line);
136 if matchElse != None:
137 #self.m_log.debug("fill: line %d -> else", lineNum);
138 if skipStack.top() == False:
139 skipCurrent = not skipCurrent;
140 continue;
142 # handle @@endif
143 matchEndif = self.m_endifRE.search(line);
144 if matchEndif != None:
145 #self.m_log.debug("fill: line %d -> endif", lineNum);
146 skipCurrent = skipStack.top();
147 skipStack.pop();
148 continue;
150 if skipCurrent == True:
151 continue;
153 # a line with regular text - substitute variables and add to output
154 self.m_outLines.append(self._substituteVariables(line, context));
156 return self.m_outLines;
158 def _processAdditionalIncludes(self, context):
159 includeList = self._lookup("AdditionalIncludes", context);
161 for include in includeList:
162 self.m_outLines.append("#include <" + include + ">\n");
164 def _processAdditionalPrioIncludes(self, context):
165 includeList = self._lookup("AdditionalPriorityIncludes", context);
167 for include in includeList:
168 self.m_outLines.append("#include <" + include + ">\n");
170 def _processLoop(self, loopType, loopLines, context):
171 """For loopType == "Fields" repeat lines in loopLines for all fields
172 for loopType == "SFields" repeat lines in loopLines for all sfields
173 for loopType == "MFields" repeat lines in loopLines for all mfields
175 if loopType == "Fields" or loopType == "SFields" or loopType == "MFields":
176 fields = self._lookup(loopType, context);
177 else:
178 self.m_log.error("_processLoop: unknown loopType \"%s\"." % loopType);
179 return;
181 localDict = dict([("field", None)]);
182 loopContext = [localDict];
183 for c in context:
184 loopContext.append(c);
186 for field in fields:
187 localDict["field"] = field;
189 skipStack = ListStack();
190 skipCurrent = False;
192 for line in loopLines:
193 # handle @@if
194 matchIf = self.m_ifRE.search(line);
195 if matchIf != None:
196 skipStack.push(copy.copy(skipCurrent));
198 if skipStack.top() == False:
199 if self._lookup(matchIf.group(2), loopContext) == True:
200 skipCurrent = False;
201 else:
202 skipCurrent = True;
204 if matchIf.group(1) == "!":
205 skipCurrent = not skipCurrent;
206 continue;
208 # handle @@else
209 matchElse = self.m_elseRE.search(line);
210 if matchElse != None:
211 if skipStack.top() == False:
212 skipCurrent = not skipCurrent;
213 continue;
215 # handle @@endif
216 matchEndif = self.m_endifRE.search(line);
217 if matchEndif != None:
218 skipCurrent = skipStack.top();
219 skipStack.pop();
220 continue;
222 if skipCurrent == True:
223 continue;
225 # a line with regular text - substitute variables and add to output
226 self.m_outLines.append(self._substituteVariables(line, loopContext));
228 def _substituteVariables(self, inLine, context):
229 """Replace all variables in inLine and return the resulting line.
231 indexOffset = 0;
232 outLine = inLine[:];
233 for matchVar in self.m_varRE.finditer(inLine):
234 varString = matchVar.group(1);
235 varLen = len(varString) + 4;
237 if varString.find(":") != -1:
238 varName = varString.split(":")[0];
239 varFieldLen = int(varString.split(":")[1]);
240 else:
241 varName = varString;
242 varFieldLen = 0;
244 varValue = self._lookup(varName, context);
245 varValue = varValue.ljust(varFieldLen);
246 repLen = len(varValue);
248 outLine = outLine[:matchVar.start()+indexOffset] + varValue + \
249 outLine[matchVar.end()+indexOffset:];
250 indexOffset = indexOffset + (repLen - varLen);
252 return outLine;
254 def _lookup(self, var, context):
255 """Determine the value of var in the given context, which is a dict or
256 a list of dicts.
257 var may consist of multiple parts separated by dots, i.e.
258 field.prevField.Name
259 In that case the first part is looked up in the given context, the
260 next part in the context returned by the first lookup and so forth.
262 #self.m_log.debug("_lookup: var: %s" % var);
264 varParts = var.split(".");
265 value = None;
267 for part in varParts:
268 if isinstance(context, list):
269 for elem in context:
270 if elem.has_key(part):
271 value = elem[part];
272 break;
273 elif context.has_key(part):
274 value = context[part];
275 else:
276 value = context;
278 if value == None:
279 self.m_log.warning("_lookup: value is None for var: %s part: %s",
280 var, part);
281 break;
283 context = value;
284 return value;