Initial commit
[profile/ivi/openjade.git] / style / Interpreter.cxx
1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
3
4 #include "stylelib.h"
5 #include "Interpreter.h"
6 #include "Insn.h"
7 #include "InterpreterMessages.h"
8 #include "LocNode.h"
9 #include "Pattern.h"
10 #include "MacroFlowObj.h"
11 #include "ELObjMessageArg.h"
12 #include "VM.h"
13 #include "Owner.h" 
14 #include "SchemeParser.h"
15 #include "macros.h"
16 #include "InternalInputSource.h"
17 #include <stdlib.h>
18 #include "LangObj.h"
19
20 #ifdef DSSSL_NAMESPACE
21 namespace DSSSL_NAMESPACE {
22 #endif
23
24 const Char defaultChar = 0xfffd;
25
26 static
27 size_t maxObjSize()
28 {
29   static size_t sz[] = {
30     sizeof(UnresolvedQuantityObj),
31     sizeof(VarStyleObj),
32     sizeof(OverriddenStyleObj),
33     sizeof(MergeStyleObj),
34     sizeof(DeviceRGBColorObj),
35     sizeof(ColorSpaceObj),
36     sizeof(PairObj),
37     sizeof(QuantityObj),
38     sizeof(GlyphIdObj),
39     sizeof(NamedNodeListPtrNodeListObj),
40     sizeof(ProcessNodeSosofoObj),
41     sizeof(AppendSosofoObj),
42     sizeof(SetNonInheritedCsSosofoObj),
43     sizeof(LabelSosofoObj),
44     sizeof(MacroFlowObj),
45     sizeof(FlowObj) + sizeof(StringC), // for FormattingInstructionFlowObj
46     sizeof(LangObj),
47 #ifdef SP_HAVE_LOCALE
48 #ifdef SP_HAVE_WCHAR
49     sizeof(RefLangObj),
50 #endif
51 #endif
52   };
53   size_t n = sz[0];
54   for (size_t i = 1; i < SIZEOF(sz); i++)
55     if (sz[i] > n)
56       n = sz[i];
57   return n;
58 }
59
60 Interpreter::Interpreter(GroveManager *groveManager,
61                          Messenger *messenger,
62                          int unitsPerInch,
63                          bool debugMode,
64                          bool dsssl2,
65                          bool strictMode,
66                          const FOTBuilder::Extension *extensionTable)
67 : groveManager_(groveManager),
68   messenger_(messenger),
69   extensionTable_(extensionTable),
70   Collector(maxObjSize()),
71   partIndex_(0),  // 0 is for command-line definitions
72   dPartIndex_(1),
73   lexCategory_(lexOther),
74   unitsPerInch_(unitsPerInch),
75   nInheritedC_(0),
76   initialProcessingMode_(StringC()),
77   currentPartFirstInitialValue_(0),
78   initialStyle_(0),
79   nextGlyphSubstTableUniqueId_(0),
80   debugMode_(debugMode),
81   dsssl2_(dsssl2),
82   strictMode_(strictMode)
83 {
84   makePermanent(theNilObj_ = new (*this) NilObj);
85   makePermanent(theFalseObj_ = new (*this) FalseObj);
86   makePermanent(theTrueObj_ = new (*this) TrueObj);
87   makePermanent(theErrorObj_ = new (*this) ErrorObj);
88   makePermanent(theUnspecifiedObj_ = new (*this) UnspecifiedObj);
89   makePermanent(addressNoneObj_
90                 = new (*this) AddressObj(FOTBuilder::Address::none));
91   makePermanent(emptyNodeListObj_
92                 = new (*this) NodePtrNodeListObj);
93   defaultLanguage_ = theFalseObj_;
94   installSyntacticKeys();
95   installCValueSymbols();
96   installPortNames();
97   installPrimitives();
98   installUnits();
99   if (!strictMode_) {
100     installCharNames();
101     installSdata();
102   }
103   installFlowObjs();
104   installInheritedCs();
105   installNodeProperties();
106
107   static const char *lexCategories[] = {
108     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
109     "!$%&*/<=>?~_^:",
110     "",
111     "0123456789",
112     "-+.",
113     "",
114     "();\"",
115     " \t\r\n\f",
116     "",
117   };
118   lexCategory_.setEe(lexDelimiter);
119   for (size_t i = 0; i < SIZEOF(lexCategories); i++)
120     for (const char *s = lexCategories[i]; *s; s++)
121       lexCategory_.setChar(*s, i);
122
123   // #',@[\\]`{|} are ASCII chars not mentioned above,
124   // but I guess we don't want to allow any of these
125   // in names (as most of them have special meaning in
126   // scheme/dsssl).
127   if (!strictMode_)
128     for (Char i = 127; i < charMax; i++)
129       lexCategory_.setChar(i, lexAddNameStart);
130
131   initialProcessingMode_.setDefined();
132   // can't be done before initializing lexCategory_
133   installBuiltins();
134   installCharProperties();
135 }
136
137 void Interpreter::compile()
138 {
139   // FIXME compile all definitions
140   compileInitialValues();
141   initialProcessingMode_.compile(*this);
142   NamedTableIter<ProcessingMode> iter(processingModeTable_);
143   for (;;) {
144     ProcessingMode *mode = iter.next();
145     if (!mode)
146       break;
147     mode->compile(*this);
148   }
149   compileCharProperties();
150   compileDefaultLanguage();
151 }
152
153 void Interpreter::compileInitialValues()
154 {
155   Vector<ConstPtr<InheritedC> > ics;
156   for (size_t i = 0; i < initialValueNames_.size(); i++) {
157     const Identifier *ident = initialValueNames_[i];
158     Owner<Expression> &expr = initialValueValues_[i];
159     ConstPtr<InheritedC> ic(ident->inheritedC());
160     expr->optimize(*this, Environment(), expr);
161     ELObj *val = expr->constantValue();
162     if (val) {
163       ConstPtr<InheritedC> tem(ic->make(val, expr->location(), *this));
164       if (!tem.isNull())
165         ics.push_back(tem);
166     }
167     else
168       ics.push_back(new VarInheritedC(ic,
169                                       expr->compile(*this, Environment(), 0, InsnPtr()),
170                                       expr->location()));
171   }
172   if (ics.size()) {
173     Vector<ConstPtr<InheritedC> > forceIcs;
174     initialStyle_ = new (*this) VarStyleObj(new StyleSpec(forceIcs, ics), 0, 0, NodePtr());
175     makePermanent(initialStyle_);
176   }
177 }
178
179 void Interpreter::installInitialValue(Identifier *ident, Owner<Expression> &expr)
180 {
181   for (size_t i = 0; i < initialValueNames_.size(); i++) {
182     if (ident == initialValueNames_[i]) {
183       if (i >= currentPartFirstInitialValue_) {
184         setNextLocation(expr->location());
185         message(InterpreterMessages::duplicateInitialValue,
186                 StringMessageArg(ident->name()),
187                 initialValueValues_[i]->location());
188       }
189       return;
190     }
191   }
192   initialValueValues_.resize(initialValueValues_.size() + 1);
193   expr.swap(initialValueValues_.back());
194   initialValueNames_.push_back(ident);
195 }
196
197 void Interpreter::installUnits()
198 {
199   static struct {
200     const char *name;
201     int numer;
202     int denom;
203     bool dsssl2;
204   } units[] = {
205     { "m", 5000, 127 },
206     { "cm", 50, 127 },
207     { "mm", 5, 127 },
208     { "in", 1, 1 },
209     { "pt", 1, 72 },
210     { "pica", 1, 6 },
211     { "pc", 1, 6 } // a DSSSL2 addition
212   };
213   size_t nUnits = dsssl2() ? SIZEOF(units) : SIZEOF(units) - 1;
214   for (size_t i = 0; i < nUnits; i++) {
215     Unit *unit = lookupUnit(makeStringC(units[i].name));
216     long n = unitsPerInch_ * units[i].numer;
217     if (n % units[i].denom == 0)
218       unit->setValue(long(n / units[i].denom));
219     else
220       unit->setValue(double(n)/units[i].denom);
221   }
222 }
223
224 void Interpreter::installSyntacticKeys()
225 {
226   static struct {
227     const char *name;
228     Identifier::SyntacticKey key;
229   } keys[] = {
230     { "quote", Identifier::keyQuote },
231     { "lambda", Identifier::keyLambda },
232     { "if", Identifier::keyIf },
233     { "cond", Identifier::keyCond },
234     { "and", Identifier::keyAnd },
235     { "or", Identifier::keyOr },
236     { "case", Identifier::keyCase },
237     { "let", Identifier::keyLet },
238     { "let*", Identifier::keyLetStar },
239     { "letrec", Identifier::keyLetrec },
240     { "quasiquote", Identifier::keyQuasiquote },
241     { "unquote", Identifier::keyUnquote },
242     { "unquote-splicing", Identifier::keyUnquoteSplicing },
243     { "define", Identifier::keyDefine },
244     { "else", Identifier::keyElse },
245     { "=>", Identifier::keyArrow },
246     { "there-exists?", Identifier::keyThereExists },
247     { "for-all?", Identifier::keyForAll },
248     { "select-each", Identifier::keySelectEach },
249     { "union-for-each", Identifier::keyUnionForEach },
250     { "make", Identifier::keyMake },
251     { "style", Identifier::keyStyle },
252     { "with-mode", Identifier::keyWithMode },
253     { "define-unit", Identifier::keyDefineUnit },
254     { "query", Identifier::keyQuery },
255     { "element", Identifier::keyElement },
256     { "default", Identifier::keyDefault },
257     { "root", Identifier::keyRoot },
258     { "id", Identifier::keyId },
259     { "mode", Identifier::keyMode },
260     { "declare-initial-value", Identifier::keyDeclareInitialValue },
261     { "declare-characteristic", Identifier::keyDeclareCharacteristic },
262     { "declare-flow-object-class", Identifier::keyDeclareFlowObjectClass },
263     { "declare-char-characteristic+property", Identifier::keyDeclareCharCharacteristicAndProperty },
264     { "declare-reference-value-type", Identifier::keyDeclareReferenceValueType },
265     { "declare-default-language", Identifier::keyDeclareDefaultLanguage },
266     { "declare-char-property", Identifier::keyDeclareCharProperty },
267     { "define-page-model", Identifier::keyDefinePageModel },
268     { "define-column-set-model", Identifier::keyDefineColumnSetModel },
269     { "define-language", Identifier::keyDefineLanguage },
270     { "add-char-properties", Identifier::keyAddCharProperties },
271     { "use", Identifier::keyUse },
272     { "label", Identifier::keyLabel },
273     { "content-map", Identifier::keyContentMap },
274     { "keep-with-previous?", Identifier::keyIsKeepWithPrevious },
275     { "keep-with-next?", Identifier::keyIsKeepWithNext },
276     { "space-before", Identifier::keySpaceBefore },
277     { "space-after", Identifier::keySpaceAfter },
278     { "left-header", Identifier::keyLeftHeader },
279     { "center-header", Identifier::keyCenterHeader },
280     { "right-header", Identifier::keyRightHeader },
281     { "left-footer", Identifier::keyLeftFooter },
282     { "center-footer", Identifier::keyCenterFooter },
283     { "right-footer", Identifier::keyRightFooter },
284     { "destination", Identifier::keyDestination },
285     { "type", Identifier::keyType },
286     { "coalesce-id", Identifier::keyCoalesceId },
287     { "display?", Identifier::keyIsDisplay },
288     { "scale", Identifier::keyScale },
289     { "max-width", Identifier::keyMaxWidth },
290     { "max-height", Identifier::keyMaxHeight },
291     { "entity-system-id", Identifier::keyEntitySystemId },
292     { "notation-system-id", Identifier::keyNotationSystemId },
293     { "position-point-x", Identifier::keyPositionPointX },
294     { "position-point-y", Identifier::keyPositionPointY },
295     { "escapement-direction", Identifier::keyEscapementDirection },
296     { "break-before-priority", Identifier::keyBreakBeforePriority },
297     { "break-after-priority", Identifier::keyBreakAfterPriority },
298     { "orientation", Identifier::keyOrientation },
299     { "length", Identifier::keyLength },
300     { "char", Identifier::keyChar },
301     { "glyph-id", Identifier::keyGlyphId },
302     { "space?", Identifier::keyIsSpace },
303     { "record-end?", Identifier::keyIsRecordEnd },
304     { "input-tab?", Identifier::keyIsInputTab },
305     { "input-whitespace?", Identifier::keyIsInputWhitespace },
306     { "punct?", Identifier::keyIsPunct },
307     { "drop-after-line-break?", Identifier::keyIsDropAfterLineBreak },
308     { "drop-unless-before-line-break?", Identifier::keyIsDropUnlessBeforeLineBreak },
309     { "math-class", Identifier::keyMathClass },
310     { "math-font-posture", Identifier::keyMathFontPosture },
311     { "script", Identifier::keyScript },
312     { "stretch-factor", Identifier::keyStretchFactor },
313     { "keep", Identifier::keyKeep },
314     { "break-before", Identifier::keyBreakBefore },
315     { "break-after", Identifier::keyBreakAfter },
316     { "may-violate-keep-before?", Identifier::keyIsMayViolateKeepBefore },
317     { "may-violate-keep-after?", Identifier::keyIsMayViolateKeepAfter },
318     { "before-row-border", Identifier::keyBeforeRowBorder },
319     { "after-row-border", Identifier::keyAfterRowBorder },
320     { "before-column-border", Identifier::keyBeforeColumnBorder },
321     { "after-column-border", Identifier::keyAfterColumnBorder },
322     { "column-number", Identifier::keyColumnNumber },
323     { "row-number", Identifier::keyRowNumber },
324     { "n-columns-spanned", Identifier::keyNColumnsSpanned },
325     { "n-rows-spanned", Identifier::keyNRowsSpanned },
326     { "width", Identifier::keyWidth },
327     { "starts-row?", Identifier::keyIsStartsRow },
328     { "ends-row?", Identifier::keyIsEndsRow },
329     { "table-width", Identifier::keyTableWidth },
330     { "multi-modes", Identifier::keyMultiModes },
331     { "data", Identifier::keyData },
332     { "min", Identifier::keyMin },
333     { "max", Identifier::keyMax },
334     { "conditional?", Identifier::keyIsConditional },
335     { "priority", Identifier::keyPriority },
336     { "grid-n-rows", Identifier::keyGridNRows },
337     { "grid-n-columns", Identifier::keyGridNColumns },
338     { "radical", Identifier::keyRadical },
339     { "null", Identifier::keyNull },
340     { "rcs?", Identifier::keyIsRcs },
341     { "parent", Identifier::keyParent },
342     { "active", Identifier::keyActive },
343     { "attributes", Identifier::keyAttributes },
344     { "children", Identifier::keyChildren },
345     { "repeat", Identifier::keyRepeat },
346     { "position", Identifier::keyPosition },
347     { "only", Identifier::keyOnly },
348     { "class", Identifier::keyClass },
349     { "importance", Identifier::keyImportance },
350     { "position-preference", Identifier::keyPositionPreference },
351     { "collate", Identifier::keyCollate },
352     { "toupper", Identifier::keyToupper },
353     { "tolower", Identifier::keyTolower },
354     { "symbol", Identifier::keySymbol },
355     { "order", Identifier::keyOrder },
356     { "forward", Identifier::keyForward },
357     { "backward", Identifier::keyBackward },
358     { "white-point", Identifier::keyWhitePoint },
359     { "black-point", Identifier::keyBlackPoint },
360     { "range", Identifier::keyRange },
361     { "range-abc", Identifier::keyRangeAbc },
362     { "range-lmn", Identifier::keyRangeLmn },
363     { "range-a", Identifier::keyRangeA },
364     { "decode-abc", Identifier::keyDecodeAbc },
365     { "decode-lmn", Identifier::keyDecodeLmn },
366     { "decode-a", Identifier::keyDecodeA },
367     { "matrix-abc", Identifier::keyMatrixAbc },
368     { "matrix-lmn", Identifier::keyMatrixLmn },
369     { "matrix-a", Identifier::keyMatrixA },
370     { "architecture", Identifier::keyArchitecture },
371   }, keys2[] = {
372     { "declare-class-attribute", Identifier::keyDeclareClassAttribute },
373     { "declare-id-attribute", Identifier::keyDeclareIdAttribute },
374     { "declare-flow-object-macro", Identifier::keyDeclareFlowObjectMacro },
375     { "or-element", Identifier::keyOrElement },
376     { "set!", Identifier::keySet },
377     { "begin", Identifier::keyBegin },
378   };
379   for (size_t i = 0; i < SIZEOF(keys); i++) {
380     StringC tem(makeStringC(keys[i].name));
381     lookup(tem)->setSyntacticKey(keys[i].key);
382     if (dsssl2() && tem[tem.size() - 1] == '?') {
383       tem.resize(tem.size() - 1);
384       lookup(tem)->setSyntacticKey(keys[i].key);
385     }
386   }
387   if (dsssl2()) {
388     for (size_t i = 0; i < SIZEOF(keys2); i++)
389       lookup(makeStringC(keys2[i].name))->setSyntacticKey(keys2[i].key);
390   }
391 }
392
393 void Interpreter::installCValueSymbols()
394 {
395   cValueSymbols_[0] = makeFalse();
396   cValueSymbols_[1] = makeTrue();
397   for (size_t i = 2; i < FOTBuilder::nSymbols; i++) {
398     SymbolObj *sym = makeSymbol(makeStringC(FOTBuilder::symbolName(FOTBuilder::Symbol(i))));
399     sym->setCValue(FOTBuilder::Symbol(i));
400     cValueSymbols_[i] = sym;
401   }
402 }
403
404 void Interpreter::installPortNames()
405 {
406   // These must match the order in SymbolObj.
407   static const char *names[] = {
408     "numerator",
409     "denominator",
410     "pre-sup",
411     "pre-sub",
412     "post-sup",
413     "post-sub",
414     "mid-sup",
415     "mid-sub",
416     "over-mark",
417     "under-mark",
418     "open",
419     "close",
420     "degree",
421     "operator",
422     "lower-limit",
423     "upper-limit",
424     "header",
425     "footer"
426   };
427   ASSERT(SIZEOF(names) == nPortNames);
428   for (size_t i = 0; i < SIZEOF(names); i++)
429     portNames_[i] = makeSymbol(makeStringC(names[i]));
430 }
431
432 void Interpreter::installCharNames()
433 {
434   static struct {
435     Char c;
436     const char *name;
437   } chars[] = {
438 #include "charNames.h"
439   };
440   for (size_t i = 0; i < SIZEOF(chars); i++) {
441     CharPart ch;
442     ch.c = chars[i].c;
443     ch.defPart = unsigned(-1);
444     namedCharTable_.insert(makeStringC(chars[i].name), ch, 1);
445   }
446 }
447
448 void Interpreter::installSdata()
449 {
450   // This comes from uni2sgml.txt on ftp://unicode.org.
451   // It is marked there as obsolete, so it probably ought to be checked.
452   // The definitions of apos and quot have been fixed for consistency with XML.
453   static struct {
454     Char c;
455     const char *name;
456   } entities[] = {
457 #include "sdata.h"
458   };
459   for (size_t i = 0; i < SIZEOF(entities); i++) { 
460     CharPart ch;
461     ch.c = entities[i].c;
462     ch.defPart = unsigned(-1);
463     sdataEntityNameTable_.insert(makeStringC(entities[i].name), ch, 1);
464   }
465 }
466
467 void Interpreter::installNodeProperties()
468 {
469   for (int i = 0; i < ComponentName::nIds; i++) {
470     ComponentName::Id id = ComponentName::Id(i);
471     nodePropertyTable_.insert(makeStringC(ComponentName::rcsName(id)), i);
472     nodePropertyTable_.insert(makeStringC(ComponentName::sdqlName(id)), i);
473   }
474 }
475
476 void Interpreter::setCharRepertoire(const StringC &pubid)
477 {
478   if (pubid == "UNREGISTERED::OpenJade//Character Repertoire::OpenJade") {
479     if (strictMode_) {
480       installCharNames();
481       installSdata();
482       // This assumes that we process char-repertoire
483       // declaration before any declarations which change
484       // lexical categories.
485       for (Char i = 127; i < charMax; i++)
486         lexCategory_.setChar(i, lexAddNameStart);
487       strictMode_ = 0;
488     }
489    } else 
490      message(InterpreterMessages::unsupportedCharRepertoire,
491                 StringMessageArg(pubid));
492 }
493  
494 void Interpreter::addStandardChar(const StringC &name, const StringC &num)
495 {
496   int n;
497   size_t i = 0;
498   if (!scanSignDigits(num, i, n)) {
499     message(InterpreterMessages::invalidCharNumber, StringMessageArg(num));
500     return;
501   }
502   
503   const CharPart *def = namedCharTable_.lookup(name);
504   CharPart ch;
505   ch.c = n;
506   ch.defPart = dPartIndex_;
507   if (def) {
508     if (dPartIndex_ < def->defPart)
509       namedCharTable_.insert(name, ch, 1);
510     else if (def->defPart == dPartIndex_ && def->c != ch.c) 
511       message(InterpreterMessages::duplicateCharName, 
512               StringMessageArg(name));
513   }
514   else 
515     namedCharTable_.insert(name, ch, 1);
516 }
517
518 void Interpreter::addNameChar(const StringC &name)
519 {
520   const CharPart *cp = namedCharTable_.lookup(name);
521   if (!cp) 
522     message(InterpreterMessages::badCharName, 
523             StringMessageArg(name));
524   else if (lexCategory_[cp->c] != lexOther)
525     // FIXME give a more specific error
526     message(InterpreterMessages::badDeclaration);
527   else
528     lexCategory_.setChar(cp->c, lexAddNameStart);
529 }
530
531 void Interpreter::addSeparatorChar(const StringC &name)
532 {
533   const CharPart *cp = namedCharTable_.lookup(name);
534   if (!cp)
535     message(InterpreterMessages::badCharName, 
536             StringMessageArg(name));
537   else if (lexCategory_[cp->c] != lexOther)
538     // FIXME give a more specific error
539     message(InterpreterMessages::badDeclaration);
540   else
541     lexCategory_.setChar(cp->c, lexAddWhiteSpace);
542 }
543
544 void Interpreter::addSdataEntity(const StringC &ename, const StringC &etext, const StringC &name)
545 {
546   const CharPart *cp = namedCharTable_.lookup(name);
547   if (!cp) { 
548     message(InterpreterMessages::badCharName, 
549             StringMessageArg(name));
550     return; 
551   }
552
553   CharPart ch;
554   ch.c = cp->c;
555   ch.defPart = dPartIndex_;
556
557   if (ename.size() > 0) {
558     const CharPart *def = sdataEntityNameTable_.lookup(ename);
559     if (def) {
560       if (dPartIndex_ < def->defPart)
561         sdataEntityNameTable_.insert(ename, ch);
562       else if (def->defPart == dPartIndex_ && def->c != cp->c) 
563         message(InterpreterMessages::duplicateSdataEntityName, 
564                 StringMessageArg(ename));
565     }
566     else
567       sdataEntityNameTable_.insert(ename, ch);
568   }
569
570   if (etext.size() > 0) {
571     const CharPart *def = sdataEntityTextTable_.lookup(etext);
572     if (def) {
573       if (dPartIndex_ < def->defPart)
574         sdataEntityTextTable_.insert(etext, ch);
575       else if (def->defPart == dPartIndex_ && def->c != cp->c) 
576         message(InterpreterMessages::duplicateSdataEntityText, 
577                 StringMessageArg(etext));
578     }
579     else
580       sdataEntityTextTable_.insert(etext, ch);
581   }
582 }
583
584 bool Interpreter::sdataMap(GroveString name, GroveString text, GroveChar &c) const
585 {
586   StringC tem(name.data(), name.size());
587   StringC tem2(text.data(), text.size());
588
589   const CharPart *cp = sdataEntityNameTable_.lookup(tem);
590   if (cp) {
591     c = cp->c;
592     return 1;
593   }
594   
595   cp = sdataEntityTextTable_.lookup(tem2);
596   if (cp) {
597     c = cp->c;
598     return 1;
599   }
600   
601   if (convertUnicodeCharName(tem, c))
602     return 1;
603   // I think this is the best thing to do.
604   // At least it makes preserve-sdata work with unknown SDATA entities.
605   c = defaultChar;
606   return 1;
607 }
608
609 ELObj *Interpreter::convertGlyphId(const Char *str, size_t len, const Location &loc)
610 {
611   unsigned long n = 0;
612   const char *publicId = 0;
613   for (size_t i = len; i > 1; --i) {
614     if (str[i - 1] == ':' && str[i - 2] == ':' && i < len && str[i] != '0') {
615       for (size_t j = i; j < len; j++)
616         n = n*10 + (str[j] - '0');
617       publicId = storePublicId(str, i - 2, loc);
618       break;
619     }
620     if (str[i - 1] < '0' || str[i - 1] > '9')
621       break;
622   }
623   if (!publicId)
624     publicId = storePublicId(str, len, loc);
625   return new (*this) GlyphIdObj(FOTBuilder::GlyphId(publicId, n));
626 }
627
628 bool Interpreter::convertCharName(const StringC &str, Char &c) const
629 {
630   const CharPart *cp = namedCharTable_.lookup(str);
631   if (cp) {
632     c = cp->c;
633     return 1;
634   }
635   return convertUnicodeCharName(str, c);
636 }
637
638 bool Interpreter::convertUnicodeCharName(const StringC &str, Char &c)
639 {
640   if (str.size() != 6 || str[0] != 'U' || str[1] != '-')
641     return 0;
642   Char value = 0;
643   for (int i = 2; i < 6; i++) {
644     value <<= 4;
645     switch (str[i]) {
646     case '0':
647     case '1':
648     case '2':
649     case '3':
650     case '4':
651     case '5':
652     case '6':
653     case '7':
654     case '8':
655     case '9':
656       value |= str[i] - '0';
657       break;
658     case 'A':
659     case 'B':
660     case 'C':
661     case 'D':
662     case 'E':
663     case 'F':
664       value |= 10 + (str[i] - 'A');
665       break;
666     default:
667       return 0;
668     }
669   }
670   c = value;
671   return 1;
672 }
673
674 SymbolObj *Interpreter::makeSymbol(const StringC &str)
675 {
676   SymbolObj *sym = symbolTable_.lookup(str);
677   if (!sym) {
678     StringObj *strObj = new (*this) StringObj(str);
679     makePermanent(strObj);
680     sym = new (*this) SymbolObj(strObj);
681     makePermanent(sym);
682     symbolTable_.insert(sym);
683   }
684   return sym;
685 }
686
687 Identifier *Interpreter::lookup(const StringC &str)
688 {
689   Identifier *ident = identTable_.lookup(str);
690   if (!ident) {
691     ident = new Identifier(str);
692     identTable_.insert(ident);
693   }
694   return ident;
695 }
696
697 bool Interpreter::lookupNodeProperty(const StringC &str, ComponentName::Id &id)
698 {
699   const int *val = nodePropertyTable_.lookup(str);
700   if (!val) {
701     StringC tem(str);
702     for (size_t i = 0; i < tem.size(); i++) {
703       if (tem[i] >= 'A' && tem[i] <= 'Z')
704         tem[i] = 'a' + (tem[i] - 'A');
705     }
706     val = nodePropertyTable_.lookup(tem);
707     if (!val)
708       return 0;
709   }
710   id = ComponentName::Id(*val);
711   return 1;
712 }
713
714 Unit *Interpreter::lookupUnit(const StringC &str)
715 {
716   Unit *unit = unitTable_.lookup(str);
717   if (!unit) {
718     unit = new Unit(str);
719     unitTable_.insert(unit);
720   }
721   return unit;
722 }
723
724 ProcessingMode *Interpreter::lookupProcessingMode(const StringC &str)
725 {
726   ProcessingMode *mode = processingModeTable_.lookup(str);
727   if (!mode) {
728     mode = new ProcessingMode(str, &initialProcessingMode_);
729     processingModeTable_.insert(mode);
730   }
731   return mode;
732 }
733
734 StringC Interpreter::makeStringC(const char *s)
735 {
736   StringC tem;
737   if (s)
738     while (*s)
739       tem += (unsigned char)*s++;
740   return tem;
741 }
742
743 void Interpreter::endPart()
744 {
745   currentPartFirstInitialValue_ = initialValueNames_.size();
746   partIndex_++;
747 }
748
749 void Interpreter::dEndPart()
750 {
751   dPartIndex_++;
752 }
753
754 void Interpreter::normalizeGeneralName(const NodePtr &nd, StringC &str)
755 {
756   NamedNodeListPtr nnl;
757   NodePtr root;
758   if (nd->getGroveRoot(root) == accessOK
759       && root->getElements(nnl) == accessOK)
760     str.resize(nnl->normalize(str.begin(), str.size()));
761 }
762
763 ELObj *Interpreter::makeLengthSpec(const FOTBuilder::LengthSpec &ls)
764 {
765   if (ls.displaySizeFactor != 0.0) {
766     LengthSpec result(LengthSpec::displaySize, ls.displaySizeFactor);
767     result += double(ls.length);
768     return new (*this) LengthSpecObj(result);
769   }
770   else
771     return new (*this) LengthObj(ls.length);
772 }
773
774 bool Interpreter::convertBooleanC(ELObj *obj, const Identifier *ident, const Location &loc,
775                                   bool &result)
776 {
777   obj = convertFromString(obj, convertAllowBoolean, loc);
778   if (obj == makeFalse()) {
779     result = 0;
780     return 1;
781   }
782   if (obj == makeTrue()) {
783     result = 1;
784     return 1;
785   }
786   invalidCharacteristicValue(ident, loc);
787   return 0;
788 }
789
790 bool Interpreter::convertPublicIdC(ELObj *obj, const Identifier *ident,
791                                    const Location &loc,
792                                    FOTBuilder::PublicId &pubid)
793 {
794   if (obj == makeFalse()) {
795     pubid = 0;
796     return 1;
797   }
798   const Char *s;
799   size_t n;
800   if (obj->stringData(s, n)) {
801     if (n == 0)
802       pubid = 0;
803     else
804       pubid = storePublicId(s, n, loc);
805     return 1;
806   }
807   invalidCharacteristicValue(ident, loc);
808   return 0;
809 }
810
811 const char *Interpreter::storePublicId(const Char *s, size_t n, const Location &loc)
812 {
813   String<char> buf;
814   for (; n > 0; s++, n--) {
815     if (*s >= 128) {
816       setNextLocation(loc);
817       message(InterpreterMessages::invalidPublicIdChar,
818               StringMessageArg(StringC(s, 1)));
819     }
820     else
821       buf += char(*s);
822   }
823   buf += '\0';
824   return publicIds_.store(buf);
825 }
826
827 bool Interpreter::convertStringC(ELObj *obj, const Identifier *ident, const Location &loc,
828                                  StringC &result)
829 {
830   const Char *s;
831   size_t n;
832   if (obj->stringData(s, n)) {
833     result.assign(s, n);
834     return 1;
835   }
836   invalidCharacteristicValue(ident, loc);
837   return 0;
838 }
839
840 bool Interpreter::convertLengthSpec(ELObj *obj,
841                                     FOTBuilder::LengthSpec &result)
842 {
843   int dim;
844   double d;
845   switch (obj->quantityValue(result.length, d, dim)) {
846   case ELObj::longQuantity:
847     if (dim == 1)
848       return 1;
849     break;
850   case ELObj::doubleQuantity:
851     if (dim == 1) {
852       // FIXME catch overflow
853       result.length = d < 0.0 ? long(d - .5) : long(d + .5);
854       return 1;
855     }
856     break;
857   default:
858     {
859       const LengthSpec *ls = obj->lengthSpec();
860       if (ls)
861         return ls->convert(result);
862     }
863     break;
864   }
865   return 0;
866 }
867
868 bool Interpreter::convertLengthC(ELObj *obj, const Identifier *ident,
869                                  const Location &loc,
870                                  FOTBuilder::Length &n)
871 {
872   obj = convertFromString(obj, convertAllowNumber, loc);
873   int dim;
874   double d;
875   switch (obj->quantityValue(n, d, dim)) {
876   case ELObj::longQuantity:
877     if (dim == 1)
878       return 1;
879     break;
880   case ELObj::doubleQuantity:
881     if (dim == 1) {
882       // FIXME catch overflow
883       n = long(d);
884       return 1;
885     }
886     break;
887   default:
888     break;
889   }
890   invalidCharacteristicValue(ident, loc);
891   return 0;
892 }
893
894 bool Interpreter::convertLengthSpecC(ELObj *obj, const Identifier *ident,
895                                      const Location &loc,
896                                      FOTBuilder::LengthSpec &result)
897 {
898   obj = convertFromString(obj, convertAllowNumber, loc);
899   if (convertLengthSpec(obj, result))
900     return 1;
901   invalidCharacteristicValue(ident, loc);
902   return 0;
903 }
904
905 bool Interpreter::convertOptLengthSpecC(ELObj *obj, const Identifier *ident,
906                                         const Location &loc,
907                                         FOTBuilder::OptLengthSpec &result)
908 {
909   obj = convertFromString(obj, convertAllowBoolean|convertAllowNumber, loc);
910   if (obj == makeFalse()) {
911     result.hasLength = 0;
912     return 1;
913   }
914   if (convertLengthSpecC(obj, ident, loc, result.length)) {
915     result.hasLength = 1;
916     return 1;
917   }
918   return 0;
919 }
920
921 bool Interpreter::convertOptPositiveIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
922                                              long &result)
923 {
924   obj = convertFromString(obj, convertAllowNumber|convertAllowBoolean, loc);
925   if (obj == makeFalse()) {
926     result = 0;
927     return 1;
928   }
929   if (obj->exactIntegerValue(result) && result > 0)
930     return 1;
931   // FIXME allow inexact value
932   invalidCharacteristicValue(ident, loc);
933   return 0;
934 }
935
936 bool Interpreter::convertIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
937                                   long &result)
938 {
939   obj = convertFromString(obj, convertAllowNumber, loc);
940   if (obj->exactIntegerValue(result))
941     return 1;
942   // FIXME allow inexact value
943   invalidCharacteristicValue(ident, loc);
944   return 0;
945 }
946
947
948 bool Interpreter::convertLetter2C(ELObj *obj, const Identifier *ident, const Location &loc,
949                                   FOTBuilder::Letter2 &code)
950 {
951   StringObj *strObj = obj->convertToString();
952   if (strObj) {
953     const StringC &str = *strObj;
954     if (str.size() == 2
955         && str[0] >= 'A' && str[0] <= 'Z'
956         && str[1] >= 'A' && str[1] <= 'Z') {
957       code = SP_LETTER2(str[0], str[1]);
958       return 1;
959     }
960     if (str.size() == 0) {
961       code = 0;
962       return 1;
963     }
964   }
965   else if (obj == makeFalse()) {
966     code = 0;
967     return 1;
968   }
969   invalidCharacteristicValue(ident, loc);
970   return 0;
971 }
972
973 bool Interpreter::convertCharC(ELObj *obj, const Identifier *ident, const Location &loc,
974                                Char &result)
975 {
976   if (obj->charValue(result))
977     return 1;
978   const Char *s;
979   size_t n;
980   if (obj->stringData(s, n) && n == 1) {
981     result = s[0];
982     return 1;
983   }
984   invalidCharacteristicValue(ident, loc);
985   return 0;
986 }
987
988 bool Interpreter::convertColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
989 {
990   color = obj->asColor();
991   if (color)
992     return 1;
993   invalidCharacteristicValue(ident, loc);
994   return 0;
995 }
996
997 bool Interpreter::convertOptColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
998 {
999   color = obj->asColor();
1000   if (color)
1001     return 1;
1002   if (obj == makeFalse())
1003     return 1;
1004   invalidCharacteristicValue(ident, loc);
1005   return 0;
1006 }
1007
1008 bool Interpreter::convertRealC(ELObj *obj, const Identifier *ident, const Location &loc,
1009                                double &result)
1010 {
1011   obj = convertFromString(obj, convertAllowNumber, loc);
1012   if (obj->realValue(result))
1013     return 1;
1014   invalidCharacteristicValue(ident, loc);
1015   return 0;
1016 }
1017
1018 bool Interpreter::convertEnumC(ELObj *obj, const Identifier *ident, const Location &loc,
1019                                FOTBuilder::Symbol &sym)
1020 {
1021   obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
1022   if (obj == makeFalse()) {
1023     sym = FOTBuilder::symbolFalse;
1024     return 1;
1025   }
1026   SymbolObj *symObj = obj->asSymbol();
1027   if (symObj) {
1028     sym = symObj->cValue();
1029     if (sym != FOTBuilder::symbolFalse)
1030       return 1;
1031   }
1032   if (obj == makeTrue()) {
1033     sym = FOTBuilder::symbolTrue;
1034     return 1;
1035   }
1036   invalidCharacteristicValue(ident, loc);
1037   return 0;
1038 }
1039
1040 bool Interpreter::convertEnumC(const FOTBuilder::Symbol *syms,  size_t nSyms,
1041                                ELObj *obj, const Identifier *ident, const Location &loc,
1042                                FOTBuilder::Symbol &result)
1043 {
1044   obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
1045   SymbolObj *symObj = obj->asSymbol();
1046   FOTBuilder::Symbol val;
1047   if (symObj) {
1048     val = symObj->cValue();
1049     if (val == FOTBuilder::symbolFalse) {
1050       invalidCharacteristicValue(ident, loc);
1051       return 0;
1052     }
1053   }
1054   else if (obj == makeFalse())
1055     val = FOTBuilder::symbolFalse;
1056   else if (obj == makeTrue())
1057     val = FOTBuilder::symbolTrue;
1058   else {
1059     invalidCharacteristicValue(ident, loc);
1060     return 0;
1061   }
1062   for (size_t i = 0; i < nSyms; i++)
1063     if (val == syms[i]) {
1064       result = val;
1065       return 1;
1066     }
1067   invalidCharacteristicValue(ident, loc);
1068   return 0;
1069 }
1070
1071 void Interpreter::invalidCharacteristicValue(const Identifier *ident, const Location &loc)
1072 {
1073   setNextLocation(loc);
1074   message(InterpreterMessages::invalidCharacteristicValue,
1075           StringMessageArg(ident->name()));
1076 }
1077
1078 static
1079 bool equal(const Char *s1, const char *s2, size_t n)
1080 {
1081   while (n > 0) {
1082     if (*s1++ != (unsigned char)*s2++)
1083       return 0;
1084     --n;
1085   }
1086   return 1;
1087 }
1088
1089 ELObj *Interpreter::convertFromString(ELObj *obj, unsigned hints, const Location &loc)
1090 {
1091   // FIXME fold to lower case
1092   const Char *s;
1093   size_t n;
1094   if (!dsssl2() || !obj->stringData(s, n))
1095     return obj;
1096   if (hints & convertAllowNumber) {
1097     ELObj *tem = convertNumber(StringC(s, n));
1098     if (tem)
1099       return tem->resolveQuantities(1, *this, loc);
1100   }
1101   if (hints & convertAllowSymbol) {
1102     StringC tem(s, n);
1103     SymbolObj *sym = symbolTable_.lookup(tem);
1104     if (sym && sym->cValue() != FOTBuilder::symbolFalse)
1105       return sym;
1106   }
1107   if (hints & convertAllowBoolean) {
1108     switch (n) {
1109     case 2:
1110       if (equal(s, "no", n))
1111         return makeFalse();
1112       break;
1113     case 3:
1114       if (equal(s, "yes", n))
1115         return makeTrue();
1116       break;
1117     case 4:
1118       if (equal(s, "true", n))
1119         return makeTrue();
1120       break;
1121     case 5:
1122       if (equal(s, "false", n))
1123         return makeFalse();
1124       break;
1125     }
1126   }
1127   return obj;
1128 }
1129
1130 ELObj *Interpreter::convertNumber(const StringC &str, int radix)
1131 {
1132   {
1133     if (str.size() == 0)
1134       return 0;
1135     size_t i = 0;
1136     if (str[0] == '#') {
1137       if (str.size() < 2)
1138         return 0;
1139       switch (str[1]) {
1140       case 'd':
1141         radix = 10;
1142         break;
1143       case 'x':
1144         radix = 16;
1145         break;
1146       case 'o':
1147         radix = 8;
1148         break;
1149       case 'b':
1150         radix = 2;
1151         break;
1152       default:
1153         return 0;
1154       }
1155       i += 2;
1156     }
1157     if (i >= str.size())
1158       return 0;
1159     bool negative;
1160     if (str[i] == '-') {
1161       negative = 1;
1162       i++;
1163     }
1164     else {
1165       negative = 0;
1166       if (str[i] == '+')
1167       i++;
1168     }
1169     bool hadDecimalPoint = 0;
1170     bool hadDigit = 0;
1171     long n = 0;
1172     int exp = 0;
1173     for (; i < str.size(); i++) {
1174       Char c = str[i];
1175       int weight;
1176       switch (c) {
1177       case '0':
1178         weight = 0;
1179         break;
1180       case '1':
1181         weight = 1;
1182         break;
1183       case '2':
1184         weight = 2;
1185         break;
1186       case '3':
1187         weight = 3;
1188         break;
1189       case '4':
1190         weight = 4;
1191         break;
1192       case '5':
1193         weight = 5;
1194         break;
1195       case '6':
1196         weight = 6;
1197         break;
1198       case '7':
1199         weight = 7;
1200         break;
1201       case '8':
1202         weight = 8;
1203         break;
1204       case '9':
1205         weight = 9;
1206         break;
1207       case 'a':
1208         weight = 10;
1209         break;
1210       case 'b':
1211         weight = 11;
1212         break;
1213       case 'c':
1214         weight = 12;
1215         break;
1216       case 'd':
1217         weight = 13;
1218         break;
1219       case 'e':
1220         weight = 14;
1221         break;
1222       case 'f':
1223         weight = 15;
1224         break;
1225       default:
1226         weight = -1;
1227         break;
1228       }
1229       if (weight >= 0 && weight < radix) {
1230         hadDigit = 1;
1231         if (negative) {
1232           if (-(unsigned long)n > (-(unsigned long)LONG_MIN - weight)/radix) {
1233             if (radix != 10)
1234               return 0;
1235             return convertNumberFloat(str);
1236           }
1237           else
1238             n = n*radix - weight;
1239         }
1240         else {
1241           if (n > (LONG_MAX - weight)/radix) {
1242             if (radix != 10)
1243               return 0;
1244             return convertNumberFloat(str);
1245           }
1246           else
1247             n = n*radix + weight;
1248         }
1249         if (hadDecimalPoint)
1250           exp--;
1251       }
1252       else if (c == '.' && radix == 10) {
1253         if (hadDecimalPoint)
1254           return 0;
1255         hadDecimalPoint = 1;
1256       }
1257       else
1258         break;
1259     }
1260     if (!hadDigit || (radix != 10 && i < str.size()))
1261       return 0;
1262     if (i + 1 < str.size() && str[i] == 'e'
1263         && lexCategory(str[i + 1]) != lexLetter) {
1264       hadDecimalPoint = 1;
1265       i++;
1266       int e;
1267       if (!scanSignDigits(str, i, e))
1268         return 0;
1269       exp += e;
1270     }
1271     if (i < str.size()) {
1272       int unitExp;
1273       Unit *unit = scanUnit(str, i, unitExp);
1274       if (!unit)
1275         return 0;
1276       if (unitExp == 1)
1277         return new (*this) UnresolvedLengthObj(n, exp, unit);
1278       else
1279         return convertNumberFloat(str);
1280     }
1281     if (hadDecimalPoint)
1282       return convertNumberFloat(str);
1283     return makeInteger(n);
1284   }
1285 }
1286
1287 bool Interpreter::scanSignDigits(const StringC &str, size_t &i, int &n)
1288 {
1289   bool negative = 0;
1290   if (i < str.size()) {
1291     if (str[i] == '-') {
1292       i++;
1293       negative = 1;
1294     } else if (str[i] == '+')
1295       i++;
1296   }
1297   size_t j = i;
1298   n = 0;
1299   while (i < str.size()
1300          && ('0' <= str[i] && str[i] <= '9')) {
1301     if (negative)
1302       n = n*10 - (str[i] - '0');
1303     else
1304       n = n*10 + (str[i] - '0');
1305     i++;
1306   }
1307   if (i == j)
1308     return 0;
1309   return 1;
1310 }
1311
1312 ELObj *Interpreter::convertNumberFloat(const StringC &str)
1313 {
1314   String<char> buf;
1315   // omit an optional radix prefix
1316   size_t i0 = 0;
1317   if (str.size() > 1 && str[0] == '#' && str[1] == 'd')
1318     i0 = 2;
1319   for (size_t i = i0; i < str.size(); i++) {
1320     if (str[i] > CHAR_MAX || str[i] == '\0')
1321       return 0;
1322     // 'E' is a valid exponent marker for C but not us
1323     if (str[i] == 'E')
1324       break;
1325     buf += char(str[i]);
1326   }
1327   buf += '\0';
1328   const char *endPtr;
1329   double val = strtod((char *)buf.data(), (char **)&endPtr);
1330   if (endPtr - buf.data() == str.size() - i0)
1331     return new (*this) RealObj(val);
1332   if (endPtr == buf.data())
1333     return 0;
1334   int unitExp;
1335   Unit *unit = scanUnit(str, endPtr - buf.data() + i0, unitExp);
1336   if (!unit)
1337     return 0;
1338   return new (*this) UnresolvedQuantityObj(val, unit, unitExp);
1339 }
1340
1341 // Return 0 for error.
1342
1343 Unit *Interpreter::scanUnit(const StringC &str, size_t i, int &unitExp)
1344 {
1345   StringC unitName;
1346   while (i < str.size()) {
1347     if (str[i] == '-' || str[i] == '+' || ('0' <= str[i] && str[i] <= '9'))
1348       break;
1349     unitName += str[i++];
1350   }
1351   if (i >= str.size())
1352     unitExp = 1;
1353   else {
1354     unitExp = 0;
1355     bool neg = 0;
1356     if (str[i] == '-' || str[i] == '+') {
1357       if (str[i] == '-')
1358       neg = 1;
1359       i++;
1360       if (i >= str.size())
1361         return 0;
1362     }
1363     while (i < str.size()) {
1364       if (str[i] < '0' || str[i] > '9')
1365         return 0;
1366       unitExp *= 10;
1367       if (neg)
1368         unitExp -= (str[i] - '0');
1369       else
1370         unitExp += (str[i] - '0');
1371       i++;
1372     }
1373   }
1374   return lookupUnit(unitName);
1375 }
1376
1377 void Interpreter::setNodeLocation(const NodePtr &nd)
1378 {
1379   const LocNode *lnp;
1380   Location nodeLoc;
1381   if ((lnp = LocNode::convert(nd)) != 0
1382       && lnp->getLocation(nodeLoc) == accessOK)
1383     setNextLocation(nodeLoc);
1384 }
1385
1386 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc, Pattern &pattern)
1387 {
1388   IList<Pattern::Element> list;
1389   if (!convertToPattern(obj, loc, 0, list))
1390     return 0;
1391   Pattern tem(list);
1392   tem.swap(pattern);
1393   return 1;
1394 }
1395
1396 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc,
1397                                    bool isChild,
1398                                    IList<Pattern::Element> &list)
1399 {
1400   StringObj *str = obj->convertToString();
1401   if (str) {
1402     const Char *s;
1403     size_t n;
1404     str->stringData(s, n);
1405     if (!n) {
1406       setNextLocation(loc);
1407       message(InterpreterMessages::patternEmptyGi);
1408       return 0;
1409     }
1410     list.insert(new Pattern::Element(StringC(s, n)));
1411     return 1;
1412   }
1413   if (obj == makeTrue()) {
1414     list.insert(new Pattern::Element(StringC()));
1415     return 1;
1416   }
1417   Pattern::Element *curElement = 0;
1418   while (!obj->isNil()) {
1419     PairObj *pair = obj->asPair();
1420     if (!pair) {
1421       setNextLocation(loc);
1422       message(InterpreterMessages::patternNotList);
1423       return 0;
1424     }
1425     ELObj *head = pair->car();
1426     obj = pair->cdr();
1427     if (head == makeTrue() && dsssl2()) {
1428       list.insert(curElement = new Pattern::Element(StringC()));
1429       continue;
1430     }
1431     str = head->convertToString();
1432     if (str) {
1433       const Char *s;
1434       size_t n;
1435       str->stringData(s, n);
1436       if (!n) {
1437         setNextLocation(loc);
1438         message(InterpreterMessages::patternEmptyGi);
1439         return 0;
1440       }
1441       list.insert(curElement = new Pattern::Element(StringC(s, n)));
1442       continue;
1443     }
1444     if (!curElement) {
1445       setNextLocation(loc);
1446       message(InterpreterMessages::patternBadGi,
1447               ELObjMessageArg(head, *this));
1448       return 0;
1449     }
1450     if (head->isNil())
1451       continue; // empty attribute list
1452     if (head->asPair()) {
1453       if (!patternAddAttributeQualifiers(head, loc, *curElement)) {
1454         setNextLocation(loc);
1455         message(InterpreterMessages::patternBadAttributeQualifier);
1456         return 0;
1457       }
1458       continue;
1459     }
1460     KeywordObj *key = dsssl2() ? head->asKeyword() : 0;
1461     if (!key) {
1462       setNextLocation(loc);
1463       message(InterpreterMessages::patternBadMember,
1464               ELObjMessageArg(head, *this));
1465       return 0;
1466     }
1467     pair = obj->asPair();
1468     if (!pair) {
1469       setNextLocation(loc);
1470       message(obj->isNil()
1471               ? InterpreterMessages::patternMissingQualifierValue
1472               : InterpreterMessages::patternNotList);
1473       return 0;
1474     }
1475     ELObj *value = pair->car();
1476     obj = pair->cdr();
1477     Identifier::SyntacticKey k;
1478     if (!key->identifier()->syntacticKey(k)) {
1479       setNextLocation(loc);
1480       message(InterpreterMessages::patternUnknownQualifier,
1481               StringMessageArg(key->identifier()->name()));
1482       return 0;
1483     }
1484     switch (k) {
1485     case Identifier::keyAttributes:
1486       if (!patternAddAttributeQualifiers(value, loc, *curElement)) {
1487         setNextLocation(loc);
1488         message(InterpreterMessages::patternBadAttributeQualifier);
1489         return 0;
1490       }
1491       break;
1492     case Identifier::keyChildren:
1493       {
1494         IList<Pattern::Element> children;
1495         if (!convertToPattern(value, loc, 1, children))
1496           return 0;
1497         if (!children.empty())
1498           curElement->addQualifier(new Pattern::ChildrenQualifier(children));
1499       }
1500       break;
1501     case Identifier::keyRepeat:
1502       {
1503         if (isChild) {
1504           setNextLocation(loc);
1505           message(InterpreterMessages::patternChildRepeat);
1506           return 0;
1507         }
1508         SymbolObj *sym = value->asSymbol();
1509         if (sym) {
1510           const StringC &str = *sym->name();
1511           if (str.size() == 1) {
1512             switch (str[0]) {
1513             case '*':
1514               curElement->setRepeat(0, Pattern::Repeat(-1));
1515               value = 0;
1516               break;
1517             case '?':
1518               curElement->setRepeat(0, 1);
1519               value = 0;
1520               break;
1521             case '+':
1522               curElement->setRepeat(1, Pattern::Repeat(-1));
1523               value = 0;
1524               break;
1525             default:
1526               break;
1527             }
1528           }
1529         }
1530         if (value) {
1531           setNextLocation(loc);
1532           message(InterpreterMessages::patternBadQualifierValue,
1533                   ELObjMessageArg(value, *this),
1534                   StringMessageArg(key->identifier()->name()));
1535           return 0;
1536         }
1537       }
1538       break;
1539     case Identifier::keyPosition:
1540       {
1541         SymbolObj *sym = value->asSymbol();
1542         if (sym) {
1543           Pattern::Qualifier *qual = 0;
1544           const StringC &str = *sym->name();
1545           if (str == "first-of-type")
1546             qual = new Pattern::FirstOfTypeQualifier;
1547           else if (str == "last-of-type")
1548             qual = new Pattern::LastOfTypeQualifier;
1549           else if (str == "first-of-any")
1550             qual = new Pattern::FirstOfAnyQualifier;
1551           else if (str == "last-of-any")
1552             qual = new Pattern::LastOfAnyQualifier;
1553           if (qual) {
1554             curElement->addQualifier(qual);
1555             break;
1556           }
1557         }
1558         setNextLocation(loc);
1559         message(InterpreterMessages::patternBadQualifierValue,
1560                 ELObjMessageArg(value, *this),
1561                 StringMessageArg(key->identifier()->name()));
1562         return 0;
1563       }
1564     case Identifier::keyOnly:
1565       {
1566         SymbolObj *sym = value->asSymbol();
1567         if (sym) {
1568           Pattern::Qualifier *qual = 0;
1569           const StringC &str = *sym->name();
1570           if (str == "of-type")
1571             qual = new Pattern::OnlyOfTypeQualifier;
1572           else if (str == "of-any")
1573             qual = new Pattern::OnlyOfAnyQualifier;
1574           if (qual) {
1575             curElement->addQualifier(qual);
1576             break;
1577           }
1578         }
1579         setNextLocation(loc);
1580         message(InterpreterMessages::patternBadQualifierValue,
1581                 ELObjMessageArg(value, *this),
1582                 StringMessageArg(key->identifier()->name()));
1583         return 0;
1584       }
1585       break;
1586     case Identifier::keyId:
1587       {
1588         StringObj *str = value->convertToString();
1589         if (!str) {
1590           setNextLocation(loc);
1591           message(InterpreterMessages::patternBadQualifierValue,
1592                   ELObjMessageArg(value, *this),
1593                   StringMessageArg(key->identifier()->name()));
1594           return 0;
1595         }
1596         const Char *s;
1597         size_t n;
1598         str->stringData(s, n);
1599         curElement->addQualifier(new Pattern::IdQualifier(StringC(s, n)));
1600       }
1601       break;
1602     case Identifier::keyClass:
1603       {
1604         StringObj *str = value->convertToString();
1605         if (!str) {
1606           setNextLocation(loc);
1607           message(InterpreterMessages::patternBadQualifierValue,
1608                   ELObjMessageArg(value, *this),
1609                   StringMessageArg(key->identifier()->name()));
1610           return 0;
1611         }
1612         const Char *s;
1613         size_t n;
1614         str->stringData(s, n);
1615         curElement->addQualifier(new Pattern::ClassQualifier(StringC(s, n)));
1616       }
1617       break;
1618     case Identifier::keyImportance:
1619       {
1620         long n;
1621         if (!value->exactIntegerValue(n)) {
1622           setNextLocation(loc);
1623           message(InterpreterMessages::patternBadQualifierValue,
1624                   ELObjMessageArg(value, *this),
1625                   StringMessageArg(key->identifier()->name()));
1626           return 0;
1627         }
1628         curElement->addQualifier(new Pattern::ImportanceQualifier(n));
1629       }
1630       break;
1631     case Identifier::keyPriority:
1632       {
1633         long n;
1634         if (!value->exactIntegerValue(n)) {
1635           setNextLocation(loc);
1636           message(InterpreterMessages::patternBadQualifierValue,
1637                   ELObjMessageArg(value, *this),
1638                   StringMessageArg(key->identifier()->name()));
1639           return 0;
1640         }
1641         curElement->addQualifier(new Pattern::PriorityQualifier(n));
1642       }
1643       break;
1644     default:
1645       setNextLocation(loc);
1646       message(InterpreterMessages::patternUnknownQualifier,
1647               StringMessageArg(key->identifier()->name()));
1648       return 0;
1649     }
1650   }
1651   return 1;
1652 }
1653
1654 bool Interpreter::patternAddAttributeQualifiers(ELObj *obj,
1655                                                 const Location &loc,
1656                                                 Pattern::Element &elem)
1657 {
1658   while (!obj->isNil()) {
1659     PairObj *pair = obj->asPair();
1660     if (!pair)
1661       return 0;
1662     StringObj *tem = pair->car()->convertToString();
1663     if (!tem)
1664       return 0;
1665     const Char *s;
1666     size_t n;
1667     tem->stringData(s, n);
1668     if (n == 0)
1669       return 0;
1670     StringC name(s, n);
1671     obj = pair->cdr();
1672     pair = obj->asPair();
1673     if (!pair)
1674       return 0;
1675     obj = pair->cdr();
1676     if (pair->car() == makeFalse() && dsssl2())
1677       elem.addQualifier(new Pattern::AttributeMissingValueQualifier(name));
1678     else if (pair->car() == makeTrue() && dsssl2())
1679       elem.addQualifier(new Pattern::AttributeHasValueQualifier(name));
1680     else {
1681       tem = pair->car()->convertToString();
1682       if (!tem)
1683         return 0;
1684       tem->stringData(s, n);
1685       elem.addQualifier(new Pattern::AttributeQualifier(name, StringC(s, n)));
1686     }
1687   }
1688   return 1;
1689 }
1690
1691 void Interpreter::dispatchMessage(Message &msg)
1692 {
1693   messenger_->dispatchMessage(msg);
1694 }
1695
1696 void Interpreter::dispatchMessage(const Message &msg)
1697 {
1698   messenger_->dispatchMessage(msg);
1699 }
1700
1701 Interpreter::StringSet::StringSet()
1702 {
1703 }
1704
1705 const char *Interpreter::StringSet::store(String<char> &str)
1706 {
1707   str += '\0';
1708   const String<char> *p = table_.lookup(str);
1709   if (!p) {
1710     String<char> *tem = new String<char>;
1711     str.swap(*tem);
1712     table_.insert(tem);
1713     p = tem;
1714   }
1715   return p->data();
1716 }
1717
1718 unsigned long Interpreter::StringSet::hash(const String<char> &str)
1719 {
1720   const char *p = str.data();
1721   unsigned long h = 0;
1722   for (size_t n = str.size(); n > 0; n--)
1723     h = (h << 5) + h + (unsigned char)*p++;     // from Chris Torek
1724   return h;
1725 }
1726
1727 bool Identifier::preferBuiltin_ = 0;
1728
1729 Identifier::Identifier(const StringC &name)
1730 : Named(name), value_(0), syntacticKey_(notKey), beingComputed_(0), 
1731   flowObj_(0), builtin_(0), defPart_(0), charNIC_(0)
1732 {
1733 }
1734
1735 void Identifier::maybeSaveBuiltin()
1736 {
1737   if (defPart_ == unsigned(-1) && !builtin_) {
1738     builtin_ = new Identifier(name());
1739     if (value_)
1740       builtin_->setValue(value_, defPart_);
1741     else
1742       builtin_->setDefinition(def_, defPart_, defLoc_);
1743   }
1744 }
1745  
1746 void Identifier::setDefinition(Owner<Expression> &expr,
1747                                unsigned part,
1748                                const Location &loc)
1749 {
1750   maybeSaveBuiltin();
1751   def_.swap(expr);
1752   defPart_ = part;
1753   defLoc_ = loc;
1754   value_ = 0;
1755 }
1756
1757 void Identifier::setValue(ELObj *value, unsigned partIndex)
1758 {
1759   maybeSaveBuiltin();
1760   value_ = value;
1761   // Built in functions have lowest priority.
1762   defPart_ = partIndex;
1763 }
1764
1765 bool Identifier::defined(unsigned &part, Location &loc) const
1766 {
1767   if (!def_ && !value_)
1768     return 0;
1769   part = defPart_;
1770   loc = defLoc_;
1771   return 1;
1772 }
1773
1774 ELObj *Identifier::computeValue(bool force, Interpreter &interp) const
1775 {
1776   if (builtin_ && preferBuiltin_)
1777     return builtin_->computeValue(force, interp);
1778   if (value_)
1779     return value_;
1780   bool preferred = 0;
1781   if (defPart_ == unsigned(-1) && !preferBuiltin_) {
1782     preferBuiltin_ = 1;
1783     preferred = 1;
1784   }
1785   ASSERT(def_);
1786   if (beingComputed_) {
1787     if (force) {
1788       interp.setNextLocation(defLoc_);
1789       interp.message(InterpreterMessages::identifierLoop,
1790                      StringMessageArg(name()));
1791       ((Identifier *)this)->value_ = interp.makeError();
1792     }
1793   }
1794   else {
1795     ((Identifier *)this)->beingComputed_ = 1;
1796     if (insn_.isNull())
1797       ((Identifier *)this)->insn_ 
1798         = Expression::optimizeCompile(((Identifier *)this)->def_, interp,
1799                                       Environment(), 0, InsnPtr());
1800     if (force || def_->canEval(0)) {
1801       VM vm(interp);
1802       ELObj *v = vm.eval(insn_.pointer());
1803       interp.makePermanent(v);
1804       ((Identifier *)this)->value_ = v;
1805     }
1806     ((Identifier *)this)->beingComputed_ = 0;
1807   }
1808   if (preferred)
1809     preferBuiltin_ = 0;
1810   return value_;
1811 }
1812
1813 ELObj *Identifier::computeBuiltinValue(bool force, Interpreter &interp) const
1814 {
1815   preferBuiltin_ = 1;
1816   ELObj *res = computeValue(force, interp);
1817   preferBuiltin_ = 0;
1818   return res;
1819 }
1820
1821 Unit::Unit(const StringC &name)
1822 : Named(name), computed_(notComputed)
1823 {
1824 }
1825
1826 bool Unit::defined(unsigned &part, Location &loc) const
1827 {
1828   if (!def_ && computed_ == notComputed)
1829     return 0;
1830   part = defPart_;
1831   loc = defLoc_;
1832   return 1;
1833 }
1834
1835 void Unit::setDefinition(Owner<Expression> &expr,
1836                          unsigned part,
1837                          const Location &loc)
1838 {
1839   def_.swap(expr);
1840   defPart_ = part;
1841   defLoc_ = loc;
1842   computed_ = notComputed;
1843 }
1844
1845 void Unit::setValue(long n)
1846 {
1847   computed_ = computedExact;
1848   exact_ = n;
1849   dim_ = 1;
1850   defPart_ = unsigned(-1);
1851 }
1852
1853 void Unit::setValue(double n)
1854 {
1855   computed_ = computedInexact;
1856   inexact_ = n;
1857   dim_ = 1;
1858   defPart_ = unsigned(-1);
1859 }
1860
1861 void Unit::tryCompute(bool force, Interpreter &interp)
1862 {
1863   if (computed_ == notComputed) {
1864     computed_ = beingComputed;
1865     if (insn_.isNull())
1866       insn_ = Expression::optimizeCompile(def_, interp, Environment(), 0, InsnPtr());
1867     if (force || def_->canEval(0)) {
1868       VM vm(interp);
1869       ELObj *v = vm.eval(insn_.pointer());
1870       switch (v->quantityValue(exact_, inexact_, dim_)) {
1871       case ELObj::noQuantity:
1872         if (!interp.isError(v)) {
1873           interp.setNextLocation(defLoc_);
1874           interp.message(InterpreterMessages::badUnitDefinition,
1875                          StringMessageArg(name()));
1876         }
1877         computed_ = computedError;
1878         break;
1879       case ELObj::longQuantity:
1880         computed_ = computedExact;
1881         break;
1882       case ELObj::doubleQuantity:
1883         computed_ = computedInexact;
1884         break;
1885       default:
1886         CANNOT_HAPPEN();
1887       }
1888     }
1889     if (computed_ == beingComputed)
1890       computed_ = notComputed;
1891   }
1892   else if (computed_ == beingComputed) {
1893     interp.setNextLocation(defLoc_);
1894     interp.message(InterpreterMessages::unitLoop,
1895                    StringMessageArg(name()));
1896     computed_ = computedError;
1897   }
1898 }
1899
1900 // multiply by 10^valExp
1901 // quantity has exponent of 1
1902
1903 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1904                              long val, int valExp)
1905 {
1906   tryCompute(force, interp);
1907   long result;
1908   if (computed_ == computedExact && scale(val, valExp, exact_, result))
1909     return new (interp) LengthObj(result);
1910   double x = val;
1911   while (valExp > 0) {
1912     x *= 10.0;
1913     valExp--;
1914   }
1915   while (valExp < 0) {
1916     x /= 10.0;
1917     valExp++;
1918   }
1919   return resolveQuantity(force, interp, x, 1);
1920 }
1921
1922 // val * 10^valExp * factor
1923 // return 0 if it can't be done without overflow
1924
1925 bool Unit::scale(long val, int valExp, long factor, long &result)
1926 {
1927   if (factor <= 0)
1928     return 0; // feeble
1929   while (valExp > 0) {
1930     if (factor > LONG_MAX/10)
1931       return 0;
1932     valExp--;
1933     factor *= 10;
1934   }
1935   if (val >= 0) {
1936     if (val > LONG_MAX/factor)
1937       return 0;
1938   }
1939   else {
1940     if (-(unsigned long)val > -(unsigned long)LONG_MIN/factor)
1941       return 0;
1942   }
1943   result = val*factor;
1944   while (valExp < 0) {
1945     result /= 10;
1946     valExp++;
1947   }
1948   return 1;
1949 }
1950
1951 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1952                              double val, int unitExp)
1953 {
1954   tryCompute(force, interp);
1955   double factor;
1956   switch (computed_) {
1957   case computedExact:
1958     factor = exact_;
1959     break;
1960   case computedInexact:
1961     factor = inexact_;
1962     break;
1963   case computedError:
1964     return interp.makeError();
1965   default:
1966     return 0;
1967   }
1968   int resultDim = 0;
1969   double resultVal = val;
1970   while (unitExp > 0) {
1971     resultDim += dim_;
1972     resultVal *= factor;
1973     unitExp--;
1974   }
1975   while (unitExp < 0) {
1976     resultDim -= dim_;
1977     resultVal /= factor;
1978     unitExp++;
1979   }
1980   if (resultDim == 0)
1981     return new (interp) RealObj(resultVal);
1982   return new (interp) QuantityObj(resultVal, resultDim);
1983 }
1984
1985 void ELObjDynamicRoot::trace(Collector &c) const
1986 {
1987   c.trace(obj_);
1988 }
1989
1990 bool operator==(const StringC &s, const char *p)
1991 {
1992   for (size_t i = 0; i < s.size(); i++)
1993     if (p[i] == '\0' || (unsigned char)p[i] != s[i])
1994       return 0;
1995   return p[s.size()] == '\0';
1996 }
1997
1998 void Interpreter::installBuiltins()
1999 {
2000   partIndex_ = unsigned(-1);
2001   StringC sysid(makeStringC(DEFAULT_SCHEME_BUILTINS));
2002   StringC src;
2003   groveManager_->mapSysid(sysid);
2004   if (groveManager_->readEntity(sysid, src)) {
2005     Owner<InputSource> in(new InternalInputSource(src,
2006                               InputSourceOrigin::make()));
2007     SchemeParser scm(*this, in);
2008     scm.parse();
2009   }
2010   endPart();
2011   partIndex_ = 0;
2012 }
2013
2014 void Interpreter::setDefaultLanguage(Owner<Expression> &expr,
2015                                      unsigned part,
2016                                      const Location &loc)
2017 {
2018   defaultLanguageDef_.swap(expr);
2019   defaultLanguageDefPart_ = part;
2020   defaultLanguageDefLoc_ = loc;
2021 }
2022
2023 ELObj *Interpreter::defaultLanguage() const
2024 {
2025   return defaultLanguage_;
2026 }
2027
2028 bool Interpreter::defaultLanguageSet(unsigned &part,Location &loc) const
2029 {
2030   if(defaultLanguageDef_) {
2031     part = defaultLanguageDefPart_;
2032     loc = defaultLanguageDefLoc_;
2033     return true;
2034   }
2035   return false;
2036 }
2037
2038 void Interpreter::compileDefaultLanguage()
2039 {
2040   if(defaultLanguageDef_) {
2041     InsnPtr insn = Expression::optimizeCompile(defaultLanguageDef_, *this,
2042                                                Environment(), 0, InsnPtr());
2043     VM vm(*this);
2044     ELObj *obj = vm.eval(insn.pointer());
2045     if(!obj->asLanguage()) {
2046       if(!isError(obj)) {
2047         setNextLocation(defaultLanguageDefLoc_);
2048         message(InterpreterMessages::defLangDeclRequiresLanguage,
2049                 ELObjMessageArg(obj, *this));
2050       }
2051       return;
2052     }
2053     makePermanent(obj);
2054     defaultLanguage_ = obj;
2055   }
2056 }
2057
2058 void Interpreter::installCharProperties()
2059 {
2060   //FIXME convert this to tables 
2061   // initialize charProperties_;
2062   // if a character doesn't have a value for a property,
2063   // the CharMap contains 0. 
2064
2065   CharProp cp;
2066
2067   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2068   cp.loc = Location();
2069   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2070   if (!strictMode_)
2071     for (int i = 0; i < 10; i++) {
2072       ELObjPart num(makeInteger(i), unsigned(-1));
2073       makePermanent(num.obj);
2074       cp.map->setChar(i+'0', num);
2075     }
2076   charProperties_.insert(makeStringC("numeric-equiv"), cp);
2077   
2078   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2079   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2080   if (!strictMode_) {
2081     static struct {
2082       Char c;
2083       unsigned num;
2084     } chars[] = {
2085 #define SPACE 
2086 #include "charProps.h"
2087 #undef SPACE
2088     };
2089    
2090     for (size_t i = 0; i < SIZEOF(chars); i++) 
2091       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2092                        ELObjPart(makeTrue(), unsigned(-1)));
2093   }
2094   charProperties_.insert(makeStringC("space?"), cp);
2095     
2096   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2097   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2098   if (!strictMode_) {
2099     static struct {
2100       Char c;
2101       unsigned num;
2102     } chars[] = {
2103 #define RECORD_END
2104 #include "charProps.h"
2105 #undef RECORD_END
2106     };
2107     
2108     for (size_t i = 0; i < SIZEOF(chars); i++) 
2109       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2110                        ELObjPart(makeTrue(), unsigned(-1)));
2111   }
2112   charProperties_.insert(makeStringC("record-end?"), cp);
2113
2114   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2115   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2116   if (!strictMode_) {
2117     static struct {
2118       Char c;
2119       unsigned num;
2120     } chars[] = {
2121 #define BLANK
2122 #include "charProps.h"
2123 #undef BLANK
2124     };
2125     
2126     for (size_t i = 0; i < SIZEOF(chars); i++) 
2127       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2128                        ELObjPart(makeTrue(), unsigned(-1)));
2129   }
2130   charProperties_.insert(makeStringC("blank?"), cp);
2131
2132   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2133   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2134   if (!strictMode_) {
2135     static struct {
2136       Char c;
2137       unsigned num;
2138     } chars[] = {
2139 #define INPUT_TAB
2140 #include "charProps.h"
2141 #undef INPUT_TAB
2142     };
2143     
2144     for (size_t i = 0; i < SIZEOF(chars); i++) 
2145       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2146                        ELObjPart(makeTrue(), unsigned(-1)));
2147   }
2148   charProperties_.insert(makeStringC("input-tab?"), cp);
2149     
2150   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2151   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2152   if (!strictMode_) {
2153     static struct {
2154       Char c;
2155       unsigned num;
2156     } chars[] = {
2157 #define INPUT_WHITESPACE
2158 #include "charProps.h"
2159 #undef INPUT_WHITESPACE
2160     };
2161     
2162     for (size_t i = 0; i < SIZEOF(chars); i++) 
2163       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2164                        ELObjPart(makeTrue(), unsigned(-1)));
2165   }
2166   charProperties_.insert(makeStringC("input-whitespace?"), cp);
2167
2168   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2169   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2170   if (!strictMode_) {
2171     static struct {
2172       Char c;
2173       unsigned num;
2174     } chars[] = {
2175 #define PUNCT
2176 #include "charProps.h"
2177 #undef PUNCT
2178     };
2179     
2180     for (size_t i = 0; i < SIZEOF(chars); i++) 
2181       cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2182                        ELObjPart(makeTrue(), unsigned(-1)));
2183   }
2184   charProperties_.insert(makeStringC("punct?"), cp);
2185
2186   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2187   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2188   if (!strictMode_) {
2189     static struct {
2190       Char c1, c2;
2191       char *script;
2192     } chars[] = {
2193 #define SCRIPT
2194 #include "charProps.h"
2195 #undef SCRIPT
2196     };
2197     
2198     StringC prefix = makeStringC("ISO/IEC 10179::1996//Script::");
2199     for (size_t i = 0; i < SIZEOF(chars); i++) { 
2200       StringC tem(prefix);
2201       tem += makeStringC(chars[i].script);
2202       StringObj *obj = new (*this) StringObj(tem);
2203       makePermanent(obj);  
2204       cp.map->setRange(chars[i].c1, chars[i].c2,
2205                        ELObjPart(obj, unsigned(-1)));
2206     }
2207   }
2208   charProperties_.insert(makeStringC("script"), cp);
2209
2210   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2211   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2212   charProperties_.insert(makeStringC("glyph-id"), cp);  
2213
2214   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2215   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2216   charProperties_.insert(makeStringC("drop-after-line-break?"), cp);  
2217
2218   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2219   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2220   charProperties_.insert(makeStringC("drop-unless-before-line-break?"), cp);  
2221
2222   cp.def = ELObjPart(makeInteger(0), unsigned(-1));
2223   makePermanent(cp.def.obj);
2224   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2225   CharProp cp2;
2226   cp2.def = ELObjPart(cp.def.obj, unsigned(-1));
2227   cp2.loc = Location();
2228   cp2.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2229   if(!strictMode_) {
2230     static struct {
2231       Char c;
2232       unsigned short num;
2233       unsigned short bbp;
2234       unsigned short bap;
2235     } chars[] ={
2236 #define BREAK_PRIORITIES
2237 #include "charProps.h"
2238 #undef BREAK_PRIORITIES
2239     };
2240     for(size_t i = 0; i<SIZEOF(chars); ++i) {
2241       ELObj *obj = makeInteger(chars[i].bbp);
2242       makePermanent(obj);
2243       cp.map->setRange(chars[i].c, chars[i].c + chars[i].num-1,
2244                        ELObjPart(obj, unsigned(-1)));
2245       if(chars[i].bap!=chars[i].bbp) {
2246         obj = makeInteger(chars[i].bap);
2247         makePermanent(obj);
2248       }
2249       cp2.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2250                         ELObjPart(obj, unsigned(-1)));
2251     }
2252   }
2253
2254   charProperties_.insert(makeStringC("break-before-priority"), cp);  
2255   charProperties_.insert(makeStringC("break-after-priority"), cp2);  
2256
2257   cp.def = ELObjPart(makeSymbol(makeStringC("ordinary")), unsigned(-1));
2258   makePermanent(cp.def.obj);
2259   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2260   charProperties_.insert(makeStringC("math-class"), cp);  
2261
2262   cp.def = ELObjPart(makeFalse(), unsigned(-1));
2263   cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2264   charProperties_.insert(makeStringC("math-font-posture"), cp);  
2265 }
2266
2267 // return 1 if the character has the property, return 0 if no such property
2268 // or the character doesn't have the property
2269 // set ret to the value or the default value
2270 ELObj *Interpreter::charProperty(const StringC &prop, Char c, const Location &loc, ELObj *def) 
2271 {
2272   const CharProp *cp = charProperties_.lookup(prop);
2273   if (!cp) {
2274     setNextLocation(loc);
2275     message(InterpreterMessages::unknownCharProperty,
2276             StringMessageArg(prop));
2277     return makeError();
2278   }
2279
2280   if ((*cp->map)[c].obj) 
2281     return (*cp->map)[c].obj;
2282   else if (def) 
2283     return def;
2284   else 
2285     return cp->def.obj;
2286 }
2287
2288 void Interpreter::addCharProperty(const Identifier *prop, Owner<Expression> &defval)
2289 {
2290   // FIXME: what about variable default values ?
2291   defval->optimize(*this, Environment(), defval);
2292   if(!defval->constantValue()) {
2293     setNextLocation(defval->location());
2294     message(InterpreterMessages::varCharPropertyExprUnsupported);
2295     return;
2296   }
2297   // FIXME: this is a kind of memory leak
2298   makePermanent(defval->constantValue());
2299   ELObjPart val(defval->constantValue(), partIndex_);
2300   const CharProp *cp = charProperties_.lookup(prop->name());
2301   if (cp) {
2302     if (partIndex_ < cp->def.defPart) 
2303       ((CharProp *)cp)->def = val;
2304     else if (partIndex_ == cp->def.defPart && 
2305              !ELObj::eqv(*val.obj, *cp->def.obj)) {
2306       // FIXME: report previous location
2307       setNextLocation(defval->location());
2308       message(InterpreterMessages::duplicateCharPropertyDecl,
2309               StringMessageArg(prop->name()), cp->loc);
2310     }
2311   }
2312    else {
2313     CharProp ncp;
2314     ncp.map = new CharMap<ELObjPart>(ELObjPart(0,0));
2315     ncp.def = val;
2316     ncp.loc = defval->location();
2317     charProperties_.insert(prop->name(), ncp);
2318   }
2319 }
2320
2321 void Interpreter::setCharProperty(const Identifier *prop, Char c, Owner<Expression> &val)
2322 {
2323   // FIXME: what about variable default values ?
2324   val->optimize(*this, Environment(), val);
2325   if(!val->constantValue()) {
2326     setNextLocation(val->location());
2327     message(InterpreterMessages::varCharPropertyExprUnsupported);
2328     return;
2329   }
2330   makePermanent(val->constantValue());
2331   const CharProp *cp = charProperties_.lookup(prop->name());
2332   if (!cp) {
2333     CharProp ncp;
2334     ncp.map = new CharMap<ELObjPart>(ELObjPart(0,0));
2335     ncp.def = ELObjPart(0, unsigned(-1));
2336     ncp.loc = val->location();
2337     charProperties_.insert(prop->name(), ncp);
2338     cp = charProperties_.lookup(prop->name());
2339   }
2340   ELObjPart obj = ELObjPart(val->constantValue(), partIndex_);
2341   
2342   ELObjPart def = (*cp->map)[c];
2343   if (def.obj) {
2344     if (partIndex_ < def.defPart) 
2345       cp->map->setChar(c, obj);
2346     else if (partIndex_ == def.defPart && !ELObj::eqv(*obj.obj, *def.obj)) {
2347       setNextLocation(val->location());
2348       // FIXME: report previous location
2349       message(InterpreterMessages::duplicateAddCharProperty,
2350               StringMessageArg(prop->name()),
2351               StringMessageArg(StringC(&c, 1)));
2352     }
2353   }
2354   else 
2355     cp->map->setChar(c, obj);
2356 }
2357
2358 void
2359 Interpreter::compileCharProperties()
2360 {
2361   HashTableIter<StringC, CharProp> iter(charProperties_);
2362   const StringC *key;
2363   const CharProp *val;
2364   while (iter.next(key, val)) 
2365     if (!val->def.obj) {
2366       // FIXME location
2367       setNextLocation(val->loc);
2368       message(InterpreterMessages::unknownCharProperty,
2369               StringMessageArg(*key));
2370       ((CharProp *)val)->def = ELObjPart(makeError(), 0);
2371     }
2372 }
2373
2374
2375 void Interpreter::installExtensionCharNIC(Identifier *ident,
2376                                           const StringC &pubid,
2377                                           const Location &loc)
2378 {
2379   ident->setCharNIC(currentPartIndex(), loc);
2380 }
2381
2382 #ifdef DSSSL_NAMESPACE
2383 }
2384 #endif