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/
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.
12 * The Original Code is the Sablotron XSLT Processor.
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.
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
39 #define iterate(VAR, LST) for(int VAR = 0; VAR < (LST).number(); VAR++)
41 void varDump(VarsList *which, char *text)
43 printf("'%s': variable dump at level %d/%d\n", text, which -> currCallLevel,
44 which -> currNestLevel);
46 whichNumber = which -> number();
47 for (i = 0; i < whichNumber; i++)
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++)
53 printf("%s%d/%d ", (record -> bindings[j] -> prebinding ? "P":""),
54 record -> bindings[j] -> callLevel,
55 record -> bindings[j] -> nestLevel);
62 /*****************************************************************
63 V a r B i n d i n g I t e m
64 *****************************************************************/
66 VarBindingItem::~VarBindingItem()
71 /*****************************************************************
73 *****************************************************************/
75 VarBindings::~VarBindings()
77 bindings.freeall(FALSE);
80 /*****************************************************************
82 *****************************************************************/
84 VarsList::VarsList(Tree& sheet_)
85 : SList<VarBindings*>(1), sheet(sheet_)
87 currCallLevel = currNestLevel = 0;
95 VarBindings* VarsList::find(QName &name)
97 for (int i = 0; i < number(); i++)
98 if (sheet.cmpQNames((*this)[i] -> varname,name))
103 int VarsList::compare(int first, int second, void *data)
106 &q1 = (*this)[first] -> varname,
107 &q2 = (*this)[second] -> varname;
108 int u = sheet.expand(q1.getUri()).compare(sheet.expand(q2.getUri()));
110 u = sheet.expand(q1.getLocal()).compare(sheet.expand(q2.getLocal()));
114 VarBindings* VarsList::getOrAdd(QName &q)
116 VarBindings *record = find(q);
119 record = new VarBindings(q);
125 eFlag VarsList::addBinding(Sit S, QName& q, Expression *e, Bool force)
127 VarBindings *record = getOrAdd(q);
128 VarBindingItem *lastbind = NULL;
130 if (!record -> bindings.isEmpty())
132 lastbind = record -> bindings.last();
133 if (lastbind -> callLevel == currCallLevel) // && !lastbind -> prebinding)
134 Err1(S, E1_MULT_ASSIGNMENT, (char*)sheet.expand(q.getLocal()));
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,
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 &&
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) );
162 eFlag VarsList::addPrebinding(Sit S, QName &q, Expression *e)
164 VarBindings *record = getOrAdd(q);
165 VarBindingItem *lastbind = NULL;
167 if (!record -> bindings.isEmpty())
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()));
176 VarBindingItem *it = new VarBindingItem;
177 it -> callLevel = currCallLevel;
178 it -> nestLevel = currNestLevel;
180 it -> prebinding = TRUE;
181 record -> bindings.append(it);
186 void VarsList::rmBinding(QName &q)
188 VarBindings *record = find(q);
189 assert(record && record -> bindings.number());
190 record -> bindings.freelast(FALSE);
193 Expression* VarsList::getBinding(QName &q)
195 VarBindings *record = find(q);
198 return getBinding(record);
201 Expression* VarsList::getBinding(VarBindings* record)
203 if (!record || record -> bindings.isEmpty())
206 for (int i = record -> bindings.number() - 1;
207 (i >= 0) && (record -> bindings[i] -> callLevel == currCallLevel);
210 if (!record -> bindings[i] -> prebinding)
211 return record -> bindings[i] -> expr;
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;
220 if ((record -> bindings.number() > 1) &&
221 (record -> bindings[1] -> callLevel == 1))
222 return record -> bindings[1] -> expr;
228 void VarsList::startCall()
231 // varDump(this, "startCall");
234 /*================================================================
236 ================================================================*/
238 void VarsList::_endCall(Bool rmLastLevelPrebs)
240 // varDump(this, "_endCall before");
241 VarBindingItem* lastbind;
242 for (int i = 0; i < number(); i++)
244 VarBindings *record = (*this)[i];
245 if (!record -> bindings.isEmpty())
247 while ( !record -> bindings.isEmpty() &&
248 (((lastbind=record -> bindings.last()) ->
249 callLevel == currCallLevel) ||
251 lastbind -> callLevel == currCallLevel - 1 &&
252 lastbind -> prebinding)) &&
253 lastbind -> nestLevel >= currNestLevel) // was ==
255 record -> bindings.freelast(FALSE);
259 // varDump(this, "_endCall after");
263 void VarsList::endCall()
268 void VarsList::startNested()
273 void VarsList::endNested()
278 void VarsList::startApplyOne()
283 void VarsList::endApplyOne()
288 void VarsList::rmPrebindings()
290 VarBindingItem* lastbind;
291 for (int i = 0; i < number(); i++)
293 VarBindings *record = (*this)[i];
294 if (!record -> bindings.isEmpty() &&
295 (lastbind = record -> bindings.last()) -> callLevel == currCallLevel &&
296 lastbind -> prebinding &&
297 lastbind -> nestLevel >= currNestLevel)
299 record -> bindings.freelast(FALSE);
304 eFlag VarsList::openGlobal(Sit S, QName& name, VarBindings *&record)
309 insert(record = new VarBindings(name));
310 record -> isOpenGlobal = TRUE;
314 eFlag VarsList::closeGlobal(Sit S, VarBindings *record)
316 record -> isOpenGlobal = FALSE;
320 void VarsList::report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
322 S.message(type,code,arg1,arg2);
325 void VarsList::pushCallLevel(int level)
327 callLevels.append(currCallLevel);
328 currCallLevel = level;
331 void VarsList::popCallLevel()
333 currCallLevel = callLevels[callLevels.number() - 1];
334 callLevels.deppend();