added Info.plist
[TestXSLT.git] / libsablot / src / engine / vars.cpp
1 /* 
2  * The contents of this file are subject to the Mozilla Public
3  * License Version 1.1 (the "License"); you may not use this file
4  * except in compliance with the License. You may obtain a copy of
5  * the License at http://www.mozilla.org/MPL/
6  * 
7  * Software distributed under the License is distributed on an "AS
8  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9  * implied. See the License for the specific language governing
10  * rights and limitations under the License.
11  * 
12  * The Original Code is the Sablotron XSLT Processor.
13  * 
14  * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15  * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16  * Ginger Alliance Ltd. All Rights Reserved.
17  * 
18  * Contributor(s):
19  * 
20  * Alternatively, the contents of this file may be used under the
21  * terms of the GNU General Public License Version 2 or later (the
22  * "GPL"), in which case the provisions of the GPL are applicable 
23  * instead of those above.  If you wish to allow use of your 
24  * version of this file only under the terms of the GPL and not to
25  * allow others to use your version of this file under the MPL,
26  * indicate your decision by deleting the provisions above and
27  * replace them with the notice and other provisions required by
28  * the GPL.  If you do not delete the provisions above, a recipient
29  * may use your version of this file under either the MPL or the
30  * GPL.
31  */
32
33 #include "vars.h"
34 #include "situa.h"
35 #include "tree.h"
36
37 // GP: clean
38
39 #define iterate(VAR, LST) for(int VAR = 0; VAR < (LST).number(); VAR++)
40
41 void varDump(VarsList *which, char *text)
42 {
43     printf("'%s': variable dump at level %d/%d\n", text, which -> currCallLevel, 
44         which -> currNestLevel);
45     int i, 
46         whichNumber = which -> number();
47     for (i = 0; i < whichNumber; i++)
48     {
49         VarBindings *record = (*which)[i];
50         printf("%s ",(char *)(which -> sheet.expand(record -> varname.getLocal())));
51         for (int j = 0; j < record -> bindings.number(); j++)
52         {
53             printf("%s%d/%d ", (record -> bindings[j] -> prebinding ? "P":""),
54                 record -> bindings[j] -> callLevel, 
55                 record -> bindings[j] -> nestLevel);
56         }
57         puts("");
58     }
59     puts("");
60 }
61
62 /*****************************************************************
63     V a r B i n d i n g I t e m
64 *****************************************************************/
65
66 VarBindingItem::~VarBindingItem()
67 {
68     delete expr;
69 }
70
71 /*****************************************************************
72     V a r B i n d i n g s
73 *****************************************************************/
74
75 VarBindings::~VarBindings()
76 {
77     bindings.freeall(FALSE);
78 }
79
80 /*****************************************************************
81     V a r s L i s t
82 *****************************************************************/
83
84 VarsList::VarsList(Tree& sheet_)
85 : SList<VarBindings*>(1), sheet(sheet_)
86 {
87     currCallLevel = currNestLevel = 0;
88 }
89
90 VarsList::~VarsList()
91 {
92   freeall(FALSE);
93 }
94
95 VarBindings* VarsList::find(QName &name)
96 {
97     for (int i = 0; i < number(); i++)
98         if (sheet.cmpQNames((*this)[i] -> varname,name))
99             return (*this)[i];
100     return NULL;
101 }
102
103 int VarsList::compare(int first, int second, void *data)
104 {
105     const QName 
106         &q1 = (*this)[first] -> varname,
107         &q2 = (*this)[second] -> varname;
108     int u = sheet.expand(q1.getUri()).compare(sheet.expand(q2.getUri()));
109     if (u) return u;
110     u = sheet.expand(q1.getLocal()).compare(sheet.expand(q2.getLocal()));
111     return u;
112 }
113
114 VarBindings* VarsList::getOrAdd(QName &q)
115 {
116     VarBindings *record = find(q);
117     if (!record)
118     {
119         record = new VarBindings(q);
120         insert(record);
121     };
122     return record;
123 }
124
125 eFlag VarsList::addBinding(Sit S, QName& q, Expression *e, Bool force)
126 {
127     VarBindings *record = getOrAdd(q);
128     VarBindingItem *lastbind = NULL;
129
130     if (!record -> bindings.isEmpty())
131     {
132         lastbind = record -> bindings.last();
133         if (lastbind -> callLevel == currCallLevel) // && !lastbind -> prebinding)
134             Err1(S, E1_MULT_ASSIGNMENT, (char*)sheet.expand(q.getLocal()));
135     }
136
137     /*
138         construct the new binding item. if there is a pre-binding that applies,
139         just change it to a binding and drop the current expression. otherwise,
140         add the new item.
141     */
142
143     VarBindingItem *it;
144     record -> bindings.append(it = new VarBindingItem);
145     it -> callLevel = currCallLevel;
146     it -> nestLevel = currNestLevel;
147     it -> prebinding = FALSE;
148     if (lastbind && lastbind -> prebinding && 
149         lastbind -> callLevel == (currCallLevel - 1) && 
150         lastbind -> nestLevel == currNestLevel &&
151         !force)
152     {
153         it -> expr = new Expression(e -> getOwnerElement()); // GP: OK
154         delete e; // moved above the following line
155         E( lastbind -> expr -> eval(S, *(it -> expr), NULL) );
156     }
157     else
158         it -> expr = e;
159     return OK;
160 }
161
162 eFlag VarsList::addPrebinding(Sit S, QName &q, Expression *e)
163 {
164     VarBindings *record = getOrAdd(q);
165     VarBindingItem *lastbind = NULL;
166
167     if (!record -> bindings.isEmpty())
168     {
169         lastbind = record -> bindings.last();
170         if (lastbind -> nestLevel == currNestLevel && 
171             lastbind -> callLevel == currCallLevel &&    // new
172             lastbind -> prebinding)
173             Err1(S, E1_MULT_ASSIGNMENT, (char*)sheet.expand(q.getLocal()));
174     }
175
176     VarBindingItem *it = new VarBindingItem;
177     it -> callLevel = currCallLevel; 
178     it -> nestLevel = currNestLevel;
179     it -> expr = e;
180     it -> prebinding = TRUE;
181     record -> bindings.append(it);
182
183     return OK;
184 }
185
186 void VarsList::rmBinding(QName &q)
187 {
188     VarBindings *record = find(q);
189     assert(record && record -> bindings.number());
190     record -> bindings.freelast(FALSE);
191 }
192
193 Expression* VarsList::getBinding(QName &q)
194 {
195     VarBindings *record = find(q);
196     if (!record)
197         return NULL;
198     return getBinding(record);
199 }
200
201 Expression* VarsList::getBinding(VarBindings* record)
202 {
203     if (!record || record -> bindings.isEmpty()) 
204         return NULL;
205
206     for (int i = record -> bindings.number() - 1; 
207         (i >= 0) && (record -> bindings[i] -> callLevel == currCallLevel);
208         i--)
209         {
210             if (!record -> bindings[i] -> prebinding)
211                 return record -> bindings[i] -> expr;
212         };
213
214     // try to return the global value
215 //    if (!record -> bindings[0] -> callLevel && !record -> bindings[0] -> prebinding)
216     if (record -> bindings[0] -> callLevel == 1)
217         return record -> bindings[0] -> expr;
218     else 
219     {
220         if ((record -> bindings.number() > 1) && 
221         (record -> bindings[1] -> callLevel == 1))
222             return record -> bindings[1] -> expr;
223         else
224             return NULL;
225     }
226 }
227
228 void VarsList::startCall()
229 {
230     currCallLevel++;
231 //    varDump(this, "startCall");
232 }
233
234 /*================================================================
235 endCall
236 ================================================================*/
237
238 void VarsList::_endCall(Bool rmLastLevelPrebs)
239 {
240 //    varDump(this, "_endCall before");
241     VarBindingItem* lastbind;
242     for (int i = 0; i < number(); i++)
243     {
244         VarBindings *record = (*this)[i];
245         if (!record -> bindings.isEmpty())
246         {
247             while ( !record -> bindings.isEmpty() &&
248                     (((lastbind=record -> bindings.last()) -> 
249                             callLevel == currCallLevel) ||
250                         (rmLastLevelPrebs &&
251                             lastbind -> callLevel == currCallLevel - 1 &&
252                             lastbind -> prebinding)) && 
253                     lastbind -> nestLevel >= currNestLevel) // was ==
254             {
255                 record -> bindings.freelast(FALSE);
256             }
257         }
258     }
259 //    varDump(this, "_endCall after");
260     currCallLevel--;
261 }
262
263 void VarsList::endCall()
264 {
265     _endCall(TRUE);
266 }
267
268 void VarsList::startNested()
269 {
270     currNestLevel++;
271 }
272
273 void VarsList::endNested()
274 {
275     currNestLevel--;
276 }
277
278 void VarsList::startApplyOne()
279 {
280     startCall();
281 }
282
283 void VarsList::endApplyOne()
284 {
285     _endCall(FALSE);
286 }
287
288 void VarsList::rmPrebindings()
289 {
290     VarBindingItem* lastbind;
291     for (int i = 0; i < number(); i++)
292     {
293         VarBindings *record = (*this)[i];
294         if (!record -> bindings.isEmpty() && 
295             (lastbind = record -> bindings.last()) -> callLevel == currCallLevel &&
296             lastbind -> prebinding && 
297             lastbind -> nestLevel >= currNestLevel)
298         {
299             record -> bindings.freelast(FALSE);
300         }
301     }
302 }
303
304 eFlag VarsList::openGlobal(Sit S, QName& name, VarBindings *&record)
305 {
306     if (!record)
307         record = find(name);
308     if (!record)
309         insert(record = new VarBindings(name));
310     record -> isOpenGlobal = TRUE;
311     return OK;
312 }
313
314 eFlag VarsList::closeGlobal(Sit S, VarBindings *record)
315
316     record -> isOpenGlobal = FALSE; 
317     return OK;
318 }
319
320 void VarsList::report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
321 {
322     S.message(type,code,arg1,arg2);
323 }
324
325 void VarsList::pushCallLevel(int level)
326 {
327   callLevels.append(currCallLevel);
328   currCallLevel = level;
329 }
330
331 void VarsList::popCallLevel()
332 {
333   currCallLevel = callLevels[callLevels.number() - 1];
334   callLevels.deppend();
335 }