Initial commit
[profile/ivi/openjade.git] / style / ELObj.cxx
1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
3
4 #include "stylelib.h"
5 #include "ELObj.h"
6 #include "Interpreter.h"
7 #include "InterpreterMessages.h"
8 #include "macros.h"
9 #include <string.h>
10 #include <math.h>
11 #include <stdio.h>
12
13 #ifdef DSSSL_NAMESPACE
14 namespace DSSSL_NAMESPACE {
15 #endif
16
17 class ReverseNodeListObj : public NodeListObj {
18 public:
19   ReverseNodeListObj(NodeListObj *);
20   NodePtr nodeListFirst(EvalContext &, Interpreter &);
21   NodeListObj *nodeListRest(EvalContext &, Interpreter &);
22   NodeListObj *nodeListReverse(EvalContext &context, Interpreter &interp);
23   NodePtr nodeListRef(long, EvalContext &, Interpreter &);
24   long nodeListLength(EvalContext &context, Interpreter &interp);
25   void traceSubObjects(Collector &) const;
26 private:
27   NodeListObj *reversed(EvalContext &context, Interpreter &interp);
28   NodeListObj *nl_;
29   NodeListObj *reversed_;
30 };
31
32 ELObj::ELObj()
33 {
34   hasSubObjects_ = 0;
35 }
36
37 bool ELObj::isEqual(ELObj &)
38 {
39   return false;
40 }
41     
42 bool ELObj::isEquiv(ELObj &obj)
43 {
44   return isEqual(obj);
45 }
46     
47 bool ELObj::isNil() const
48 {
49   return false;
50 }
51
52 bool ELObj::isList() const
53 {
54   return false;
55 }
56
57 bool ELObj::isTrue() const
58 {
59   return true;
60 }
61
62 PairObj *ELObj::asPair()
63 {
64   return 0;
65 }
66
67 VectorObj *ELObj::asVector()
68 {
69   return 0;
70 }
71
72 SymbolObj *ELObj::asSymbol()
73 {
74   return 0;
75 }
76
77 KeywordObj *ELObj::asKeyword()
78 {
79   return 0;
80 }
81
82 StringObj *ELObj::convertToString()
83 {
84   return 0;
85 }
86
87 FunctionObj *ELObj::asFunction()
88 {
89   return 0;
90 }
91
92 SosofoObj *ELObj::asSosofo()
93 {
94   return 0;
95 }
96
97 AppendSosofoObj *ELObj::asAppendSosofo()
98 {
99   return 0;
100 }
101
102 ColorObj *ELObj::asColor()
103 {
104   return 0;
105 }
106
107 ColorSpaceObj *ELObj::asColorSpace()
108 {
109   return 0;
110 }
111
112 AddressObj *ELObj::asAddress()
113 {
114   return 0;
115 }
116
117 DisplaySpaceObj *ELObj::asDisplaySpace()
118 {
119   return 0;
120 }
121
122 InlineSpaceObj *ELObj::asInlineSpace()
123 {
124   return 0;
125 }
126
127 GlyphSubstTableObj *ELObj::asGlyphSubstTable()
128 {
129   return 0;
130 }
131
132 LanguageObj *ELObj::asLanguage()
133 {
134   return 0;
135 }
136
137 bool ELObj::optSingletonNodeList(EvalContext &, Interpreter &, NodePtr &)
138 {
139   return 0;
140 }
141
142 NodeListObj *ELObj::asNodeList()
143 {
144   return 0;
145 }
146
147 NamedNodeListObj *ELObj::asNamedNodeList()
148 {
149   return 0;
150 }
151
152 StyleObj *ELObj::asStyle()
153 {
154   return 0;
155 }
156
157 BoxObj *ELObj::asBox()
158 {
159   return 0;
160 }
161
162 void ELObj::print(Interpreter &interp, OutputCharStream &out)
163 {
164   out << "#<unknown object " << (unsigned long)this << ">";
165 }
166
167 void ELObj::print(Interpreter &interp, OutputCharStream &out, unsigned)
168 {
169   print(interp, out);
170 }
171
172 bool ELObj::exactIntegerValue(long &)
173 {
174   return false;
175 }
176
177 bool ELObj::realValue(double &)
178 {
179   return false;
180 }
181
182 bool ELObj::inexactRealValue(double &)
183 {
184   return false;
185 }
186
187 bool ELObj::lengthValue(long &n)
188 {
189   return false;
190 }
191
192 ELObj::QuantityType ELObj::quantityValue(long &, double &, int &)
193 {
194   return noQuantity;
195 }
196
197 const LengthSpec *ELObj::lengthSpec() const
198 {
199   return 0;
200 }
201
202 bool ELObj::stringData(const Char *&, size_t &)
203 {
204   return false;
205 }
206
207 bool ELObj::charValue(Char &)
208 {
209   return false;
210 }
211
212 const FOTBuilder::GlyphId *ELObj::glyphId() const
213 {
214   return 0;
215 }
216
217 ELObj *ELObj::resolveQuantities(bool, Interpreter &, const Location &)
218 {
219   return this;
220 }
221
222 ErrorObj::ErrorObj()
223 {
224 }
225
226 void ErrorObj::print(Interpreter &interp, OutputCharStream &out)
227 {
228   out << "#<error>";
229 }
230
231 UnspecifiedObj::UnspecifiedObj()
232 {
233 }
234
235 void UnspecifiedObj::print(Interpreter &interp, OutputCharStream &out)
236 {
237   out << "#v";
238 }
239
240 NilObj::NilObj()
241 {
242 }
243
244 bool NilObj::isNil() const
245 {
246   return true;
247 }
248
249 bool NilObj::isList() const
250 {
251   return true;
252 }
253
254 void NilObj::print(Interpreter &, OutputCharStream &out)
255 {
256   out << "()";
257 }
258
259 TrueObj::TrueObj()
260 {
261 }
262
263 void TrueObj::print(Interpreter &, OutputCharStream &out)
264 {
265   out << "#t";
266 }
267
268 FalseObj::FalseObj()
269 {
270 }
271
272 bool FalseObj::isTrue() const
273 {
274   return false;
275 }
276
277 void FalseObj::print(Interpreter &, OutputCharStream &out)
278 {
279   out << "#f";
280 }
281
282 SymbolObj::SymbolObj(StringObj *name)
283 : name_(name), cValue_(FOTBuilder::symbolFalse)
284 {
285   hasSubObjects_ = 1;
286 }
287
288 void SymbolObj::traceSubObjects(Collector &c) const
289 {
290   c.trace(name_);
291 }
292
293 void SymbolObj::print(Interpreter &interp, OutputCharStream &out)
294 {
295   out.write(name()->data(), name()->size());
296 }
297
298 SymbolObj *SymbolObj::asSymbol()
299 {
300   return this;
301 }
302
303 StringObj *SymbolObj::convertToString()
304 {
305   return name();
306 }
307
308 KeywordObj::KeywordObj(const Identifier *ident)
309 : ident_(ident)
310 {
311 }
312
313 KeywordObj *KeywordObj::asKeyword()
314 {
315   return this;
316 }
317
318 bool KeywordObj::isEqual(ELObj &obj)
319 {
320   KeywordObj *k = obj.asKeyword();
321   return k && k->ident_ == ident_;
322 }
323
324 void KeywordObj::print(Interpreter &interp, OutputCharStream &out)
325 {
326   out << ident_->name() << ":";
327 }
328
329 PairObj::PairObj(ELObj *car, ELObj *cdr)
330 : car_(car), cdr_(cdr)
331 {
332   hasSubObjects_ = 1;
333 }
334
335 bool PairObj::isEqual(ELObj &obj)
336 {
337   PairObj *p = obj.asPair();
338   // FIXME need non-recursive implementation
339   return p && equal(*p->car(), *car()) && equal(*p->cdr(), *cdr());
340 }
341
342 bool PairObj::isEquiv(ELObj &obj)
343 {
344   PairObj *p = obj.asPair();
345   // FIXME need non-recursive implementation
346   return p && eqv(*p->car(), *car()) && eqv(*p->cdr(), *cdr());
347 }
348
349 void PairObj::traceSubObjects(Collector &c) const
350 {
351   c.trace(car_);
352   c.trace(cdr_);
353 }
354
355 ELObj *PairObj::resolveQuantities(bool force, Interpreter &interp,
356                                   const Location &loc)
357 {
358   bool fail = 0;
359   PairObj *pair = this;
360   for (;;) {
361     ELObj *tem = pair->car_->resolveQuantities(force, interp, loc);
362     if (!tem)
363       fail = 1;
364     else {
365       if (pair->permanent())
366         interp.makePermanent(tem);
367       pair->car_ = tem;
368     }
369     PairObj *nextPair = pair->cdr_->asPair();
370     if (!nextPair)
371       break;
372     pair = nextPair;
373   }
374   ELObj *tem = pair->cdr_->resolveQuantities(force, interp, loc);
375   if (!tem)
376     fail = 1;
377   else {
378     if (pair->permanent())
379       interp.makePermanent(tem);
380     pair->cdr_ = tem;
381   }
382   if (fail)
383     return 0;
384   else
385     return this;
386 }
387
388
389 PairObj *PairObj::asPair()
390 {
391   return this;
392 }
393
394 bool PairObj::isList() const
395 {
396   ELObj *p = cdr_;
397   while (!p->isNil()) {
398     PairObj *pair = p->asPair();
399     if (!pair)
400       return false;
401     p = pair->cdr();
402   }
403   return true;
404 }
405
406 void PairObj::print(Interpreter &interp, OutputCharStream &out)
407 {
408   out << "(";
409   car_->print(interp, out);
410   ELObj *p = cdr_;
411   for (;;) {
412     if (p->isNil()) {
413       out << ")";
414       return;
415     }
416     PairObj *pair = p->asPair();
417     if (!pair) {
418       out << " . ";
419       p->print(interp, out);
420       out << ")";
421       return;
422     }
423     out << " ";
424     pair->car()->print(interp, out);
425     p = pair->cdr();
426   }
427 }
428
429 VectorObj::VectorObj()
430 {
431   hasSubObjects_ = 1;
432 }
433
434 VectorObj::VectorObj(Vector<ELObj *> &v)
435 {
436   hasSubObjects_ = 1;
437   v.swap(*this);
438 }
439
440 void VectorObj::traceSubObjects(Collector &c) const
441 {
442   for (size_t i = 0; i < Vector<ELObj *>::size(); i++)
443     c.trace((*this)[i]);
444 }
445
446 VectorObj *VectorObj::asVector()
447 {
448   return this;
449 }
450
451 bool VectorObj::isEquiv(ELObj &)
452 {
453   return 0;
454 }
455
456 bool VectorObj::isEqual(ELObj &obj)
457 {
458   VectorObj *v = obj.asVector();
459   if (!v)
460     return 0;
461   if (size() != v->size())
462     return 0;
463   for (size_t i = 0; i < size(); i++)
464     if (!equal(*(*this)[i], *(*v)[i]))
465       return 0;
466   return 1;
467 }
468
469 void VectorObj::print(Interpreter &interp, OutputCharStream &out)
470 {
471   out << "#(";
472   Vector<ELObj *> &v = *this;
473   for (size_t i = 0; i < v.size(); i++) {
474     if (i)
475       out << " ";
476     ELObj *tem = v[i];
477     if (!tem)
478       out << "#<cycle>";
479     else {
480       v[i] = 0;
481       tem->print(interp, out);
482       v[i] = tem;
483     }
484   }
485   out << ")";
486 }
487
488 ELObj *VectorObj::resolveQuantities(bool force, Interpreter &interp,
489                                     const Location &loc)
490 {
491   bool fail = 0;
492   Vector<ELObj *> &v = *this;
493   for (size_t i = 0; i < v.size(); i++) {
494     ELObj *tem = v[i]->resolveQuantities(force, interp, loc);
495     if (tem) {
496       if (permanent())
497         interp.makePermanent(tem);
498       v[i] = tem;
499     }
500     else
501       fail = 1;
502   }
503   if (fail)
504     return 0;
505   return this;
506 }
507
508 CharObj::CharObj(Char ch)
509 : ch_(ch)
510 {
511 }
512
513 void CharObj::display(Interpreter &interp, OutputCharStream &out) const
514 {
515   out.put(ch_);         // FIXME
516 }
517
518 void CharObj::print(Interpreter &, OutputCharStream &out)
519 {
520   out << "#\\";
521   out.put(ch_); // FIXME
522 }
523
524 bool CharObj::charValue(Char &c)
525 {
526   c = ch_;
527   return 1;
528 }
529
530 bool CharObj::isEqual(ELObj &obj)
531 {
532   Char c;
533   return obj.charValue(c) && c == ch_;
534 }
535
536 StringObj::StringObj()
537 {
538 }
539
540 StringObj::StringObj(const StringC &str)
541 : StringC(str)
542 {
543 }
544
545 StringObj::StringObj(const Char *s, size_t len)
546 : StringC(s, len)
547 {
548 }
549
550 bool StringObj::stringData(const Char *&s, size_t &n)
551 {
552   s = data();
553   n = size();
554   return true;
555 }
556
557 bool StringObj::isEqual(ELObj &obj)
558 {
559   const Char *s;
560   size_t n;
561   return (obj.stringData(s, n) 
562           && n == size()
563           && (n == 0 || memcmp(s, data(), n*sizeof(Char)) == 0));
564 }
565
566 StringObj *StringObj::convertToString()
567 {
568   return this;
569 }
570
571 void StringObj::print(Interpreter &interp, OutputCharStream &out)
572 {
573   // FIXME
574   out << "\"";
575   const Char *s = data();
576   for (size_t i = 0; i < size(); i++)
577     switch (s[i]) {
578     case '\\':
579     case '"':
580       out << "\\";
581       // fall through
582     default:
583       out.put(s[i]);
584       break;
585     }
586   out << "\"";
587 }
588
589 IntegerObj::IntegerObj()
590 : n_(0)
591 {
592 }
593
594 IntegerObj::IntegerObj(long n)
595 : n_(n)
596 {
597 }
598
599 bool IntegerObj::isEqual(ELObj &obj)
600 {
601   long n;
602   return obj.exactIntegerValue(n) && n == n_;
603 }
604
605 void IntegerObj::print(Interpreter &interp, OutputCharStream &out)
606 {
607   print(interp, out, 10);
608 }
609
610 void IntegerObj::print(Interpreter &, OutputCharStream &out, unsigned radix)
611 {
612   if (radix == 10) {
613     if (n_ < 0)
614       out << '-' << (unsigned long)-n_;
615     else
616       out << (unsigned long)n_;
617     return;
618   }
619
620   if (n_ == 0) {
621     out << '0';
622     return;
623   }
624   
625   unsigned long n;
626
627   if (n_ < 0) {
628     out << '-';
629     n = -n_;
630   }
631   else
632     n = n_;
633   
634   char buf[64];
635   int i = 0;
636
637   while (n != 0) {
638     buf[i++] = "0123456789abcdef"[n % radix];
639     n /= radix;
640   }
641
642   while (i > 0)
643     out << buf[--i];
644 }
645
646 bool IntegerObj::exactIntegerValue(long &n)
647 {
648   n = n_;
649   return true;
650 }
651
652 bool IntegerObj::realValue(double &n)
653 {
654   n = n_;
655   return true;
656 }
657
658 ELObj::QuantityType IntegerObj::quantityValue(long &val, double &, int &dim)
659 {
660   val = n_;
661   dim = 0;
662   return longQuantity;
663 }
664
665 RealObj::RealObj(double n)
666 : n_(n)
667 {
668 }
669
670 bool RealObj::isEqual(ELObj &obj)
671 {
672   double n;
673   return obj.inexactRealValue(n) && n == n_;
674 }
675
676
677 bool RealObj::realValue(double &n)
678 {
679   n = n_;
680   return true;
681 }
682
683 bool RealObj::inexactRealValue(double &n)
684 {
685   n = n_;
686   return true;
687 }
688
689 ELObj::QuantityType RealObj::quantityValue(long &, double &val, int &dim)
690 {
691   val = n_;
692   dim = 0;
693   return doubleQuantity;
694 }
695
696 void RealObj::print(Interpreter &, OutputCharStream &out)
697 {
698   char buf[1024];
699   sprintf(buf, "%g", n_);
700   out << buf;
701 }
702
703 LengthObj::LengthObj(long n)
704 : n_(n)
705 {
706 }
707
708 bool LengthObj::lengthValue(long &n)
709 {
710   n = n_;
711   return true;
712 }
713
714 ELObj::QuantityType LengthObj::quantityValue(long &val, double &, int &dim)
715 {
716   val = n_;
717   dim = 1;
718   return longQuantity;
719 }
720
721 bool LengthObj::isEqual(ELObj &obj)
722 {
723   long n;
724   double d;
725   int dim;
726   switch (obj.quantityValue(n, d, dim)) {
727   case noQuantity:
728     break;
729   case doubleQuantity:
730     return dim == 1 && d == n_;
731   case longQuantity:
732     return dim == 1 && n == n_;
733   }
734   return 0;
735 }
736
737 void LengthObj::print(Interpreter &interp, OutputCharStream &out)
738 {
739   char buf[1024];
740   sprintf(buf, "%gpt", n_ * 72.0/interp.unitsPerInch());
741   out << buf;
742 }
743
744 QuantityObj::QuantityObj(double val, int dim)
745 : val_(val), dim_(dim)
746 {
747 }
748
749 bool QuantityObj::isEqual(ELObj &obj)
750 {
751   long n;
752   double d;
753   int dim;
754   switch (obj.quantityValue(n, d, dim)) {
755   case noQuantity:
756     break;
757   case doubleQuantity:
758     return dim == dim_ && d == val_;
759   case longQuantity:
760     return dim == dim_ && n == val_;
761   }
762   return 0;
763 }
764
765 ELObj::QuantityType QuantityObj::quantityValue(long &, double &val, int &dim)
766 {
767   val = val_;
768   dim = dim_;
769   return doubleQuantity;
770 }
771
772 void QuantityObj::print(Interpreter &interp, OutputCharStream &out)
773 {
774   char buf[1024];
775   sprintf(buf, "%gpt%d", val_ * pow(72.0/interp.unitsPerInch(), double(dim_)),
776           dim_);
777   out << buf;
778 }
779
780 bool QuantityObj::realValue(double &d)
781 {
782   if (dim_ != 0)
783     return 0;
784   d = val_;
785   return 1;
786 }
787
788 bool QuantityObj::inexactRealValue(double &d)
789 {
790   if (dim_ != 0)
791     return 0;
792   d = val_;
793   return 1;
794 }
795
796 LengthSpecObj::LengthSpecObj(const LengthSpec &spec)
797 : lengthSpec_(new LengthSpec(spec))
798 {
799 }
800
801 const LengthSpec *LengthSpecObj::lengthSpec() const
802 {
803   return lengthSpec_.pointer();
804 }
805
806 LengthSpec::LengthSpec()
807 {
808   for (int i = 0; i < nVals; i++)
809     val_[i] = 0.0;
810 }
811
812 LengthSpec::LengthSpec(double d)
813 {
814   val_[0] = d;
815   for (int i = 1; i < nVals; i++)
816     val_[i] = 0.0;
817 }
818  
819 LengthSpec::LengthSpec(Unknown unknown, double d)
820 {
821   int i;
822   for (i = 0; i < unknown; i++)
823     val_[i] = 0.0;
824   val_[unknown] = d;
825   for (i = unknown + 1; i < nVals; i++)
826     val_[i] = 0.0;
827 }
828
829 void LengthSpec::operator+=(const LengthSpec &ls)
830 {
831   for (int i = 0; i < nVals; i++)
832     val_[i] += ls.val_[i];
833 }
834
835 void LengthSpec::operator-=(const LengthSpec &ls)
836 {
837   for (int i = 0; i < nVals; i++)
838     val_[i] -= ls.val_[i];
839 }
840
841 void LengthSpec::operator*=(double d)
842 {
843   for (int i = 0; i < nVals; i++)
844     val_[i] *= d;
845 }
846
847 void LengthSpec::operator/=(double d)
848 {
849   for (int i = 0; i < nVals; i++)
850     val_[i] /= d;
851 }
852
853 bool LengthSpec::convert(FOTBuilder::LengthSpec &result) const
854 {
855   // FIXME do some checking
856   result.length = long(val_[0] < 0.0 ? val_[0] - 0.5 : val_[0] + .5);
857   result.displaySizeFactor = val_[1];
858   return 1;
859 }
860
861 bool LengthSpec::convert(FOTBuilder::TableLengthSpec &result) const
862 {
863   // FIXME do some checking
864   result.length = long(val_[0] < 0.0 ? val_[0] - 0.5 : val_[0] + .5);
865   result.displaySizeFactor = val_[1];
866   result.tableUnitFactor = val_[2];
867   return 1;
868 }
869
870 DisplaySpaceObj::DisplaySpaceObj(const FOTBuilder::DisplaySpace &displaySpace)
871 : displaySpace_(new FOTBuilder::DisplaySpace(displaySpace))
872 {
873 }
874  
875 const FOTBuilder::DisplaySpace &DisplaySpaceObj::displaySpace() const
876 {
877   return *displaySpace_;
878 }
879
880 DisplaySpaceObj *DisplaySpaceObj::asDisplaySpace()
881 {
882   return this;
883 }
884
885 InlineSpaceObj::InlineSpaceObj(const FOTBuilder::InlineSpace &inlineSpace)
886 : inlineSpace_(new FOTBuilder::InlineSpace(inlineSpace))
887 {
888 }
889  
890 const FOTBuilder::InlineSpace &InlineSpaceObj::inlineSpace() const
891 {
892   return *inlineSpace_;
893 }
894
895 InlineSpaceObj *InlineSpaceObj::asInlineSpace()
896 {
897   return this;
898 }
899
900 UnresolvedLengthObj::UnresolvedLengthObj(long val, int valExp, Unit *unit)
901 : val_(val), valExp_(valExp), unit_(unit)
902 {
903 }
904
905 ELObj *UnresolvedLengthObj::resolveQuantities(bool force,
906                                               Interpreter &interp,
907                                               const Location &loc)
908 {
909   unsigned part;
910   Location defLoc;
911   if (!unit_->defined(part, defLoc)) {
912     interp.setNextLocation(loc);
913     interp.message(InterpreterMessages::undefinedQuantity,
914                    StringMessageArg(unit_->name()));
915     return interp.makeError();
916   }
917   return unit_->resolveQuantity(force, interp, val_, valExp_);
918 }
919
920 UnresolvedQuantityObj
921 ::UnresolvedQuantityObj(double val, Unit *unit, int unitExp)
922 : val_(val), unit_(unit), unitExp_(unitExp)
923 {
924 }
925
926 ELObj *UnresolvedQuantityObj::resolveQuantities(bool force,
927                                                 Interpreter &interp,
928                                                 const Location &loc)
929 {
930   unsigned part;
931   Location defLoc;
932   if (!unit_->defined(part, defLoc)) {
933     interp.setNextLocation(loc);
934     interp.message(InterpreterMessages::undefinedQuantity,
935                    StringMessageArg(unit_->name()));
936     return interp.makeError();
937   }
938   return unit_->resolveQuantity(force, interp, val_, unitExp_);
939 }
940
941 GlyphIdObj::GlyphIdObj(const FOTBuilder::GlyphId &glyphId)
942 : glyphId_(glyphId)
943 {
944 }
945
946 const FOTBuilder::GlyphId *GlyphIdObj::glyphId() const
947 {
948   return &glyphId_;
949 }
950
951 bool GlyphIdObj::isEqual(ELObj &obj)
952 {
953   const FOTBuilder::GlyphId *p = obj.glyphId();
954   return (p
955           && p->publicId == glyphId_.publicId
956           && p->suffix == glyphId_.suffix);
957 }
958
959 GlyphSubstTableObj::GlyphSubstTableObj(const ConstPtr<FOTBuilder::GlyphSubstTable> &table)
960 : table_(table)
961 {
962 }
963
964 GlyphSubstTableObj *GlyphSubstTableObj::asGlyphSubstTable()
965 {
966   return this;
967 }
968
969 AddressObj::AddressObj(FOTBuilder::Address::Type type,
970                        const NodePtr &node,
971                        const StringC &str1,
972                        const StringC &str2,
973                        const StringC &str3)
974 {
975   address_ = new FOTBuilder::Address;
976   address_->type = type;
977   address_->node = node;
978   address_->params[0] = str1;
979   address_->params[1] = str2;
980   address_->params[2] = str3;
981 }
982
983 AddressObj *AddressObj::asAddress()
984 {
985   return this;
986 }
987
988 NodeListObj *NodeListObj::asNodeList()
989 {
990   return this;
991 }
992
993 NodeListObj *NodeListObj::nodeListNoOrder(Collector &)
994 {
995   return this;
996 }
997
998 NodeListObj *NodeListObj::nodeListChunkRest(EvalContext &context, Interpreter &interp, bool &chunk)
999 {
1000   chunk = 0;
1001   return nodeListRest(context, interp);
1002 }
1003
1004 bool NodeListObj::optSingletonNodeList(EvalContext &context, Interpreter &interp, NodePtr &node)
1005 {
1006   NodeListObj *rest = nodeListRest(context, interp);
1007   ELObjDynamicRoot protect(interp, rest);
1008   if (rest->nodeListFirst(context, interp))
1009     return 0;
1010   node = nodeListFirst(context, interp);
1011   return 1;
1012 }
1013
1014 NodePtr NodeListObj::nodeListRef(long n, EvalContext &context, Interpreter &interp)
1015 {
1016   if (n < 0)
1017     return NodePtr();
1018   NodeListObj *nl = this;
1019   ELObjDynamicRoot protect(interp, nl);
1020   while (n > 0) {
1021     NodePtr nd(nl->nodeListFirst(context, interp));
1022     if (!nd)
1023       return NodePtr();
1024     GroveString str;
1025     if (nd->charChunk(interp, str) == accessOK && str.size() <= n) {
1026       bool chunk;
1027       nl = nl->nodeListChunkRest(context, interp, chunk);
1028       if (chunk)
1029         n -= str.size();
1030       else
1031         n--;
1032     }
1033     else {
1034       nl = nl->nodeListRest(context, interp);
1035       n--;
1036     }
1037     protect = nl;
1038   }
1039   return nl->nodeListFirst(context, interp);
1040 }
1041
1042 NodeListObj *NodeListObj::nodeListReverse(EvalContext &, Interpreter &interp)
1043 {
1044   return new (interp) ReverseNodeListObj(this);
1045 }
1046
1047 long NodeListObj::nodeListLength(EvalContext &context, Interpreter &interp)
1048 {
1049   NodeListObj *nl = this;
1050   long n = 0;
1051   ELObjDynamicRoot protect(interp, nl);
1052   for (;;) {
1053     NodePtr nd(nl->nodeListFirst(context, interp));
1054     if (!nd)
1055       break;
1056     bool chunk;
1057     nl = nl->nodeListChunkRest(context, interp, chunk);
1058     protect = nl;
1059     GroveString str;
1060     if (chunk && nd->charChunk(interp, str) == accessOK)
1061       n += str.size();
1062     else
1063       n += 1;
1064   }
1065   return n;
1066 }
1067
1068 bool NodeListObj::suppressError()
1069 {
1070   return 0;
1071 }
1072
1073 NamedNodeListObj *NamedNodeListObj::asNamedNodeList()
1074 {
1075   return this;
1076 }
1077
1078 NodePtrNodeListObj::NodePtrNodeListObj()
1079 {
1080 }
1081
1082 NodePtrNodeListObj::NodePtrNodeListObj(const NodePtr &node)
1083 : node_(node)
1084 {
1085 }
1086
1087 bool NodePtrNodeListObj::optSingletonNodeList(EvalContext &, Interpreter &, NodePtr &node)
1088 {
1089   node = node_;
1090   return 1;
1091 }
1092
1093 NodePtr NodePtrNodeListObj::nodeListFirst(EvalContext &, Interpreter &)
1094 {
1095   return node_;
1096 }
1097
1098 NodeListObj *NodePtrNodeListObj::nodeListRest(EvalContext &context, Interpreter &interp)
1099 {
1100   if (node_)
1101     return new (interp) NodePtrNodeListObj;
1102   else
1103     return this;
1104 }
1105
1106 NodeListPtrNodeListObj::NodeListPtrNodeListObj(const NodeListPtr &nodeList)
1107 : nodeList_(nodeList)
1108 {
1109 }
1110
1111 NodePtr NodeListPtrNodeListObj::nodeListFirst(EvalContext &, Interpreter &)
1112 {
1113   NodePtr nd;
1114   if (nodeList_->first(nd) == accessOK)
1115     return nd;
1116   else
1117     return NodePtr();
1118 }
1119
1120 NodeListObj *NodeListPtrNodeListObj::nodeListRest(EvalContext &context, Interpreter &interp)
1121 {
1122   NodeListPtr nl;
1123   if (nodeList_->rest(nl) == accessOK)
1124     return new (interp) NodeListPtrNodeListObj(nl);
1125   else
1126     return interp.makeEmptyNodeList();
1127 }
1128
1129 NodeListObj *NodeListPtrNodeListObj::nodeListChunkRest(EvalContext &context, Interpreter &interp, bool &chunk)
1130 {
1131   NodeListPtr nl;
1132   if (nodeList_->chunkRest(nl) == accessOK) {
1133     chunk = 1;
1134     return new (interp) NodeListPtrNodeListObj(nl);
1135   }
1136   else {
1137     chunk = 0;
1138     return interp.makeEmptyNodeList();
1139   }
1140 }
1141
1142 NodePtr NodeListPtrNodeListObj::nodeListRef(long i, EvalContext &, Interpreter &interp)
1143 {
1144   NodePtr nd;
1145   if (i < 0 || nodeList_->ref(i, nd) != accessOK)
1146     return NodePtr();
1147   return nd;
1148 }
1149
1150 NamedNodeListPtrNodeListObj
1151 ::NamedNodeListPtrNodeListObj(const NamedNodeListPtr &nnl)
1152 : namedNodeList_(nnl)
1153 {
1154 }
1155
1156 NodePtr NamedNodeListPtrNodeListObj::namedNode(const Char *s, size_t n)
1157 {
1158   NodePtr node;
1159   if (namedNodeList_->namedNode(GroveString(s, n), node) != accessOK)
1160     node.clear();
1161   return node;
1162 }
1163
1164 bool NamedNodeListPtrNodeListObj::nodeName(const NodePtr &nd, GroveString &str)
1165 {
1166   return namedNodeList_->nodeName(nd, str) == accessOK;
1167 }
1168
1169 size_t NamedNodeListPtrNodeListObj::normalize(Char *s, size_t n)
1170 {
1171   return namedNodeList_->normalize(s, n);
1172 }
1173
1174 NodePtr NamedNodeListPtrNodeListObj::nodeListFirst(EvalContext &, Interpreter &)
1175 {
1176   if (!nodeList_)
1177     nodeList_ = namedNodeList_->nodeList();
1178   NodePtr nd;
1179   if (nodeList_->first(nd) == accessOK)
1180     return nd;
1181   else
1182     return NodePtr();
1183 }
1184  
1185 NodeListObj *NamedNodeListPtrNodeListObj::nodeListRest(EvalContext &context, Interpreter &interp)
1186 {
1187   if (!nodeList_)
1188     nodeList_ = namedNodeList_->nodeList();
1189   NodeListPtr nl;
1190   if (nodeList_->rest(nl) == accessOK)
1191     return new (interp) NodeListPtrNodeListObj(nl);
1192   else
1193     return new (interp) NodePtrNodeListObj;
1194 }
1195
1196 NodeListObj *NamedNodeListPtrNodeListObj::nodeListNoOrder(Collector &c)
1197 {
1198   return new (c) NodeListPtrNodeListObj(namedNodeList_->nodeListNoOrder());
1199 }
1200
1201 PairNodeListObj::PairNodeListObj(NodeListObj *head, NodeListObj *tail)
1202 : head_(head), tail_(tail)
1203 {
1204   hasSubObjects_ = 1;
1205 }
1206
1207 NodePtr PairNodeListObj::nodeListFirst(EvalContext &context, Interpreter &interp)
1208 {
1209   if (head_) {
1210     NodePtr nd(head_->nodeListFirst(context, interp));
1211     if (nd)
1212       return nd;
1213     head_ = 0;
1214   }
1215   return tail_->nodeListFirst(context, interp);
1216 }
1217
1218 NodeListObj *PairNodeListObj::nodeListRest(EvalContext &context, Interpreter &interp)
1219 {
1220   if (!head_ || !head_->nodeListFirst(context, interp))
1221     return tail_->nodeListRest(context, interp);
1222   NodeListObj *tem = head_->nodeListRest(context, interp);
1223   ELObjDynamicRoot protect(interp, tem);
1224   return new (interp) PairNodeListObj(tem, tail_);
1225 }
1226
1227 NodeListObj *PairNodeListObj::nodeListChunkRest(EvalContext &context, Interpreter &interp, bool &chunk)
1228 {
1229   if (!head_ || !head_->nodeListFirst(context, interp))
1230     return tail_->nodeListChunkRest(context, interp, chunk);
1231   NodeListObj *tem = head_->nodeListChunkRest(context, interp, chunk);
1232   ELObjDynamicRoot protect(interp, tem);
1233   return new (interp) PairNodeListObj(tem, tail_);
1234 }
1235
1236 void PairNodeListObj::traceSubObjects(Collector &c) const
1237 {
1238   c.trace(head_);
1239   c.trace(tail_);
1240 }
1241
1242 ReverseNodeListObj::ReverseNodeListObj(NodeListObj *nl)
1243 : nl_(nl), reversed_(0)
1244 {
1245   hasSubObjects_ = 1;
1246 }
1247
1248 NodePtr ReverseNodeListObj::nodeListFirst(EvalContext &context, Interpreter &interp)
1249 {
1250   return reversed(context, interp)->nodeListFirst(context, interp);
1251 }
1252
1253 NodeListObj *ReverseNodeListObj::nodeListRest(EvalContext &context, Interpreter &interp)
1254 {
1255   return reversed(context, interp)->nodeListRest(context, interp);
1256 }
1257
1258 NodePtr ReverseNodeListObj::nodeListRef(long n, EvalContext &context, Interpreter &interp)
1259 {
1260   if (reversed_)
1261     return reversed_->nodeListRef(n, context, interp);
1262   if (n < 0)
1263     return NodePtr();
1264   size_t len = nl_->nodeListLength(context, interp);
1265   if (n >= len)
1266     return 0;
1267   return nl_->nodeListRef(len - n - 1, context, interp);
1268 }
1269
1270 NodeListObj *ReverseNodeListObj::reversed(EvalContext &context, Interpreter &interp)
1271 {
1272   if (!reversed_) {
1273     NodePtr nd(nl_->nodeListFirst(context, interp));
1274     if (nd) {
1275       reversed_ = new (interp) NodePtrNodeListObj(nd);
1276       NodeListObj *tem = nl_;
1277       ELObjDynamicRoot protect(interp, tem);
1278       ELObjDynamicRoot protect2(interp, reversed_);
1279       for (;;) {
1280         tem = tem->nodeListRest(context, interp);
1281         protect = tem;
1282         nd = tem->nodeListFirst(context, interp);
1283         if (!nd)
1284           break;
1285         NodeListObj *single = new (interp) NodePtrNodeListObj(nd);
1286         protect2 = single;
1287         reversed_ = new (interp) PairNodeListObj(single, reversed_);
1288       }
1289     }
1290     else
1291       reversed_ = nl_;
1292   }
1293   return reversed_;
1294 }
1295
1296 NodeListObj *ReverseNodeListObj::nodeListReverse(EvalContext &, Interpreter &)
1297 {
1298   return nl_;
1299 }
1300
1301 long ReverseNodeListObj::nodeListLength(EvalContext &context, Interpreter &interp)
1302 {
1303   return nl_->nodeListLength(context, interp);
1304 }
1305
1306 void ReverseNodeListObj::traceSubObjects(Collector &c) const
1307 {
1308   c.trace(nl_);
1309   c.trace(reversed_);
1310 }
1311
1312 #ifdef DSSSL_NAMESPACE
1313 }
1314 #endif