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 "macros.h"
14 #include <stdlib.h>
15
16 #ifdef DSSSL_NAMESPACE
17 namespace DSSSL_NAMESPACE {
18 #endif
19
20 const Char defaultChar = 0xfffd;
21
22 static
maxObjSize()23 size_t maxObjSize()
24 {
25 static size_t sz[] = {
26 sizeof(UnresolvedQuantityObj),
27 sizeof(VarStyleObj),
28 sizeof(OverriddenStyleObj),
29 sizeof(MergeStyleObj),
30 sizeof(DeviceRGBColorObj),
31 sizeof(ColorSpaceObj),
32 sizeof(PairObj),
33 sizeof(QuantityObj),
34 sizeof(GlyphIdObj),
35 sizeof(NamedNodeListPtrNodeListObj),
36 sizeof(ProcessNodeSosofoObj),
37 sizeof(AppendSosofoObj),
38 sizeof(SetNonInheritedCsSosofoObj),
39 sizeof(LabelSosofoObj),
40 sizeof(MacroFlowObj),
41 sizeof(FlowObj) + sizeof(StringC), // for FormattingInstructionFlowObj
42 };
43 size_t n = sz[0];
44 for (size_t i = 1; i < SIZEOF(sz); i++)
45 if (sz[i] > n)
46 n = sz[i];
47 return n;
48 }
49
Interpreter(GroveManager * groveManager,Messenger * messenger,int unitsPerInch,bool debugMode,bool dsssl2,const FOTBuilder::Extension * extensionTable)50 Interpreter::Interpreter(GroveManager *groveManager,
51 Messenger *messenger,
52 int unitsPerInch,
53 bool debugMode,
54 bool dsssl2,
55 const FOTBuilder::Extension *extensionTable)
56 : groveManager_(groveManager),
57 messenger_(messenger),
58 extensionTable_(extensionTable),
59 Collector(maxObjSize()),
60 partIndex_(1), // 0 is for command-line definitions
61 lexCategory_(lexOther),
62 unitsPerInch_(unitsPerInch),
63 nInheritedC_(0),
64 initialProcessingMode_(StringC()),
65 currentPartFirstInitialValue_(0),
66 initialStyle_(0),
67 nextGlyphSubstTableUniqueId_(0),
68 debugMode_(debugMode),
69 dsssl2_(dsssl2)
70 {
71 makePermanent(theNilObj_ = new (*this) NilObj);
72 makePermanent(theFalseObj_ = new (*this) FalseObj);
73 makePermanent(theTrueObj_ = new (*this) TrueObj);
74 makePermanent(theErrorObj_ = new (*this) ErrorObj);
75 makePermanent(theUnspecifiedObj_ = new (*this) UnspecifiedObj);
76 makePermanent(addressNoneObj_
77 = new (*this) AddressObj(FOTBuilder::Address::none));
78 makePermanent(emptyNodeListObj_
79 = new (*this) NodePtrNodeListObj);
80 installSyntacticKeys();
81 installCValueSymbols();
82 installPortNames();
83 installPrimitives();
84 installUnits();
85 installCharNames();
86 installFlowObjs();
87 installInheritedCs();
88 installSdata();
89 installNodeProperties();
90
91 static const char *lexCategories[] = {
92 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
93 "!$%&*/<=>?~_^:",
94 "0123456789",
95 "-+.",
96 "();\"",
97 " \t\r\n\f",
98 };
99 //
100 for (size_t i = 0; i < SIZEOF(lexCategories); i++)
101 for (const char *s = lexCategories[i]; *s; s++)
102 lexCategory_.setChar(*s, i);
103 initialProcessingMode_.setDefined();
104 }
105
compile()106 void Interpreter::compile()
107 {
108 // FIXME compile all definitions
109 compileInitialValues();
110 initialProcessingMode_.compile(*this);
111 NamedTableIter<ProcessingMode> iter(processingModeTable_);
112 for (;;) {
113 ProcessingMode *mode = iter.next();
114 if (!mode)
115 break;
116 mode->compile(*this);
117 }
118 }
119
compileInitialValues()120 void Interpreter::compileInitialValues()
121 {
122 Vector<ConstPtr<InheritedC> > ics;
123 for (size_t i = 0; i < initialValueNames_.size(); i++) {
124 const Identifier *ident = initialValueNames_[i];
125 Owner<Expression> &expr = initialValueValues_[i];
126 ConstPtr<InheritedC> ic(ident->inheritedC());
127 expr->optimize(*this, Environment(), expr);
128 ELObj *val = expr->constantValue();
129 if (val) {
130 ConstPtr<InheritedC> tem(ic->make(val, expr->location(), *this));
131 if (!tem.isNull())
132 ics.push_back(tem);
133 }
134 else
135 ics.push_back(new VarInheritedC(ic,
136 expr->compile(*this, Environment(), 0, InsnPtr()),
137 expr->location()));
138 }
139 if (ics.size()) {
140 Vector<ConstPtr<InheritedC> > forceIcs;
141 initialStyle_ = new (*this) VarStyleObj(new StyleSpec(forceIcs, ics), 0, 0, NodePtr());
142 makePermanent(initialStyle_);
143 }
144 }
145
installInitialValue(Identifier * ident,Owner<Expression> & expr)146 void Interpreter::installInitialValue(Identifier *ident, Owner<Expression> &expr)
147 {
148 for (size_t i = 0; i < initialValueNames_.size(); i++) {
149 if (ident == initialValueNames_[i]) {
150 if (i >= currentPartFirstInitialValue_) {
151 setNextLocation(expr->location());
152 message(InterpreterMessages::duplicateInitialValue,
153 StringMessageArg(ident->name()),
154 initialValueValues_[i]->location());
155 }
156 return;
157 }
158 }
159 initialValueValues_.resize(initialValueValues_.size() + 1);
160 expr.swap(initialValueValues_.back());
161 initialValueNames_.push_back(ident);
162 }
163
defineVariable(const StringC & str)164 void Interpreter::defineVariable(const StringC &str)
165 {
166 lookup(str)->setValue(makeTrue(), 0);
167 }
168
installUnits()169 void Interpreter::installUnits()
170 {
171 static struct {
172 const char *name;
173 int numer;
174 int denom;
175 bool dsssl2;
176 } units[] = {
177 { "m", 5000, 127 },
178 { "cm", 50, 127 },
179 { "mm", 5, 127 },
180 { "in", 1, 1 },
181 { "pt", 1, 72 },
182 { "pica", 1, 6 },
183 { "pc", 1, 6 } // a DSSSL2 addition
184 };
185 size_t nUnits = dsssl2() ? SIZEOF(units) : SIZEOF(units) - 1;
186 for (size_t i = 0; i < nUnits; i++) {
187 Unit *unit = lookupUnit(makeStringC(units[i].name));
188 long n = unitsPerInch_ * units[i].numer;
189 if (n % units[i].denom == 0)
190 unit->setValue(long(n / units[i].denom));
191 else
192 unit->setValue(double(n)/units[i].denom);
193 }
194 }
195
installSyntacticKeys()196 void Interpreter::installSyntacticKeys()
197 {
198 static struct {
199 const char *name;
200 Identifier::SyntacticKey key;
201 } keys[] = {
202 { "quote", Identifier::keyQuote },
203 { "lambda", Identifier::keyLambda },
204 { "if", Identifier::keyIf },
205 { "cond", Identifier::keyCond },
206 { "and", Identifier::keyAnd },
207 { "or", Identifier::keyOr },
208 { "case", Identifier::keyCase },
209 { "let", Identifier::keyLet },
210 { "let*", Identifier::keyLetStar },
211 { "letrec", Identifier::keyLetrec },
212 { "quasiquote", Identifier::keyQuasiquote },
213 { "unquote", Identifier::keyUnquote },
214 { "unquote-splicing", Identifier::keyUnquoteSplicing },
215 { "define", Identifier::keyDefine },
216 { "else", Identifier::keyElse },
217 { "=>", Identifier::keyArrow },
218 { "make", Identifier::keyMake },
219 { "style", Identifier::keyStyle },
220 { "with-mode", Identifier::keyWithMode },
221 { "define-unit", Identifier::keyDefineUnit },
222 { "element", Identifier::keyElement },
223 { "default", Identifier::keyDefault },
224 { "root", Identifier::keyRoot },
225 { "id", Identifier::keyId },
226 { "mode", Identifier::keyMode },
227 { "declare-initial-value", Identifier::keyDeclareInitialValue },
228 { "declare-characteristic", Identifier::keyDeclareCharacteristic },
229 { "declare-flow-object-class", Identifier::keyDeclareFlowObjectClass },
230 { "declare-char-characteristic+property", Identifier::keyDeclareCharCharacteristicAndProperty },
231 { "declare-reference-value-type", Identifier::keyDeclareReferenceValueType },
232 { "declare-default-language", Identifier::keyDeclareDefaultLanguage },
233 { "declare-char-property", Identifier::keyDeclareCharProperty },
234 { "define-page-model", Identifier::keyDefinePageModel },
235 { "define-column-set-model", Identifier::keyDefineColumnSetModel },
236 { "define-language", Identifier::keyDefineLanguage },
237 { "add-char-properties", Identifier::keyAddCharProperties },
238 { "use", Identifier::keyUse },
239 { "label", Identifier::keyLabel },
240 { "content-map", Identifier::keyContentMap },
241 { "keep-with-previous?", Identifier::keyIsKeepWithPrevious },
242 { "keep-with-next?", Identifier::keyIsKeepWithNext },
243 { "space-before", Identifier::keySpaceBefore },
244 { "space-after", Identifier::keySpaceAfter },
245 { "left-header", Identifier::keyLeftHeader },
246 { "center-header", Identifier::keyCenterHeader },
247 { "right-header", Identifier::keyRightHeader },
248 { "left-footer", Identifier::keyLeftFooter },
249 { "center-footer", Identifier::keyCenterFooter },
250 { "right-footer", Identifier::keyRightFooter },
251 { "destination", Identifier::keyDestination },
252 { "type", Identifier::keyType },
253 { "coalesce-id", Identifier::keyCoalesceId },
254 { "display?", Identifier::keyIsDisplay },
255 { "scale", Identifier::keyScale },
256 { "max-width", Identifier::keyMaxWidth },
257 { "max-height", Identifier::keyMaxHeight },
258 { "entity-system-id", Identifier::keyEntitySystemId },
259 { "notation-system-id", Identifier::keyNotationSystemId },
260 { "position-point-x", Identifier::keyPositionPointX },
261 { "position-point-y", Identifier::keyPositionPointY },
262 { "escapement-direction", Identifier::keyEscapementDirection },
263 { "break-before-priority", Identifier::keyBreakBeforePriority },
264 { "break-after-priority", Identifier::keyBreakAfterPriority },
265 { "orientation", Identifier::keyOrientation },
266 { "length", Identifier::keyLength },
267 { "char", Identifier::keyChar },
268 { "glyph-id", Identifier::keyGlyphId },
269 { "space?", Identifier::keyIsSpace },
270 { "record-end?", Identifier::keyIsRecordEnd },
271 { "input-tab?", Identifier::keyIsInputTab },
272 { "input-whitespace?", Identifier::keyIsInputWhitespace },
273 { "punct?", Identifier::keyIsPunct },
274 { "drop-after-line-break?", Identifier::keyIsDropAfterLineBreak },
275 { "drop-unless-before-line-break?", Identifier::keyIsDropUnlessBeforeLineBreak },
276 { "math-class", Identifier::keyMathClass },
277 { "math-font-posture", Identifier::keyMathFontPosture },
278 { "script", Identifier::keyScript },
279 { "stretch-factor", Identifier::keyStretchFactor },
280 { "keep", Identifier::keyKeep },
281 { "break-before", Identifier::keyBreakBefore },
282 { "break-after", Identifier::keyBreakAfter },
283 { "may-violate-keep-before?", Identifier::keyIsMayViolateKeepBefore },
284 { "may-violate-keep-after?", Identifier::keyIsMayViolateKeepAfter },
285 { "before-row-border", Identifier::keyBeforeRowBorder },
286 { "after-row-border", Identifier::keyAfterRowBorder },
287 { "before-column-border", Identifier::keyBeforeColumnBorder },
288 { "after-column-border", Identifier::keyAfterColumnBorder },
289 { "column-number", Identifier::keyColumnNumber },
290 { "row-number", Identifier::keyRowNumber },
291 { "n-columns-spanned", Identifier::keyNColumnsSpanned },
292 { "n-rows-spanned", Identifier::keyNRowsSpanned },
293 { "width", Identifier::keyWidth },
294 { "starts-row?", Identifier::keyIsStartsRow },
295 { "ends-row?", Identifier::keyIsEndsRow },
296 { "table-width", Identifier::keyTableWidth },
297 { "multi-modes", Identifier::keyMultiModes },
298 { "data", Identifier::keyData },
299 { "min", Identifier::keyMin },
300 { "max", Identifier::keyMax },
301 { "conditional?", Identifier::keyIsConditional },
302 { "priority", Identifier::keyPriority },
303 { "grid-n-rows", Identifier::keyGridNRows },
304 { "grid-n-columns", Identifier::keyGridNColumns },
305 { "radical", Identifier::keyRadical },
306 { "null", Identifier::keyNull },
307 { "rcs?", Identifier::keyIsRcs },
308 { "parent", Identifier::keyParent },
309 { "active", Identifier::keyActive },
310 { "attributes", Identifier::keyAttributes },
311 { "children", Identifier::keyChildren },
312 { "repeat", Identifier::keyRepeat },
313 { "position", Identifier::keyPosition },
314 { "only", Identifier::keyOnly },
315 { "class", Identifier::keyClass },
316 { "importance", Identifier::keyImportance },
317 { "position-preference", Identifier::keyPositionPreference },
318 { "architecture", Identifier::keyArchitecture },
319 }, keys2[] = {
320 { "declare-class-attribute", Identifier::keyDeclareClassAttribute },
321 { "declare-id-attribute", Identifier::keyDeclareIdAttribute },
322 { "declare-flow-object-macro", Identifier::keyDeclareFlowObjectMacro },
323 { "or-element", Identifier::keyOrElement },
324 { "set!", Identifier::keySet },
325 { "begin", Identifier::keyBegin },
326 };
327 for (size_t i = 0; i < SIZEOF(keys); i++) {
328 StringC tem(makeStringC(keys[i].name));
329 lookup(tem)->setSyntacticKey(keys[i].key);
330 if (dsssl2() && tem[tem.size() - 1] == '?') {
331 tem.resize(tem.size() - 1);
332 lookup(tem)->setSyntacticKey(keys[i].key);
333 }
334 }
335 if (dsssl2()) {
336 for (size_t i = 0; i < SIZEOF(keys2); i++)
337 lookup(makeStringC(keys2[i].name))->setSyntacticKey(keys2[i].key);
338 }
339 }
340
installCValueSymbols()341 void Interpreter::installCValueSymbols()
342 {
343 cValueSymbols_[0] = makeFalse();
344 cValueSymbols_[1] = makeTrue();
345 for (size_t i = 2; i < FOTBuilder::nSymbols; i++) {
346 SymbolObj *sym = makeSymbol(makeStringC(FOTBuilder::symbolName(FOTBuilder::Symbol(i))));
347 sym->setCValue(FOTBuilder::Symbol(i));
348 cValueSymbols_[i] = sym;
349 }
350 }
351
installPortNames()352 void Interpreter::installPortNames()
353 {
354 // These must match the order in SymbolObj.
355 static const char *names[] = {
356 "numerator",
357 "denominator",
358 "pre-sup",
359 "pre-sub",
360 "post-sup",
361 "post-sub",
362 "mid-sup",
363 "mid-sub",
364 "over-mark",
365 "under-mark",
366 "open",
367 "close",
368 "degree",
369 "operator",
370 "lower-limit",
371 "upper-limit",
372 "header",
373 "footer"
374 };
375 ASSERT(SIZEOF(names) == nPortNames);
376 for (size_t i = 0; i < SIZEOF(names); i++)
377 portNames_[i] = makeSymbol(makeStringC(names[i]));
378 }
379
installCharNames()380 void Interpreter::installCharNames()
381 {
382 static struct {
383 Char c;
384 const char *name;
385 } chars[] = {
386 #include "charNames.h"
387 };
388 for (size_t i = 0; i < SIZEOF(chars); i++)
389 namedCharTable_.insert(makeStringC(chars[i].name), chars[i].c);
390 }
391
installSdata()392 void Interpreter::installSdata()
393 {
394 // This comes from uni2sgml.txt on ftp://unicode.org.
395 // It is marked there as obsolete, so it probably ought to be checked.
396 // The definitions of apos and quot have been fixed for consistency with XML.
397 static struct {
398 Char c;
399 const char *name;
400 } entities[] = {
401 #include "sdata.h"
402 };
403 for (size_t i = 0; i < SIZEOF(entities); i++)
404 sdataEntityNameTable_.insert(makeStringC(entities[i].name), entities[i].c);
405 }
406
installNodeProperties()407 void Interpreter::installNodeProperties()
408 {
409 for (int i = 0; i < ComponentName::nIds; i++) {
410 ComponentName::Id id = ComponentName::Id(i);
411 nodePropertyTable_.insert(makeStringC(ComponentName::rcsName(id)), i);
412 nodePropertyTable_.insert(makeStringC(ComponentName::sdqlName(id)), i);
413 }
414 }
415
sdataMap(GroveString name,GroveString,GroveChar & c) const416 bool Interpreter::sdataMap(GroveString name, GroveString, GroveChar &c) const
417 {
418 StringC tem(name.data(), name.size());
419 const Char *cp = sdataEntityNameTable_.lookup(tem);
420 if (cp) {
421 c = *cp;
422 return 1;
423 }
424 if (convertUnicodeCharName(tem, c))
425 return 1;
426 // I think this is the most thing to do.
427 // At least it makes preserve-sdata work with unknown SDATA entities.
428 c = defaultChar;
429 return 1;
430 }
431
convertGlyphId(const Char * str,size_t len,const Location & loc)432 ELObj *Interpreter::convertGlyphId(const Char *str, size_t len, const Location &loc)
433 {
434 unsigned long n = 0;
435 const char *publicId = 0;
436 for (size_t i = len; i > 1; --i) {
437 if (str[i - 1] == ':' && str[i - 2] == ':' && i < len && str[i] != '0') {
438 for (size_t j = i; j < len; j++)
439 n = n*10 + (str[j] - '0');
440 publicId = storePublicId(str, i - 2, loc);
441 break;
442 }
443 if (str[i - 1] < '0' || str[i - 1] > '9')
444 break;
445 }
446 if (!publicId)
447 publicId = storePublicId(str, len, loc);
448 return new (*this) GlyphIdObj(FOTBuilder::GlyphId(publicId, n));
449 }
450
convertCharName(const StringC & str,Char & c) const451 bool Interpreter::convertCharName(const StringC &str, Char &c) const
452 {
453 const Char *cp = namedCharTable_.lookup(str);
454 if (cp) {
455 c = *cp;
456 return 1;
457 }
458 return convertUnicodeCharName(str, c);
459 }
460
convertUnicodeCharName(const StringC & str,Char & c)461 bool Interpreter::convertUnicodeCharName(const StringC &str, Char &c)
462 {
463 if (str.size() != 6 || str[0] != 'U' || str[1] != '-')
464 return 0;
465 Char value = 0;
466 for (int i = 2; i < 6; i++) {
467 value <<= 4;
468 switch (str[i]) {
469 case '0':
470 case '1':
471 case '2':
472 case '3':
473 case '4':
474 case '5':
475 case '6':
476 case '7':
477 case '8':
478 case '9':
479 value |= str[i] - '0';
480 break;
481 case 'A':
482 case 'B':
483 case 'C':
484 case 'D':
485 case 'E':
486 case 'F':
487 value |= 10 + (str[i] - 'A');
488 break;
489 default:
490 return 0;
491 }
492 }
493 c = value;
494 return 1;
495 }
496
makeSymbol(const StringC & str)497 SymbolObj *Interpreter::makeSymbol(const StringC &str)
498 {
499 SymbolObj *sym = symbolTable_.lookup(str);
500 if (!sym) {
501 StringObj *strObj = new (*this) StringObj(str);
502 makePermanent(strObj);
503 sym = new (*this) SymbolObj(strObj);
504 makePermanent(sym);
505 symbolTable_.insert(sym);
506 }
507 return sym;
508 }
509
lookup(const StringC & str)510 Identifier *Interpreter::lookup(const StringC &str)
511 {
512 Identifier *ident = identTable_.lookup(str);
513 if (!ident) {
514 ident = new Identifier(str);
515 identTable_.insert(ident);
516 }
517 return ident;
518 }
519
lookupNodeProperty(const StringC & str,ComponentName::Id & id)520 bool Interpreter::lookupNodeProperty(const StringC &str, ComponentName::Id &id)
521 {
522 const int *val = nodePropertyTable_.lookup(str);
523 if (!val) {
524 StringC tem(str);
525 for (size_t i = 0; i < tem.size(); i++) {
526 if (tem[i] >= 'A' && tem[i] <= 'Z')
527 tem[i] = 'a' + (tem[i] - 'A');
528 }
529 val = nodePropertyTable_.lookup(tem);
530 if (!val)
531 return 0;
532 }
533 id = ComponentName::Id(*val);
534 return 1;
535 }
536
lookupUnit(const StringC & str)537 Unit *Interpreter::lookupUnit(const StringC &str)
538 {
539 Unit *unit = unitTable_.lookup(str);
540 if (!unit) {
541 unit = new Unit(str);
542 unitTable_.insert(unit);
543 }
544 return unit;
545 }
546
lookupProcessingMode(const StringC & str)547 ProcessingMode *Interpreter::lookupProcessingMode(const StringC &str)
548 {
549 ProcessingMode *mode = processingModeTable_.lookup(str);
550 if (!mode) {
551 mode = new ProcessingMode(str, &initialProcessingMode_);
552 processingModeTable_.insert(mode);
553 }
554 return mode;
555 }
556
makeStringC(const char * s)557 StringC Interpreter::makeStringC(const char *s)
558 {
559 StringC tem;
560 if (s)
561 while (*s)
562 tem += (unsigned char)*s++;
563 return tem;
564 }
565
endPart()566 void Interpreter::endPart()
567 {
568 currentPartFirstInitialValue_ = initialValueNames_.size();
569 partIndex_++;
570 }
571
normalizeGeneralName(const NodePtr & nd,StringC & str)572 void Interpreter::normalizeGeneralName(const NodePtr &nd, StringC &str)
573 {
574 NamedNodeListPtr nnl;
575 NodePtr root;
576 if (nd->getGroveRoot(root) == accessOK
577 && root->getElements(nnl) == accessOK)
578 str.resize(nnl->normalize(str.begin(), str.size()));
579 }
580
makeLengthSpec(const FOTBuilder::LengthSpec & ls)581 ELObj *Interpreter::makeLengthSpec(const FOTBuilder::LengthSpec &ls)
582 {
583 if (ls.displaySizeFactor != 0.0) {
584 LengthSpec result(LengthSpec::displaySize, ls.displaySizeFactor);
585 result += double(ls.length);
586 return new (*this) LengthSpecObj(result);
587 }
588 else
589 return new (*this) LengthObj(ls.length);
590 }
591
convertBooleanC(ELObj * obj,const Identifier * ident,const Location & loc,bool & result)592 bool Interpreter::convertBooleanC(ELObj *obj, const Identifier *ident, const Location &loc,
593 bool &result)
594 {
595 obj = convertFromString(obj, convertAllowBoolean, loc);
596 if (obj == makeFalse()) {
597 result = 0;
598 return 1;
599 }
600 if (obj == makeTrue()) {
601 result = 1;
602 return 1;
603 }
604 invalidCharacteristicValue(ident, loc);
605 return 0;
606 }
607
convertPublicIdC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::PublicId & pubid)608 bool Interpreter::convertPublicIdC(ELObj *obj, const Identifier *ident,
609 const Location &loc,
610 FOTBuilder::PublicId &pubid)
611 {
612 if (obj == makeFalse()) {
613 pubid = 0;
614 return 1;
615 }
616 const Char *s;
617 size_t n;
618 if (obj->stringData(s, n)) {
619 if (n == 0)
620 pubid = 0;
621 else
622 pubid = storePublicId(s, n, loc);
623 return 1;
624 }
625 invalidCharacteristicValue(ident, loc);
626 return 0;
627 }
628
storePublicId(const Char * s,size_t n,const Location & loc)629 const char *Interpreter::storePublicId(const Char *s, size_t n, const Location &loc)
630 {
631 String<char> buf;
632 for (; n > 0; s++, n--) {
633 if (*s >= 128) {
634 setNextLocation(loc);
635 message(InterpreterMessages::invalidPublicIdChar,
636 StringMessageArg(StringC(s, 1)));
637 }
638 else
639 buf += char(*s);
640 }
641 buf += '\0';
642 return publicIds_.store(buf);
643 }
644
convertStringC(ELObj * obj,const Identifier * ident,const Location & loc,StringC & result)645 bool Interpreter::convertStringC(ELObj *obj, const Identifier *ident, const Location &loc,
646 StringC &result)
647 {
648 const Char *s;
649 size_t n;
650 if (obj->stringData(s, n)) {
651 result.assign(s, n);
652 return 1;
653 }
654 invalidCharacteristicValue(ident, loc);
655 return 0;
656 }
657
convertLengthSpec(ELObj * obj,FOTBuilder::LengthSpec & result)658 bool Interpreter::convertLengthSpec(ELObj *obj,
659 FOTBuilder::LengthSpec &result)
660 {
661 int dim;
662 double d;
663 switch (obj->quantityValue(result.length, d, dim)) {
664 case ELObj::longQuantity:
665 if (dim == 1)
666 return 1;
667 break;
668 case ELObj::doubleQuantity:
669 if (dim == 1) {
670 // FIXME catch overflow
671 result.length = d < 0.0 ? long(d - .5) : long(d + .5);
672 return 1;
673 }
674 break;
675 default:
676 {
677 const LengthSpec *ls = obj->lengthSpec();
678 if (ls)
679 return ls->convert(result);
680 }
681 break;
682 }
683 return 0;
684 }
685
convertLengthC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::Length & n)686 bool Interpreter::convertLengthC(ELObj *obj, const Identifier *ident,
687 const Location &loc,
688 FOTBuilder::Length &n)
689 {
690 obj = convertFromString(obj, convertAllowNumber, loc);
691 int dim;
692 double d;
693 switch (obj->quantityValue(n, d, dim)) {
694 case ELObj::longQuantity:
695 if (dim == 1)
696 return 1;
697 break;
698 case ELObj::doubleQuantity:
699 if (dim == 1) {
700 // FIXME catch overflow
701 n = long(d);
702 return 1;
703 }
704 break;
705 default:
706 break;
707 }
708 invalidCharacteristicValue(ident, loc);
709 return 0;
710 }
711
convertLengthSpecC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::LengthSpec & result)712 bool Interpreter::convertLengthSpecC(ELObj *obj, const Identifier *ident,
713 const Location &loc,
714 FOTBuilder::LengthSpec &result)
715 {
716 obj = convertFromString(obj, convertAllowNumber, loc);
717 if (convertLengthSpec(obj, result))
718 return 1;
719 invalidCharacteristicValue(ident, loc);
720 return 0;
721 }
722
convertOptLengthSpecC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::OptLengthSpec & result)723 bool Interpreter::convertOptLengthSpecC(ELObj *obj, const Identifier *ident,
724 const Location &loc,
725 FOTBuilder::OptLengthSpec &result)
726 {
727 obj = convertFromString(obj, convertAllowBoolean|convertAllowNumber, loc);
728 if (obj == makeFalse()) {
729 result.hasLength = 0;
730 return 1;
731 }
732 if (convertLengthSpecC(obj, ident, loc, result.length)) {
733 result.hasLength = 1;
734 return 1;
735 }
736 return 0;
737 }
738
convertOptPositiveIntegerC(ELObj * obj,const Identifier * ident,const Location & loc,long & result)739 bool Interpreter::convertOptPositiveIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
740 long &result)
741 {
742 obj = convertFromString(obj, convertAllowNumber|convertAllowBoolean, loc);
743 if (obj == makeFalse()) {
744 result = 0;
745 return 1;
746 }
747 if (obj->exactIntegerValue(result) && result > 0)
748 return 1;
749 // FIXME allow inexact value
750 invalidCharacteristicValue(ident, loc);
751 return 0;
752 }
753
convertIntegerC(ELObj * obj,const Identifier * ident,const Location & loc,long & result)754 bool Interpreter::convertIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
755 long &result)
756 {
757 obj = convertFromString(obj, convertAllowNumber, loc);
758 if (obj->exactIntegerValue(result))
759 return 1;
760 // FIXME allow inexact value
761 invalidCharacteristicValue(ident, loc);
762 return 0;
763 }
764
765
convertLetter2C(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::Letter2 & code)766 bool Interpreter::convertLetter2C(ELObj *obj, const Identifier *ident, const Location &loc,
767 FOTBuilder::Letter2 &code)
768 {
769 StringObj *strObj = obj->convertToString();
770 if (strObj) {
771 const StringC &str = *strObj;
772 if (str.size() == 2
773 && str[0] >= 'A' && str[0] <= 'Z'
774 && str[1] >= 'A' && str[1] <= 'Z') {
775 code = SP_LETTER2(str[0], str[1]);
776 return 1;
777 }
778 if (str.size() == 0) {
779 code = 0;
780 return 1;
781 }
782 }
783 else if (obj == makeFalse()) {
784 code = 0;
785 return 1;
786 }
787 invalidCharacteristicValue(ident, loc);
788 return 0;
789 }
790
convertCharC(ELObj * obj,const Identifier * ident,const Location & loc,Char & result)791 bool Interpreter::convertCharC(ELObj *obj, const Identifier *ident, const Location &loc,
792 Char &result)
793 {
794 if (obj->charValue(result))
795 return 1;
796 const Char *s;
797 size_t n;
798 if (obj->stringData(s, n) && n == 1) {
799 result = s[0];
800 return 1;
801 }
802 invalidCharacteristicValue(ident, loc);
803 return 0;
804 }
805
convertColorC(ELObj * obj,const Identifier * ident,const Location & loc,ColorObj * & color)806 bool Interpreter::convertColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
807 {
808 color = obj->asColor();
809 if (color)
810 return 1;
811 invalidCharacteristicValue(ident, loc);
812 return 0;
813 }
814
convertOptColorC(ELObj * obj,const Identifier * ident,const Location & loc,ColorObj * & color)815 bool Interpreter::convertOptColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
816 {
817 color = obj->asColor();
818 if (color)
819 return 1;
820 if (obj == makeFalse())
821 return 1;
822 invalidCharacteristicValue(ident, loc);
823 return 0;
824 }
825
convertRealC(ELObj * obj,const Identifier * ident,const Location & loc,double & result)826 bool Interpreter::convertRealC(ELObj *obj, const Identifier *ident, const Location &loc,
827 double &result)
828 {
829 obj = convertFromString(obj, convertAllowNumber, loc);
830 if (obj->realValue(result))
831 return 1;
832 invalidCharacteristicValue(ident, loc);
833 return 0;
834 }
835
convertEnumC(ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::Symbol & sym)836 bool Interpreter::convertEnumC(ELObj *obj, const Identifier *ident, const Location &loc,
837 FOTBuilder::Symbol &sym)
838 {
839 obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
840 if (obj == makeFalse()) {
841 sym = FOTBuilder::symbolFalse;
842 return 1;
843 }
844 SymbolObj *symObj = obj->asSymbol();
845 if (symObj) {
846 sym = symObj->cValue();
847 if (sym != FOTBuilder::symbolFalse)
848 return 1;
849 }
850 if (obj == makeTrue()) {
851 sym = FOTBuilder::symbolTrue;
852 return 1;
853 }
854 invalidCharacteristicValue(ident, loc);
855 return 0;
856 }
857
convertEnumC(const FOTBuilder::Symbol * syms,size_t nSyms,ELObj * obj,const Identifier * ident,const Location & loc,FOTBuilder::Symbol & result)858 bool Interpreter::convertEnumC(const FOTBuilder::Symbol *syms, size_t nSyms,
859 ELObj *obj, const Identifier *ident, const Location &loc,
860 FOTBuilder::Symbol &result)
861 {
862 obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
863 SymbolObj *symObj = obj->asSymbol();
864 FOTBuilder::Symbol val;
865 if (symObj) {
866 val = symObj->cValue();
867 if (val == FOTBuilder::symbolFalse) {
868 invalidCharacteristicValue(ident, loc);
869 return 0;
870 }
871 }
872 else if (obj == makeFalse())
873 val = FOTBuilder::symbolFalse;
874 else if (obj == makeTrue())
875 val = FOTBuilder::symbolTrue;
876 else {
877 invalidCharacteristicValue(ident, loc);
878 return 0;
879 }
880 for (size_t i = 0; i < nSyms; i++)
881 if (val == syms[i]) {
882 result = val;
883 return 1;
884 }
885 invalidCharacteristicValue(ident, loc);
886 return 0;
887 }
888
invalidCharacteristicValue(const Identifier * ident,const Location & loc)889 void Interpreter::invalidCharacteristicValue(const Identifier *ident, const Location &loc)
890 {
891 setNextLocation(loc);
892 message(InterpreterMessages::invalidCharacteristicValue,
893 StringMessageArg(ident->name()));
894 }
895
896 static
equal(const Char * s1,const char * s2,size_t n)897 bool equal(const Char *s1, const char *s2, size_t n)
898 {
899 while (n > 0) {
900 if (*s1++ != (unsigned char)*s2++)
901 return 0;
902 --n;
903 }
904 return 1;
905 }
906
convertFromString(ELObj * obj,unsigned hints,const Location & loc)907 ELObj *Interpreter::convertFromString(ELObj *obj, unsigned hints, const Location &loc)
908 {
909 // FIXME fold to lower case
910 const Char *s;
911 size_t n;
912 if (!dsssl2() || !obj->stringData(s, n))
913 return obj;
914 if (hints & convertAllowNumber) {
915 ELObj *tem = convertNumber(StringC(s, n));
916 if (tem)
917 return tem->resolveQuantities(1, *this, loc);
918 }
919 if (hints & convertAllowSymbol) {
920 StringC tem(s, n);
921 SymbolObj *sym = symbolTable_.lookup(tem);
922 if (sym && sym->cValue() != FOTBuilder::symbolFalse)
923 return sym;
924 }
925 if (hints & convertAllowBoolean) {
926 switch (n) {
927 case 2:
928 if (equal(s, "no", n))
929 return makeFalse();
930 break;
931 case 3:
932 if (equal(s, "yes", n))
933 return makeTrue();
934 break;
935 case 4:
936 if (equal(s, "true", n))
937 return makeTrue();
938 break;
939 case 5:
940 if (equal(s, "false", n))
941 return makeFalse();
942 break;
943 }
944 }
945 return obj;
946 }
947
convertNumber(const StringC & str,int radix)948 ELObj *Interpreter::convertNumber(const StringC &str, int radix)
949 {
950 {
951 if (str.size() == 0)
952 return 0;
953 size_t i = 0;
954 if (str[0] == '#') {
955 if (str.size() < 2)
956 return 0;
957 switch (str[1]) {
958 case 'd':
959 radix = 10;
960 break;
961 case 'x':
962 radix = 16;
963 break;
964 case 'o':
965 radix = 8;
966 break;
967 case 'b':
968 radix = 2;
969 break;
970 default:
971 return 0;
972 }
973 i += 2;
974 }
975 if (i >= str.size())
976 return 0;
977 bool negative;
978 if (str[i] == '-') {
979 negative = 1;
980 i++;
981 }
982 else {
983 negative = 0;
984 if (str[i] == '+')
985 i++;
986 }
987 bool hadDecimalPoint = 0;
988 bool hadDigit = 0;
989 long n = 0;
990 int exp = 0;
991 for (; i < str.size(); i++) {
992 Char c = str[i];
993 int weight;
994 switch (c) {
995 case '0':
996 weight = 0;
997 break;
998 case '1':
999 weight = 1;
1000 break;
1001 case '2':
1002 weight = 2;
1003 break;
1004 case '3':
1005 weight = 3;
1006 break;
1007 case '4':
1008 weight = 4;
1009 break;
1010 case '5':
1011 weight = 5;
1012 break;
1013 case '6':
1014 weight = 6;
1015 break;
1016 case '7':
1017 weight = 7;
1018 break;
1019 case '8':
1020 weight = 8;
1021 break;
1022 case '9':
1023 weight = 9;
1024 break;
1025 case 'a':
1026 weight = 10;
1027 break;
1028 case 'b':
1029 weight = 11;
1030 break;
1031 case 'c':
1032 weight = 12;
1033 break;
1034 case 'd':
1035 weight = 13;
1036 break;
1037 case 'e':
1038 weight = 14;
1039 break;
1040 case 'f':
1041 weight = 15;
1042 break;
1043 default:
1044 weight = -1;
1045 break;
1046 }
1047 if (weight >= 0 && weight < radix) {
1048 hadDigit = 1;
1049 if (negative) {
1050 if (-(unsigned long)n > (-(unsigned long)LONG_MIN - weight)/radix) {
1051 if (radix != 10)
1052 return 0;
1053 return convertNumberFloat(str);
1054 }
1055 else
1056 n = n*radix - weight;
1057 }
1058 else {
1059 if (n > (LONG_MAX - weight)/radix) {
1060 if (radix != 10)
1061 return 0;
1062 return convertNumberFloat(str);
1063 }
1064 else
1065 n = n*radix + weight;
1066 }
1067 if (hadDecimalPoint)
1068 exp--;
1069 }
1070 else if (c == '.' && radix == 10) {
1071 if (hadDecimalPoint)
1072 return 0;
1073 hadDecimalPoint = 1;
1074 }
1075 else
1076 break;
1077 }
1078 if (!hadDigit || (radix != 10 && i < str.size()))
1079 return 0;
1080 if (i + 1 < str.size() && str[i] == 'e'
1081 && lexCategory(str[i + 1]) != lexLetter) {
1082 hadDecimalPoint = 1;
1083 i++;
1084 int e;
1085 if (!scanSignDigits(str, i, e))
1086 return 0;
1087 exp += e;
1088 }
1089 if (i < str.size()) {
1090 int unitExp;
1091 Unit *unit = scanUnit(str, i, unitExp);
1092 if (!unit)
1093 return 0;
1094 if (unitExp == 1)
1095 return new (*this) UnresolvedLengthObj(n, exp, unit);
1096 else
1097 return convertNumberFloat(str);
1098 }
1099 if (hadDecimalPoint)
1100 return convertNumberFloat(str);
1101 return makeInteger(n);
1102 }
1103 }
1104
scanSignDigits(const StringC & str,size_t & i,int & n)1105 bool Interpreter::scanSignDigits(const StringC &str, size_t &i, int &n)
1106 {
1107 bool negative = 0;
1108 if (i < str.size()) {
1109 if (str[i] == '-') {
1110 i++;
1111 negative = 1;
1112 } else if (str[i] == '+')
1113 i++;
1114 }
1115 size_t j = i;
1116 n = 0;
1117 while (i < str.size()
1118 && ('0' <= str[i] && str[i] <= '9')) {
1119 if (negative)
1120 n = n*10 - (str[i] - '0');
1121 else
1122 n = n*10 + (str[i] - '0');
1123 i++;
1124 }
1125 if (i == j)
1126 return 0;
1127 return 1;
1128 }
1129
convertNumberFloat(const StringC & str)1130 ELObj *Interpreter::convertNumberFloat(const StringC &str)
1131 {
1132 String<char> buf;
1133 // omit an optional radix prefix
1134 size_t i0 = 0;
1135 if (str.size() > 1 && str[0] == '#' && str[1] == 'd')
1136 i0 = 2;
1137 for (size_t i = i0; i < str.size(); i++) {
1138 if (str[i] > CHAR_MAX || str[i] == '\0')
1139 return 0;
1140 // 'E' is a valid exponent marker for C but not us
1141 if (str[i] == 'E')
1142 break;
1143 buf += char(str[i]);
1144 }
1145 buf += '\0';
1146 const char *endPtr;
1147 double val = strtod((char *)buf.data(), (char **)&endPtr);
1148 if (endPtr - buf.data() == str.size() - i0)
1149 return new (*this) RealObj(val);
1150 if (endPtr == buf.data())
1151 return 0;
1152 int unitExp;
1153 Unit *unit = scanUnit(str, endPtr - buf.data(), unitExp);
1154 if (!unit)
1155 return 0;
1156 return new (*this) UnresolvedQuantityObj(val, unit, unitExp);
1157 }
1158
1159 // Return 0 for error.
1160
scanUnit(const StringC & str,size_t i,int & unitExp)1161 Unit *Interpreter::scanUnit(const StringC &str, size_t i, int &unitExp)
1162 {
1163 StringC unitName;
1164 while (i < str.size()) {
1165 if (str[i] == '-' || str[i] == '+' || ('0' <= str[i] && str[i] <= '9'))
1166 break;
1167 unitName += str[i++];
1168 }
1169 if (i >= str.size())
1170 unitExp = 1;
1171 else {
1172 unitExp = 0;
1173 bool neg = 0;
1174 if (str[i] == '-' || str[i] == '+') {
1175 if (str[i] == '-')
1176 neg = 1;
1177 i++;
1178 if (i >= str.size())
1179 return 0;
1180 }
1181 while (i < str.size()) {
1182 if (str[i] < '0' || str[i] > '9')
1183 return 0;
1184 unitExp *= 10;
1185 if (neg)
1186 unitExp -= (str[i] - '0');
1187 else
1188 unitExp += (str[i] - '0');
1189 i++;
1190 }
1191 }
1192 return lookupUnit(unitName);
1193 }
1194
setNodeLocation(const NodePtr & nd)1195 void Interpreter::setNodeLocation(const NodePtr &nd)
1196 {
1197 const LocNode *lnp;
1198 Location nodeLoc;
1199 if ((lnp = LocNode::convert(nd)) != 0
1200 && lnp->getLocation(nodeLoc) == accessOK)
1201 setNextLocation(nodeLoc);
1202 }
1203
convertToPattern(ELObj * obj,const Location & loc,Pattern & pattern)1204 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc, Pattern &pattern)
1205 {
1206 IList<Pattern::Element> list;
1207 if (!convertToPattern(obj, loc, 0, list))
1208 return 0;
1209 Pattern tem(list);
1210 tem.swap(pattern);
1211 return 1;
1212 }
1213
convertToPattern(ELObj * obj,const Location & loc,bool isChild,IList<Pattern::Element> & list)1214 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc,
1215 bool isChild,
1216 IList<Pattern::Element> &list)
1217 {
1218 StringObj *str = obj->convertToString();
1219 if (str) {
1220 const Char *s;
1221 size_t n;
1222 str->stringData(s, n);
1223 if (!n) {
1224 setNextLocation(loc);
1225 message(InterpreterMessages::patternEmptyGi);
1226 return 0;
1227 }
1228 list.insert(new Pattern::Element(StringC(s, n)));
1229 return 1;
1230 }
1231 if (obj == makeTrue()) {
1232 list.insert(new Pattern::Element(StringC()));
1233 return 1;
1234 }
1235 Pattern::Element *curElement = 0;
1236 while (!obj->isNil()) {
1237 PairObj *pair = obj->asPair();
1238 if (!pair) {
1239 setNextLocation(loc);
1240 message(InterpreterMessages::patternNotList);
1241 return 0;
1242 }
1243 ELObj *head = pair->car();
1244 obj = pair->cdr();
1245 if (head == makeTrue() && dsssl2()) {
1246 list.insert(curElement = new Pattern::Element(StringC()));
1247 continue;
1248 }
1249 str = head->convertToString();
1250 if (str) {
1251 const Char *s;
1252 size_t n;
1253 str->stringData(s, n);
1254 if (!n) {
1255 setNextLocation(loc);
1256 message(InterpreterMessages::patternEmptyGi);
1257 return 0;
1258 }
1259 list.insert(curElement = new Pattern::Element(StringC(s, n)));
1260 continue;
1261 }
1262 if (!curElement) {
1263 setNextLocation(loc);
1264 message(InterpreterMessages::patternBadGi,
1265 ELObjMessageArg(head, *this));
1266 return 0;
1267 }
1268 if (head->isNil())
1269 continue; // empty attribute list
1270 if (head->asPair()) {
1271 if (!patternAddAttributeQualifiers(head, loc, *curElement)) {
1272 setNextLocation(loc);
1273 message(InterpreterMessages::patternBadAttributeQualifier);
1274 return 0;
1275 }
1276 continue;
1277 }
1278 KeywordObj *key = dsssl2() ? head->asKeyword() : 0;
1279 if (!key) {
1280 setNextLocation(loc);
1281 message(InterpreterMessages::patternBadMember,
1282 ELObjMessageArg(head, *this));
1283 return 0;
1284 }
1285 pair = obj->asPair();
1286 if (!pair) {
1287 setNextLocation(loc);
1288 message(obj->isNil()
1289 ? InterpreterMessages::patternMissingQualifierValue
1290 : InterpreterMessages::patternNotList);
1291 return 0;
1292 }
1293 ELObj *value = pair->car();
1294 obj = pair->cdr();
1295 Identifier::SyntacticKey k;
1296 if (!key->identifier()->syntacticKey(k)) {
1297 setNextLocation(loc);
1298 message(InterpreterMessages::patternUnknownQualifier,
1299 StringMessageArg(key->identifier()->name()));
1300 return 0;
1301 }
1302 switch (k) {
1303 case Identifier::keyAttributes:
1304 if (!patternAddAttributeQualifiers(value, loc, *curElement)) {
1305 setNextLocation(loc);
1306 message(InterpreterMessages::patternBadAttributeQualifier);
1307 return 0;
1308 }
1309 break;
1310 case Identifier::keyChildren:
1311 {
1312 IList<Pattern::Element> children;
1313 if (!convertToPattern(value, loc, 1, children))
1314 return 0;
1315 if (!children.empty())
1316 curElement->addQualifier(new Pattern::ChildrenQualifier(children));
1317 }
1318 break;
1319 case Identifier::keyRepeat:
1320 {
1321 if (isChild) {
1322 setNextLocation(loc);
1323 message(InterpreterMessages::patternChildRepeat);
1324 return 0;
1325 }
1326 SymbolObj *sym = value->asSymbol();
1327 if (sym) {
1328 const StringC &str = *sym->name();
1329 if (str.size() == 1) {
1330 switch (str[0]) {
1331 case '*':
1332 curElement->setRepeat(0, Pattern::Repeat(-1));
1333 value = 0;
1334 break;
1335 case '?':
1336 curElement->setRepeat(0, 1);
1337 value = 0;
1338 break;
1339 case '+':
1340 curElement->setRepeat(1, Pattern::Repeat(-1));
1341 value = 0;
1342 break;
1343 default:
1344 break;
1345 }
1346 }
1347 }
1348 if (value) {
1349 setNextLocation(loc);
1350 message(InterpreterMessages::patternBadQualifierValue,
1351 ELObjMessageArg(value, *this),
1352 StringMessageArg(key->identifier()->name()));
1353 return 0;
1354 }
1355 }
1356 break;
1357 case Identifier::keyPosition:
1358 {
1359 SymbolObj *sym = value->asSymbol();
1360 if (sym) {
1361 Pattern::Qualifier *qual = 0;
1362 const StringC &str = *sym->name();
1363 if (str == "first-of-type")
1364 qual = new Pattern::FirstOfTypeQualifier;
1365 else if (str == "last-of-type")
1366 qual = new Pattern::LastOfTypeQualifier;
1367 else if (str == "first-of-any")
1368 qual = new Pattern::FirstOfAnyQualifier;
1369 else if (str == "last-of-any")
1370 qual = new Pattern::LastOfAnyQualifier;
1371 if (qual) {
1372 curElement->addQualifier(qual);
1373 break;
1374 }
1375 }
1376 setNextLocation(loc);
1377 message(InterpreterMessages::patternBadQualifierValue,
1378 ELObjMessageArg(value, *this),
1379 StringMessageArg(key->identifier()->name()));
1380 return 0;
1381 }
1382 case Identifier::keyOnly:
1383 {
1384 SymbolObj *sym = value->asSymbol();
1385 if (sym) {
1386 Pattern::Qualifier *qual = 0;
1387 const StringC &str = *sym->name();
1388 if (str == "of-type")
1389 qual = new Pattern::OnlyOfTypeQualifier;
1390 else if (str == "of-any")
1391 qual = new Pattern::OnlyOfAnyQualifier;
1392 if (qual) {
1393 curElement->addQualifier(qual);
1394 break;
1395 }
1396 }
1397 setNextLocation(loc);
1398 message(InterpreterMessages::patternBadQualifierValue,
1399 ELObjMessageArg(value, *this),
1400 StringMessageArg(key->identifier()->name()));
1401 return 0;
1402 }
1403 break;
1404 case Identifier::keyId:
1405 {
1406 StringObj *str = value->convertToString();
1407 if (!str) {
1408 setNextLocation(loc);
1409 message(InterpreterMessages::patternBadQualifierValue,
1410 ELObjMessageArg(value, *this),
1411 StringMessageArg(key->identifier()->name()));
1412 return 0;
1413 }
1414 const Char *s;
1415 size_t n;
1416 str->stringData(s, n);
1417 curElement->addQualifier(new Pattern::IdQualifier(StringC(s, n)));
1418 }
1419 break;
1420 case Identifier::keyClass:
1421 {
1422 StringObj *str = value->convertToString();
1423 if (!str) {
1424 setNextLocation(loc);
1425 message(InterpreterMessages::patternBadQualifierValue,
1426 ELObjMessageArg(value, *this),
1427 StringMessageArg(key->identifier()->name()));
1428 return 0;
1429 }
1430 const Char *s;
1431 size_t n;
1432 str->stringData(s, n);
1433 curElement->addQualifier(new Pattern::ClassQualifier(StringC(s, n)));
1434 }
1435 break;
1436 case Identifier::keyImportance:
1437 {
1438 long n;
1439 if (!value->exactIntegerValue(n)) {
1440 setNextLocation(loc);
1441 message(InterpreterMessages::patternBadQualifierValue,
1442 ELObjMessageArg(value, *this),
1443 StringMessageArg(key->identifier()->name()));
1444 return 0;
1445 }
1446 curElement->addQualifier(new Pattern::ImportanceQualifier(n));
1447 }
1448 break;
1449 case Identifier::keyPriority:
1450 {
1451 long n;
1452 if (!value->exactIntegerValue(n)) {
1453 setNextLocation(loc);
1454 message(InterpreterMessages::patternBadQualifierValue,
1455 ELObjMessageArg(value, *this),
1456 StringMessageArg(key->identifier()->name()));
1457 return 0;
1458 }
1459 curElement->addQualifier(new Pattern::PriorityQualifier(n));
1460 }
1461 break;
1462 default:
1463 setNextLocation(loc);
1464 message(InterpreterMessages::patternUnknownQualifier,
1465 StringMessageArg(key->identifier()->name()));
1466 return 0;
1467 }
1468 }
1469 return 1;
1470 }
1471
patternAddAttributeQualifiers(ELObj * obj,const Location & loc,Pattern::Element & elem)1472 bool Interpreter::patternAddAttributeQualifiers(ELObj *obj,
1473 const Location &loc,
1474 Pattern::Element &elem)
1475 {
1476 while (!obj->isNil()) {
1477 PairObj *pair = obj->asPair();
1478 if (!pair)
1479 return 0;
1480 StringObj *tem = pair->car()->convertToString();
1481 if (!tem)
1482 return 0;
1483 const Char *s;
1484 size_t n;
1485 tem->stringData(s, n);
1486 if (n == 0)
1487 return 0;
1488 StringC name(s, n);
1489 obj = pair->cdr();
1490 pair = obj->asPair();
1491 if (!pair)
1492 return 0;
1493 obj = pair->cdr();
1494 if (pair->car() == makeFalse() && dsssl2())
1495 elem.addQualifier(new Pattern::AttributeMissingValueQualifier(name));
1496 else if (pair->car() == makeTrue() && dsssl2())
1497 elem.addQualifier(new Pattern::AttributeHasValueQualifier(name));
1498 else {
1499 tem = pair->car()->convertToString();
1500 if (!tem)
1501 return 0;
1502 tem->stringData(s, n);
1503 elem.addQualifier(new Pattern::AttributeQualifier(name, StringC(s, n)));
1504 }
1505 }
1506 return 1;
1507 }
1508
dispatchMessage(Message & msg)1509 void Interpreter::dispatchMessage(Message &msg)
1510 {
1511 messenger_->dispatchMessage(msg);
1512 }
1513
dispatchMessage(const Message & msg)1514 void Interpreter::dispatchMessage(const Message &msg)
1515 {
1516 messenger_->dispatchMessage(msg);
1517 }
1518
StringSet()1519 Interpreter::StringSet::StringSet()
1520 {
1521 }
1522
store(String<char> & str)1523 const char *Interpreter::StringSet::store(String<char> &str)
1524 {
1525 str += '\0';
1526 const String<char> *p = table_.lookup(str);
1527 if (!p) {
1528 String<char> *tem = new String<char>;
1529 str.swap(*tem);
1530 table_.insert(tem);
1531 p = tem;
1532 }
1533 return p->data();
1534 }
1535
hash(const String<char> & str)1536 unsigned long Interpreter::StringSet::hash(const String<char> &str)
1537 {
1538 const char *p = str.data();
1539 unsigned long h = 0;
1540 for (size_t n = str.size(); n > 0; n--)
1541 h = (h << 5) + h + (unsigned char)*p++; // from Chris Torek
1542 return h;
1543 }
1544
Identifier(const StringC & name)1545 Identifier::Identifier(const StringC &name)
1546 : Named(name), value_(0), syntacticKey_(notKey), beingComputed_(0), flowObj_(0)
1547 {
1548 }
1549
setDefinition(Owner<Expression> & expr,unsigned part,const Location & loc)1550 void Identifier::setDefinition(Owner<Expression> &expr,
1551 unsigned part,
1552 const Location &loc)
1553 {
1554 def_.swap(expr);
1555 defPart_ = part;
1556 defLoc_ = loc;
1557 value_ = 0;
1558 }
1559
setValue(ELObj * value,unsigned partIndex)1560 void Identifier::setValue(ELObj *value, unsigned partIndex)
1561 {
1562 value_ = value;
1563 // Built in functions have lowest priority.
1564 defPart_ = partIndex;
1565 }
1566
defined(unsigned & part,Location & loc) const1567 bool Identifier::defined(unsigned &part, Location &loc) const
1568 {
1569 if (!def_ && !value_)
1570 return 0;
1571 part = defPart_;
1572 loc = defLoc_;
1573 return 1;
1574 }
1575
computeValue(bool force,Interpreter & interp) const1576 ELObj *Identifier::computeValue(bool force, Interpreter &interp) const
1577 {
1578 if (value_)
1579 return value_;
1580 ASSERT(def_);
1581 if (beingComputed_) {
1582 if (force) {
1583 interp.setNextLocation(defLoc_);
1584 interp.message(InterpreterMessages::identifierLoop,
1585 StringMessageArg(name()));
1586 ((Identifier *)this)->value_ = interp.makeError();
1587 }
1588 }
1589 else {
1590 ((Identifier *)this)->beingComputed_ = 1;
1591 if (insn_.isNull())
1592 ((Identifier *)this)->insn_
1593 = Expression::optimizeCompile(((Identifier *)this)->def_, interp,
1594 Environment(), 0, InsnPtr());
1595 if (force || def_->canEval(0)) {
1596 VM vm(interp);
1597 ELObj *v = vm.eval(insn_.pointer());
1598 interp.makePermanent(v);
1599 ((Identifier *)this)->value_ = v;
1600 }
1601 ((Identifier *)this)->beingComputed_ = 0;
1602 }
1603 return value_;
1604 }
1605
Unit(const StringC & name)1606 Unit::Unit(const StringC &name)
1607 : Named(name), computed_(notComputed)
1608 {
1609 }
1610
defined(unsigned & part,Location & loc) const1611 bool Unit::defined(unsigned &part, Location &loc) const
1612 {
1613 if (!def_ && computed_ == notComputed)
1614 return 0;
1615 part = defPart_;
1616 loc = defLoc_;
1617 return 1;
1618 }
1619
setDefinition(Owner<Expression> & expr,unsigned part,const Location & loc)1620 void Unit::setDefinition(Owner<Expression> &expr,
1621 unsigned part,
1622 const Location &loc)
1623 {
1624 def_.swap(expr);
1625 defPart_ = part;
1626 defLoc_ = loc;
1627 computed_ = notComputed;
1628 }
1629
setValue(long n)1630 void Unit::setValue(long n)
1631 {
1632 computed_ = computedExact;
1633 exact_ = n;
1634 dim_ = 1;
1635 defPart_ = unsigned(-1);
1636 }
1637
setValue(double n)1638 void Unit::setValue(double n)
1639 {
1640 computed_ = computedInexact;
1641 inexact_ = n;
1642 dim_ = 1;
1643 defPart_ = unsigned(-1);
1644 }
1645
tryCompute(bool force,Interpreter & interp)1646 void Unit::tryCompute(bool force, Interpreter &interp)
1647 {
1648 if (computed_ == notComputed) {
1649 computed_ = beingComputed;
1650 if (insn_.isNull())
1651 insn_ = Expression::optimizeCompile(def_, interp, Environment(), 0, InsnPtr());
1652 if (force || def_->canEval(0)) {
1653 VM vm(interp);
1654 ELObj *v = vm.eval(insn_.pointer());
1655 switch (v->quantityValue(exact_, inexact_, dim_)) {
1656 case ELObj::noQuantity:
1657 if (!interp.isError(v)) {
1658 interp.setNextLocation(defLoc_);
1659 interp.message(InterpreterMessages::badUnitDefinition,
1660 StringMessageArg(name()));
1661 }
1662 computed_ = computedError;
1663 break;
1664 case ELObj::longQuantity:
1665 computed_ = computedExact;
1666 break;
1667 case ELObj::doubleQuantity:
1668 computed_ = computedInexact;
1669 break;
1670 default:
1671 CANNOT_HAPPEN();
1672 }
1673 }
1674 if (computed_ == beingComputed)
1675 computed_ = notComputed;
1676 }
1677 else if (computed_ == beingComputed) {
1678 interp.setNextLocation(defLoc_);
1679 interp.message(InterpreterMessages::unitLoop,
1680 StringMessageArg(name()));
1681 computed_ = computedError;
1682 }
1683 }
1684
1685 // multiply by 10^valExp
1686 // quantity has exponent of 1
1687
resolveQuantity(bool force,Interpreter & interp,long val,int valExp)1688 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1689 long val, int valExp)
1690 {
1691 tryCompute(force, interp);
1692 long result;
1693 if (computed_ == computedExact && scale(val, valExp, exact_, result))
1694 return new (interp) LengthObj(result);
1695 double x = val;
1696 while (valExp > 0) {
1697 x *= 10.0;
1698 valExp--;
1699 }
1700 while (valExp < 0) {
1701 x /= 10.0;
1702 valExp++;
1703 }
1704 return resolveQuantity(force, interp, x, 1);
1705 }
1706
1707 // val * 10^valExp * factor
1708 // return 0 if it can't be done without overflow
1709
scale(long val,int valExp,long factor,long & result)1710 bool Unit::scale(long val, int valExp, long factor, long &result)
1711 {
1712 if (factor <= 0)
1713 return 0; // feeble
1714 while (valExp > 0) {
1715 if (factor > LONG_MAX/10)
1716 return 0;
1717 valExp--;
1718 factor *= 10;
1719 }
1720 if (val >= 0) {
1721 if (val > LONG_MAX/factor)
1722 return 0;
1723 }
1724 else {
1725 if (-(unsigned long)val > -(unsigned long)LONG_MIN/factor)
1726 return 0;
1727 }
1728 result = val*factor;
1729 while (valExp < 0) {
1730 result /= 10;
1731 valExp++;
1732 }
1733 return 1;
1734 }
1735
resolveQuantity(bool force,Interpreter & interp,double val,int unitExp)1736 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1737 double val, int unitExp)
1738 {
1739 tryCompute(force, interp);
1740 double factor;
1741 switch (computed_) {
1742 case computedExact:
1743 factor = exact_;
1744 break;
1745 case computedInexact:
1746 factor = inexact_;
1747 break;
1748 case computedError:
1749 return interp.makeError();
1750 default:
1751 return 0;
1752 }
1753 int resultDim = 0;
1754 double resultVal = val;
1755 while (unitExp > 0) {
1756 resultDim += dim_;
1757 resultVal *= factor;
1758 unitExp--;
1759 }
1760 while (unitExp < 0) {
1761 resultDim -= dim_;
1762 resultVal /= factor;
1763 unitExp++;
1764 }
1765 if (resultDim == 0)
1766 return new (interp) RealObj(resultVal);
1767 return new (interp) QuantityObj(resultVal, resultDim);
1768 }
1769
trace(Collector & c) const1770 void ELObjDynamicRoot::trace(Collector &c) const
1771 {
1772 c.trace(obj_);
1773 }
1774
operator ==(const StringC & s,const char * p)1775 bool operator==(const StringC &s, const char *p)
1776 {
1777 for (size_t i = 0; i < s.size(); i++)
1778 if (p[i] == '\0' || (unsigned char)p[i] != s[i])
1779 return 0;
1780 return p[s.size()] == '\0';
1781 }
1782
1783 #ifdef DSSSL_NAMESPACE
1784 }
1785 #endif
1786