Initial commit
[profile/ivi/openjade.git] / style / ProcessingMode.cxx
1 // Copyright (c) 1996, 1997 James Clark
2 // See the file copying.txt for copying permission.
3
4 #include "stylelib.h"
5 #include "ProcessingMode.h"
6 #include "Interpreter.h"
7 #include "MessageArg.h"
8 #include "InterpreterMessages.h"
9 #include "Expression.h"
10 #include "Insn.h"
11 #include "Insn2.h"
12 #include "IListIter.h"
13 #include "LocNode.h"
14 #include "macros.h"
15 #include <stdlib.h>
16
17 #ifdef DSSSL_NAMESPACE
18 namespace DSSSL_NAMESPACE {
19 #endif
20
21 ProcessingMode::ProcessingMode(const StringC &name, const ProcessingMode *initial)
22 : Named(name), initial_(initial), defined_(0)
23 {
24 }
25
26 void ProcessingMode::compile(Interpreter &interp)
27 {
28   for (int i = 0; i < nRuleType; i++) {
29     for (size_t j = 0; j < rootRules_[i].size(); j++)
30       rootRules_[i][j].action().compile(interp, RuleType(i));
31     for (IListIter<ElementRule> iter(elementRules_[i]); !iter.done(); iter.next())
32       iter.cur()->action().compile(interp, RuleType(i));
33   }
34 }
35
36 void ProcessingMode::GroveRules::build(const IList<ElementRule> *lists,
37                                        const NodePtr &node,
38                                        Messenger &)
39 {
40   built = 1;
41   for (int ruleType = 0; ruleType < nRuleType; ruleType++) {
42     for (IListIter<ElementRule> iter(lists[ruleType]); !iter.done(); iter.next()) {
43       StringC gi;
44       if (iter.cur()->mustHaveGi(gi)) {
45         Interpreter::normalizeGeneralName(node, gi);
46         ElementRules *p = elementTable.lookup(gi);
47         if (!p) {
48           p = new ElementRules(gi);
49           elementTable.insert(p);
50         }
51         p->rules[ruleType].push_back(iter.cur());
52       }
53       else
54         otherRules[ruleType].push_back(iter.cur());
55     }
56   }
57   for (int ruleType = 0; ruleType < nRuleType; ruleType++) {
58     NamedTableIter<ElementRules> iter(elementTable);
59     for (;;) {
60       ElementRules *p = iter.next();
61       if (!p)
62         break;
63       size_t j = p->rules[ruleType].size();
64       p->rules[ruleType].resize(p->rules[ruleType].size() + otherRules[ruleType].size());
65       for (size_t i = 0; i < otherRules[ruleType].size(); i++)
66         p->rules[ruleType][j++] = otherRules[ruleType][i];
67       sortRules(p->rules[ruleType]);
68     }
69     sortRules(otherRules[ruleType]);
70   }
71 }
72
73 extern "C" {
74
75 static
76 int ruleCompare(const void *p1, const void *p2)
77 {
78   return (*(const ProcessingMode::Rule *const *)p1)
79          ->compareSpecificity(**(const ProcessingMode::Rule *const *)p2);
80 }
81
82 }
83
84 void ProcessingMode::GroveRules::sortRules(Vector<const ElementRule *> &v)
85 {
86   qsort(&v[0], v.size(), sizeof(v[0]), ruleCompare);
87 }
88
89 ProcessingMode::Action::Action(unsigned partIndex, Owner<Expression> &expr,
90                            const Location &loc)
91 : partIndex_(partIndex), defLoc_(loc), sosofo_(0)
92 {
93   expr.swap(expr_);
94 }
95
96 ProcessingMode::Rule::Rule()
97 {
98 }
99
100 ProcessingMode::Rule::Rule(const Ptr<Action> &action)
101 : action_(action)
102 {
103 }
104
105 int ProcessingMode::Rule::compareSpecificity(const Rule &r) const
106 {
107   unsigned i1 = action().partIndex();
108   unsigned i2 = r.action().partIndex();
109   if (i1 == i2)
110     return 0;
111   return i1 < i2 ? -1 : 1;
112 }
113
114 void ProcessingMode::Action::compile(Interpreter &interp, RuleType ruleType)
115 {
116   expr_->optimize(interp, Environment(), expr_);
117   ELObj *tem = expr_->constantValue();
118   if (tem) {
119     if (ruleType == constructionRule) {
120       sosofo_ = tem->asSosofo();
121       if (sosofo_)
122         return;
123     }
124   }
125   InsnPtr check;
126   if (ruleType == constructionRule)
127     check = new CheckSosofoInsn(defLoc_, check);
128   insn_ = expr_->compile(interp, Environment(), 0, check);
129 }
130
131 ProcessingMode::ElementRule::ElementRule(const Ptr<Action> &action,
132                                          Pattern &pattern)
133 : Rule(action)
134 {
135   pattern.swap(*this);
136 }
137
138 int ProcessingMode::ElementRule::compareSpecificity(const Rule &r) const
139 {
140   int result = Rule::compareSpecificity(r);
141   if (result)
142     return result;
143   return Pattern::compareSpecificity(*this, (const ElementRule &)r);
144 }
145
146 void ProcessingMode::addRule(bool root,
147                              NCVector<Pattern> &patterns,
148                              Owner<Expression> &expr,
149                              RuleType ruleType,
150                              const Location &loc,
151                              Interpreter &interp)
152 {
153   Ptr<Action> action = new Action(interp.currentPartIndex(), expr, loc);
154   for (size_t i = 0; i < patterns.size(); i++)
155     elementRules_[ruleType].insert(new ElementRule(action, patterns[i]));
156   if (!root)
157     return;
158   Vector<Rule> &rules = rootRules_[ruleType];
159   rules.push_back(Rule(action));
160   for (size_t i = rules.size() - 1; i > 0; i--) {
161     int cmp = rules[i - 1].compareSpecificity(rules[i]);
162     if (cmp <= 0) {
163       if (cmp == 0 && ruleType == constructionRule) {
164         interp.setNextLocation(loc);
165         interp.message(InterpreterMessages::duplicateRootRule,
166                        rules[i - 1].location());
167       }
168       break;
169     }
170     rules[i - 1].swap(rules[i]);
171   }
172 }
173
174 ProcessingMode::GroveRules::GroveRules()
175 : built(0)
176 {
177 }
178
179 ProcessingMode::ElementRules::ElementRules(const StringC &name)
180 : Named(name)
181 {
182 }
183
184 // Specificity gives specificity of last match; get specificity of current match.
185
186 const ProcessingMode::Rule *
187 ProcessingMode::findMatch(const NodePtr &node,
188                           Pattern::MatchContext &context,
189                           Messenger &mgr,
190                           Specificity &specificity) const
191 {
192   GroveString gi;
193   if (node->getGi(gi) == accessOK)
194     return findElementMatch(StringC(gi.data(), gi.size()), node, context, mgr,
195                             specificity);
196   NodePtr tem;
197   if (node->getOrigin(tem) != accessOK)
198     return findRootMatch(node, context, mgr, specificity);
199   return 0;
200 }
201
202
203 const ProcessingMode::Rule *
204 ProcessingMode::findElementMatch(const StringC &gi,
205                                  const NodePtr &node,
206                                  Pattern::MatchContext &context,
207                                  Messenger &mgr,
208                                  Specificity &specificity) const
209 {
210   const Vector<const ElementRule *> *vecP = 0;
211
212   for (;;) {
213     for (;;) {
214       const ProcessingMode &mode
215         = *(initial_ && specificity.toInitial_ ? initial_ : this);
216       if (!vecP) {
217         const GroveRules &gr = mode.groveRules(node, mgr);
218         const ElementRules *er = gr.elementTable.lookup(gi);
219         vecP = er ? er->rules : gr.otherRules;
220       }
221       const Vector<const ElementRule *> &vec = vecP[specificity.ruleType_];
222       ASSERT(specificity.nextRuleIndex_ <= vec.size());
223       for (size_t &i = specificity.nextRuleIndex_; i < vec.size(); i++) {
224         if (vec[i]->trivial() || vec[i]->matches(node, context)) {
225           const Rule *rule = vec[i];
226           elementRuleAdvance(node, context, mgr, specificity, vec);
227           return rule;
228         }
229       }
230       if (!initial_)
231         break;
232       vecP = 0;
233       if (specificity.toInitial_)
234         break;
235       specificity.nextRuleIndex_ = 0;
236       specificity.toInitial_ = 1;
237     }
238     if (specificity.ruleType_ == constructionRule)
239       break;
240     specificity.ruleType_ = constructionRule;
241     specificity.nextRuleIndex_ = 0;
242     specificity.toInitial_ = 0;
243   }
244   return 0;
245 }
246
247 const ProcessingMode::Rule *
248 ProcessingMode::findRootMatch(const NodePtr &node,
249                               Pattern::MatchContext &context,
250                               Messenger &mgr,
251                               Specificity &specificity) const
252 {
253   for (;;) {
254     for (;;) {
255       const ProcessingMode &mode = *(initial_ && specificity.toInitial_ ? initial_ : this);
256       const Vector<Rule> &rules = mode.rootRules_[specificity.ruleType_];
257       if (specificity.nextRuleIndex_ < rules.size())
258         return &rules[specificity.nextRuleIndex_++];
259       if (!initial_ || specificity.toInitial_)
260         break;
261       specificity.nextRuleIndex_ = 0;
262       specificity.toInitial_ = 1;
263     }
264     if (specificity.ruleType_ == constructionRule)
265       break;
266     specificity.ruleType_ = constructionRule;
267     specificity.nextRuleIndex_ = 0;
268     specificity.toInitial_ = 0;
269   }
270   return 0;
271 }
272
273 const ProcessingMode::GroveRules &ProcessingMode::groveRules(const NodePtr &node,
274                                                              Messenger &mgr) const
275 {
276   unsigned long n = node->groveIndex();
277   ProcessingMode *cache = (ProcessingMode *)this;
278   if (n >= groveRules_.size())
279     cache->groveRules_.resize(n + 1);
280   if (!groveRules_[n].built)
281     cache->groveRules_[n].build(elementRules_, node, mgr);
282   return groveRules_[n];
283 }
284
285 void ProcessingMode::elementRuleAdvance(const NodePtr &node,
286                                         Pattern::MatchContext &context,
287                                         Messenger &mgr,
288                                         Specificity &specificity,
289                                         const Vector<const ElementRule *> &vec)
290 {
291   size_t &i = specificity.nextRuleIndex_;
292   if (specificity.ruleType_ != constructionRule) {
293     ++i;
294     return;
295   }
296   size_t hit = i;
297   do {
298     ++i;
299     if (i >= vec.size()
300         || vec[hit]->ElementRule::compareSpecificity(*vec[i]) != 0)
301       return;
302   } while (!(vec[i]->trivial() || vec[i]->matches(node, context)));
303
304   const LocNode *lnp;
305   Location nodeLoc;
306   if ((lnp = LocNode::convert(node)) != 0
307       && lnp->getLocation(nodeLoc) == accessOK)
308     mgr.setNextLocation(nodeLoc);
309   mgr.message(InterpreterMessages::ambiguousMatch);
310   do {
311     ++i;
312   } while (i < vec.size()
313            && vec[hit]->ElementRule::compareSpecificity(*vec[i]) == 0);
314 }
315
316 #ifdef DSSSL_NAMESPACE
317 }
318 #endif