root/branches/Carsten_PtrWork2/Tools/fcd2code/TemplateFiller.py

Revision 1032, 12.8 kB (checked in by cneumann, 1 year ago)

added: generic interface
changed: factory functions return RefPtr?

The unittests don't pass right now, because of the change
to the factory functions, which leads to containers
being immediately destroyed as they are not assigned to
a RefPtr?.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1
2 import copy;
3 import logging;
4 import re;
5
6 from ListStack import ListStack;
7
8 class TemplateFiller:
9     """Fill in a template.
10     """
11
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 = [];
19        
20         self.m_varRE              = re.compile(r"@!([^!@]*)!@");
21         self.m_ifRE               = re.compile(r"@@if([^/]*)");
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
32     def fill(self, dictList):
33         """Fill in a template using the contents of the dictionaries in
34            dictList.
35         """
36         self.m_outLines = [];
37        
38         skipStack   = ListStack();
39         skipCurrent = False;
40         inLoop      = False;
41         loopLines   = [];
42        
43         # Go through template and find loops, collect their lines in loopLines.
44         # call _processLoop for the loopLines.
45         
46         context = [d for d in dictList];
47        
48         for lineNum, line in enumerate(self.m_inLines):
49             # handle @@BeginFieldLoop
50             matchBeginFieldLoop = self.m_BeginFieldLoopRE.search(line);
51             if (not skipCurrent) and (matchBeginFieldLoop != None):
52                 self.m_log.debug("fill: line %d -> BeginFieldLoop", lineNum);
53                 inLoop = True;
54                 continue;
55            
56             # handle @@BeginSFFieldLoop
57             matchBeginSFFieldLoop = self.m_BeginSFFieldLoopRE.search(line);
58             if (not skipCurrent) and (matchBeginSFFieldLoop != None):
59                 self.m_log.debug("fill: line %d -> BeginSFFieldLoop", lineNum);
60                 inLoop = True;
61                 continue;
62            
63             # handle @@BeginMFFieldLoop
64             matchBeginMFFieldLoop = self.m_BeginMFFieldLoopRE.search(line);
65             if (not skipCurrent) and (matchBeginMFFieldLoop != None):
66                 self.m_log.debug("fill: line %d -> BeginMFFieldLoop", lineNum);
67                 inLoop = True;
68                 continue;
69            
70             # handle loops - do not bother with conditionals they are handled in
71             # _processLoop
72             if (not skipCurrent) and (inLoop == True):
73                 # handle @@EndFieldLoop
74                 matchEndFieldLoop = self.m_EndFieldLoopRE.search(line);
75                 if matchEndFieldLoop != None:
76                     self.m_log.debug("fill: line %d -> EndFieldLoop", lineNum);
77                     self._processLoop("Fields", loopLines, context);
78                     inLoop    = False;
79                     loopLines = [];
80                     continue;
81                
82                 # handle @@EndSFFieldLoop
83                 matchEndSFFieldLoop = self.m_EndSFFieldLoopRE.search(line);
84                 if matchEndSFFieldLoop != None:
85                     self.m_log.debug("fill: line %d -> EndSFFieldLoop", lineNum);
86                     self._processLoop("SFields", loopLines, context);
87                     inLoop    = False;
88                     loopLines = [];
89                     continue;
90                
91                 # handle @@EndMFFieldLoop
92                 matchEndMFFieldLoop = self.m_EndMFFieldLoopRE.search(line);
93                 if matchEndMFFieldLoop != None:
94                     self.m_log.debug("fill: line %d -> EndMFFieldLoop", lineNum);
95                     self._processLoop("MFields", loopLines, context);
96                     inLoop    = False;
97                     loopLines = [];
98                     continue;
99                
100                 loopLines.append(line);
101                 continue;
102            
103             # handle @@AdditionalIncludes
104             matchAdditionalIncludes = self.m_AdditionIncludesRE.search(line);
105             if matchAdditionalIncludes != None:
106                 self._processAdditionalIncludes(dictList);
107                 continue;
108            
109             # conditionals outside of loops must be treated here
110             
111             # handle @@if
112             matchIf = self.m_ifRE.search(line);
113             if matchIf != None:
114                 self.m_log.debug("fill: line %d -> if", lineNum);
115                 skipStack.push(copy.copy(skipCurrent));
116                
117                 if skipStack.top() == False:
118                     if self._evalConditional(matchIf.group(1), context) == True:
119                         skipCurrent = False;
120                     else:
121                         skipCurrent = True;
122                 continue;
123                
124 #                 if skipStack.top() == False:
125 #                     if self._lookup(matchIf.group(2), dictList) == True:
126 #                         skipCurrent = False;
127 #                     else:
128 #                         skipCurrent = True;
129 #                     
130 #                     if matchIf.group(1) == "!":
131 #                         skipCurrent = not skipCurrent;
132 #                 continue;
133             
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;
141                
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;
149            
150             if skipCurrent == True:
151                 continue;
152            
153             # a line with regular text - substitute variables and add to output
154             self.m_outLines.append(self._substituteVariables(line, context));
155        
156         return self.m_outLines;
157    
158     def _evalConditional(self, inLine, context):     
159         """Replace all variables in inLine and return the resulting line.
160         """
161         self.m_log.debug("_evalConditional: inLine: >%s<" % inLine);
162        
163         indexOffset = 0;
164         outLine     = inLine[:];
165         for matchVar in self.m_varRE.finditer(inLine):
166             varString = matchVar.group(1);
167             varLen    = len(varString) + 4;
168            
169             if varString.find(":") != -1:
170                 varName     = varString.split(":")[0];
171                 varFieldLen = int(varString.split(":")[1]);
172             else:
173                 varName     = varString;
174                 varFieldLen = 0;
175            
176             self.m_log.debug("_evalConditional: varName: >%s<" % varName);
177                
178             varValue = self._lookup(varName, context);
179            
180             if isinstance(varValue, str):
181                 varValue = "\"" + str(varValue) + "\"";
182             else:   
183                 varValue = str(varValue);
184            
185 #             varValue = str(self._lookup(varName, context));
186             varValue = varValue.ljust(varFieldLen);
187             repLen   = len(varValue);
188            
189             outLine = outLine[:matchVar.start()+indexOffset] + varValue + \
190                       outLine[matchVar.end()+indexOffset:];
191             indexOffset = indexOffset + (repLen - varLen);
192        
193         return eval(outLine);
194      
195     def _processAdditionalIncludes(self, context):
196         includeList = self._lookup("AdditionalIncludes", context);
197        
198         for include in includeList:
199             self.m_outLines.append("#include <" + include + ">");
200    
201     def _processLoop(self, loopType, loopLines, context):
202         """For loopType == "Fields"  repeat lines in loopLines for all fields
203            for loopType == "SFields" repeat lines in loopLines for all sfields
204            for loopType == "MFields" repeat lines in loopLines for all mfields
205         """
206         if loopType == "Fields" or loopType == "SFields" or loopType == "MFields":
207             fields = self._lookup(loopType, context);
208         else:
209             self.m_log.error("_processLoop: unknown loopType \"%s\"." % loopType);
210             return;
211        
212         localDict = dict([("field", None)]);
213         loopContext = [localDict];
214         for c in context:
215             loopContext.append(c);
216        
217         for field in fields:
218             localDict["field"] = field;
219            
220             skipStack   = ListStack();
221             skipCurrent = False;
222            
223             for line in loopLines:
224                 # handle @@if
225                 matchIf = self.m_ifRE.search(line);
226                 if matchIf != None:
227                     skipStack.push(copy.copy(skipCurrent));
228                    
229                     if skipStack.top() == False:
230                         if self._evalConditional(matchIf.group(1), loopContext) == True:
231                             skipCurrent = False;
232                         else:
233                             skipCurrent = True;
234                     continue;
235                    
236 #                     if skipStack.top() == False:
237 #                         if self._lookup(matchIf.group(2), loopContext) == True:
238 #                             skipCurrent = False;
239 #                         else:
240 #                             skipCurrent = True;
241 #                         
242 #                         if matchIf.group(1) == "!":
243 #                             skipCurrent = not skipCurrent;
244 #                     continue;
245                 
246                 # handle @@else
247                 matchElse = self.m_elseRE.search(line);
248                 if matchElse != None:
249                     if skipStack.top() == False:
250                         skipCurrent = not skipCurrent;
251                     continue;
252                    
253                 # handle @@endif
254                 matchEndif = self.m_endifRE.search(line);
255                 if matchEndif != None:
256                     skipCurrent = skipStack.top();
257                     skipStack.pop();
258                     continue;
259                
260                 if skipCurrent == True:
261                     continue;
262                
263                 # a line with regular text - substitute variables and add to output
264                 self.m_outLines.append(self._substituteVariables(line, loopContext));
265    
266     def _substituteVariables(self, inLine, context):
267         """Replace all variables in inLine and return the resulting line.
268         """
269        
270         self.m_log.debug("_substituteVariables: inLine: >%s<" % inLine);
271        
272         indexOffset = 0;
273         outLine = inLine[:];
274         for matchVar in self.m_varRE.finditer(inLine):
275             varString = matchVar.group(1);
276             varLen    = len(varString) + 4;
277            
278             if varString.find(":") != -1:
279                 varName     = varString.split(":")[0];
280                 varFieldLen = int(varString.split(":")[1]);
281             else:
282                 varName     = varString;
283                 varFieldLen = 0;
284            
285             varValue = self._lookup(varName, context);
286             varValue = varValue.ljust(varFieldLen);
287             repLen   = len(varValue);
288            
289             outLine = outLine[:matchVar.start()+indexOffset] + varValue + \
290                       outLine[matchVar.end()+indexOffset:];
291             indexOffset = indexOffset + (repLen - varLen);
292        
293         return outLine;
294    
295     def _lookup(self, var, context):
296         """Determine the value of var in the given context, which is a dict or
297            a list of dicts.
298            var may consist of multiple parts separated by dots, i.e.
299            field.prevField.Name
300            In that case the first part is looked up in the given context, the
301            next part in the context returned by the first lookup and so forth.
302         """
303         self.m_log.debug("_lookup: var: >%s<" % var);
304        
305         varParts = var.split(".");
306         value    = None;
307        
308         for part in varParts:
309             if isinstance(context, list):
310                 for elem in context:
311                     if elem.has_key(part):
312                         value = elem[part];
313                         break;
314             elif context.has_key(part):
315                 value = context[part];
316             else:
317                 value = context;
318            
319             if value == None:
320                 self.m_log.warning("_lookup: value is None for var: >%s< part: >%s<",
321                     var, part);
322                 break;
323            
324             context = value;
325         return value;
326    
Note: See TracBrowser for help on using the browser.