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"
CheckSosofoInsn(const Location & loc,InsnPtr next)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 { "height", Identifier::keyHeight },
372 { "contents-rotation", Identifier::keyContentsRotation },
373 { "open", Identifier::keyOpen },
374 { "close", Identifier::keyClose },
375 { "mark", Identifier::keyMark },
376 { "direction", Identifier::keyDirection },
377 }, keys2[] = {
378 { "declare-class-attribute", Identifier::keyDeclareClassAttribute },
379 { "declare-id-attribute", Identifier::keyDeclareIdAttribute },
380 { "declare-flow-object-macro", Identifier::keyDeclareFlowObjectMacro },
381 { "or-element", Identifier::keyOrElement },
382 { "set!", Identifier::keySet },
383 { "begin", Identifier::keyBegin },
384 };
385 for (size_t i = 0; i < SIZEOF(keys); i++) {
386 StringC tem(makeStringC(keys[i].name));
387 lookup(tem)->setSyntacticKey(keys[i].key);
388 if (dsssl2() && tem[tem.size() - 1] == '?') {
389 tem.resize(tem.size() - 1);
390 lookup(tem)->setSyntacticKey(keys[i].key);
391 }
392 }
393 if (dsssl2()) {
394 for (size_t i = 0; i < SIZEOF(keys2); i++)
395 lookup(makeStringC(keys2[i].name))->setSyntacticKey(keys2[i].key);
396 }
397 }
398
399 void Interpreter::installCValueSymbols()
400 {
401 cValueSymbols_[0] = makeFalse();
402 cValueSymbols_[1] = makeTrue();
403 for (size_t i = 2; i < FOTBuilder::nSymbols; i++) {
404 SymbolObj *sym = makeSymbol(makeStringC(FOTBuilder::symbolName(FOTBuilder::Symbol(i))));
405 sym->setCValue(FOTBuilder::Symbol(i));
406 cValueSymbols_[i] = sym;
407 }
408 }
409
410 void Interpreter::installPortNames()
411 {
412 // These must match the order in SymbolObj.
413 static const char *names[] = {
414 "numerator",
415 "denominator",
416 "pre-sup",
417 "pre-sub",
418 "post-sup",
419 "post-sub",
420 "mid-sup",
421 "mid-sub",
422 "over-mark",
423 "under-mark",
424 "open",
425 "close",
426 "degree",
427 "operator",
428 "lower-limit",
429 "upper-limit",
430 "header",
431 "footer"
432 };
433 ASSERT(SIZEOF(names) == nPortNames);
434 for (size_t i = 0; i < SIZEOF(names); i++)
435 portNames_[i] = makeSymbol(makeStringC(names[i]));
436 }
437
438 void Interpreter::installCharNames()
439 {
440 static struct {
441 Char c;
442 const char *name;
443 } chars[] = {
444 #include "charNames.h"
445 };
446 for (size_t i = 0; i < SIZEOF(chars); i++) {
447 CharPart ch;
448 ch.c = chars[i].c;
449 ch.defPart = unsigned(-1);
450 namedCharTable_.insert(makeStringC(chars[i].name), ch, 1);
451 }
452 }
453
454 void Interpreter::installSdata()
455 {
456 // This comes from uni2sgml.txt on ftp://unicode.org.
457 // It is marked there as obsolete, so it probably ought to be checked.
458 // The definitions of apos and quot have been fixed for consistency with XML.
459 static struct {
460 Char c;
461 const char *name;
462 } entities[] = {
463 #include "sdata.h"
464 };
465 for (size_t i = 0; i < SIZEOF(entities); i++) {
466 CharPart ch;
467 ch.c = entities[i].c;
468 ch.defPart = unsigned(-1);
469 sdataEntityNameTable_.insert(makeStringC(entities[i].name), ch, 1);
470 }
471 }
472
473 void Interpreter::installNodeProperties()
474 {
475 for (int i = 0; i < ComponentName::nIds; i++) {
476 ComponentName::Id id = ComponentName::Id(i);
477 nodePropertyTable_.insert(makeStringC(ComponentName::rcsName(id)), i);
478 nodePropertyTable_.insert(makeStringC(ComponentName::sdqlName(id)), i);
479 }
480 }
481
482 void Interpreter::setCharRepertoire(const StringC &pubid)
483 {
484 if (pubid == "UNREGISTERED::OpenJade//Character Repertoire::OpenJade") {
485 if (strictMode_) {
486 installCharNames();
487 installSdata();
488 // This assumes that we process char-repertoire
489 // declaration before any declarations which change
490 // lexical categories.
491 for (Char i = 127; i < charMax; i++)
492 lexCategory_.setChar(i, lexAddNameStart);
493 strictMode_ = 0;
494 }
495 } else
496 message(InterpreterMessages::unsupportedCharRepertoire,
497 StringMessageArg(pubid));
498 }
499
500 void Interpreter::addStandardChar(const StringC &name, const StringC &num)
501 {
502 int n;
503 size_t i = 0;
504 if (!scanSignDigits(num, i, n)) {
505 message(InterpreterMessages::invalidCharNumber, StringMessageArg(num));
506 return;
507 }
508
509 const CharPart *def = namedCharTable_.lookup(name);
510 CharPart ch;
511 ch.c = n;
512 ch.defPart = dPartIndex_;
513 if (def) {
514 if (dPartIndex_ < def->defPart)
515 namedCharTable_.insert(name, ch, 1);
516 else if (def->defPart == dPartIndex_ && def->c != ch.c)
517 message(InterpreterMessages::duplicateCharName,
518 StringMessageArg(name));
519 }
520 else
521 namedCharTable_.insert(name, ch, 1);
522 }
523
524 void Interpreter::addNameChar(const StringC &name)
525 {
526 const CharPart *cp = namedCharTable_.lookup(name);
527 if (!cp)
528 message(InterpreterMessages::badCharName,
529 StringMessageArg(name));
530 else if (lexCategory_[cp->c] != lexOther)
531 // FIXME give a more specific error
532 message(InterpreterMessages::badDeclaration);
533 else
534 lexCategory_.setChar(cp->c, lexAddNameStart);
535 }
536
537 void Interpreter::addSeparatorChar(const StringC &name)
538 {
539 const CharPart *cp = namedCharTable_.lookup(name);
540 if (!cp)
541 message(InterpreterMessages::badCharName,
542 StringMessageArg(name));
543 else if (lexCategory_[cp->c] != lexOther)
544 // FIXME give a more specific error
545 message(InterpreterMessages::badDeclaration);
546 else
547 lexCategory_.setChar(cp->c, lexAddWhiteSpace);
548 }
549
550 void Interpreter::addSdataEntity(const StringC &ename, const StringC &etext, const StringC &name)
551 {
552 const CharPart *cp = namedCharTable_.lookup(name);
553 if (!cp) {
554 message(InterpreterMessages::badCharName,
555 StringMessageArg(name));
556 return;
557 }
558
559 CharPart ch;
560 ch.c = cp->c;
561 ch.defPart = dPartIndex_;
562
563 if (ename.size() > 0) {
564 const CharPart *def = sdataEntityNameTable_.lookup(ename);
565 if (def) {
566 if (dPartIndex_ < def->defPart)
567 sdataEntityNameTable_.insert(ename, ch);
568 else if (def->defPart == dPartIndex_ && def->c != cp->c)
569 message(InterpreterMessages::duplicateSdataEntityName,
570 StringMessageArg(ename));
571 }
572 else
573 sdataEntityNameTable_.insert(ename, ch);
574 }
575
576 if (etext.size() > 0) {
577 const CharPart *def = sdataEntityTextTable_.lookup(etext);
578 if (def) {
579 if (dPartIndex_ < def->defPart)
580 sdataEntityTextTable_.insert(etext, ch);
581 else if (def->defPart == dPartIndex_ && def->c != cp->c)
582 message(InterpreterMessages::duplicateSdataEntityText,
583 StringMessageArg(etext));
584 }
585 else
586 sdataEntityTextTable_.insert(etext, ch);
587 }
588 }
589
590 bool Interpreter::sdataMap(GroveString name, GroveString text, GroveChar &c) const
591 {
592 StringC tem(name.data(), name.size());
593 StringC tem2(text.data(), text.size());
594
595 const CharPart *cp = sdataEntityNameTable_.lookup(tem);
596 if (cp) {
597 c = cp->c;
598 return 1;
599 }
600
601 cp = sdataEntityTextTable_.lookup(tem2);
602 if (cp) {
603 c = cp->c;
604 return 1;
605 }
606
607 if (convertUnicodeCharName(tem, c))
608 return 1;
609 // I think this is the best thing to do.
610 // At least it makes preserve-sdata work with unknown SDATA entities.
611 c = defaultChar;
612 return 1;
613 }
614
615 ELObj *Interpreter::convertGlyphId(const Char *str, size_t len, const Location &loc)
616 {
617 unsigned long n = 0;
618 const char *publicId = 0;
619 for (size_t i = len; i > 1; --i) {
620 if (str[i - 1] == ':' && str[i - 2] == ':' && i < len && str[i] != '0') {
621 for (size_t j = i; j < len; j++)
622 n = n*10 + (str[j] - '0');
623 publicId = storePublicId(str, i - 2, loc);
624 break;
625 }
626 if (str[i - 1] < '0' || str[i - 1] > '9')
627 break;
628 }
629 if (!publicId)
630 publicId = storePublicId(str, len, loc);
631 return new (*this) GlyphIdObj(FOTBuilder::GlyphId(publicId, n));
632 }
633
634 bool Interpreter::convertCharName(const StringC &str, Char &c) const
635 {
636 const CharPart *cp = namedCharTable_.lookup(str);
637 if (cp) {
638 c = cp->c;
639 return 1;
640 }
641 return convertUnicodeCharName(str, c);
642 }
643
644 bool Interpreter::convertUnicodeCharName(const StringC &str, Char &c)
645 {
646 if (str.size() != 6 || str[0] != 'U' || str[1] != '-')
647 return 0;
648 Char value = 0;
649 for (int i = 2; i < 6; i++) {
650 value <<= 4;
651 switch (str[i]) {
652 case '0':
653 case '1':
654 case '2':
655 case '3':
656 case '4':
657 case '5':
658 case '6':
659 case '7':
660 case '8':
661 case '9':
662 value |= str[i] - '0';
663 break;
664 case 'A':
665 case 'B':
666 case 'C':
667 case 'D':
668 case 'E':
669 case 'F':
670 value |= 10 + (str[i] - 'A');
671 break;
672 default:
673 return 0;
674 }
675 }
676 c = value;
677 return 1;
678 }
679
680 SymbolObj *Interpreter::makeSymbol(const StringC &str)
681 {
682 SymbolObj *sym = symbolTable_.lookup(str);
683 if (!sym) {
684 StringObj *strObj = new (*this) StringObj(str);
685 makePermanent(strObj);
686 sym = new (*this) SymbolObj(strObj);
687 makePermanent(sym);
688 symbolTable_.insert(sym);
689 }
690 return sym;
691 }
692
693 Identifier *Interpreter::lookup(const StringC &str)
694 {
695 Identifier *ident = identTable_.lookup(str);
696 if (!ident) {
697 ident = new Identifier(str);
698 identTable_.insert(ident);
699 }
700 return ident;
701 }
702
703 bool Interpreter::lookupNodeProperty(const StringC &str, ComponentName::Id &id)
704 {
705 const int *val = nodePropertyTable_.lookup(str);
706 if (!val) {
707 StringC tem(str);
708 for (size_t i = 0; i < tem.size(); i++) {
709 if (tem[i] >= 'A' && tem[i] <= 'Z')
710 tem[i] = 'a' + (tem[i] - 'A');
711 }
712 val = nodePropertyTable_.lookup(tem);
713 if (!val)
714 return 0;
715 }
716 id = ComponentName::Id(*val);
717 return 1;
718 }
719
720 Unit *Interpreter::lookupUnit(const StringC &str)
721 {
722 Unit *unit = unitTable_.lookup(str);
723 if (!unit) {
724 unit = new Unit(str);
725 unitTable_.insert(unit);
726 }
727 return unit;
728 }
729
730 ProcessingMode *Interpreter::lookupProcessingMode(const StringC &str)
731 {
732 ProcessingMode *mode = processingModeTable_.lookup(str);
733 if (!mode) {
734 mode = new ProcessingMode(str, &initialProcessingMode_);
735 processingModeTable_.insert(mode);
736 }
737 return mode;
738 }
739
740 StringC Interpreter::makeStringC(const char *s)
741 {
742 StringC tem;
743 if (s)
744 while (*s)
745 tem += (unsigned char)*s++;
746 return tem;
747 }
748
749 void Interpreter::endPart()
750 {
751 currentPartFirstInitialValue_ = initialValueNames_.size();
752 partIndex_++;
753 }
754
755 void Interpreter::dEndPart()
756 {
757 dPartIndex_++;
758 }
759
760 void Interpreter::normalizeGeneralName(const NodePtr &nd, StringC &str)
761 {
762 NamedNodeListPtr nnl;
763 NodePtr root;
764 if (nd->getGroveRoot(root) == accessOK
765 && root->getElements(nnl) == accessOK)
766 str.resize(nnl->normalize(str.begin(), str.size()));
767 }
768
769 ELObj *Interpreter::makeLengthSpec(const FOTBuilder::LengthSpec &ls)
770 {
771 if (ls.displaySizeFactor != 0.0) {
772 LengthSpec result(LengthSpec::displaySize, ls.displaySizeFactor);
773 result += double(ls.length);
774 return new (*this) LengthSpecObj(result);
775 }
776 else
777 return new (*this) LengthObj(ls.length);
778 }
779
780 bool Interpreter::convertBooleanC(ELObj *obj, const Identifier *ident, const Location &loc,
781 bool &result)
782 {
783 obj = convertFromString(obj, convertAllowBoolean, loc);
784 if (obj == makeFalse()) {
785 result = 0;
786 return 1;
787 }
788 if (obj == makeTrue()) {
789 result = 1;
790 return 1;
791 }
792 invalidCharacteristicValue(ident, loc);
793 return 0;
794 }
795
796 bool Interpreter::convertPublicIdC(ELObj *obj, const Identifier *ident,
797 const Location &loc,
798 FOTBuilder::PublicId &pubid)
799 {
800 if (obj == makeFalse()) {
801 pubid = 0;
802 return 1;
803 }
804 const Char *s;
805 size_t n;
806 if (obj->stringData(s, n)) {
807 if (n == 0)
808 pubid = 0;
809 else
810 pubid = storePublicId(s, n, loc);
811 return 1;
812 }
813 invalidCharacteristicValue(ident, loc);
814 return 0;
815 }
816
817 const char *Interpreter::storePublicId(const Char *s, size_t n, const Location &loc)
818 {
819 String<char> buf;
820 for (; n > 0; s++, n--) {
821 if (*s >= 128) {
822 setNextLocation(loc);
823 message(InterpreterMessages::invalidPublicIdChar,
824 StringMessageArg(StringC(s, 1)));
825 }
826 else
827 buf += char(*s);
828 }
829 buf += '\0';
830 return publicIds_.store(buf);
831 }
832
833 bool Interpreter::convertStringC(ELObj *obj, const Identifier *ident, const Location &loc,
834 StringC &result)
835 {
836 const Char *s;
837 size_t n;
838 if (obj->stringData(s, n)) {
839 result.assign(s, n);
840 return 1;
841 }
842 invalidCharacteristicValue(ident, loc);
843 return 0;
844 }
845
846 bool Interpreter::convertLengthSpec(ELObj *obj,
847 FOTBuilder::LengthSpec &result)
848 {
849 int dim;
850 double d;
851 switch (obj->quantityValue(result.length, d, dim)) {
852 case ELObj::longQuantity:
853 if (dim == 1)
854 return 1;
855 break;
856 case ELObj::doubleQuantity:
857 if (dim == 1) {
858 // FIXME catch overflow
859 result.length = d < 0.0 ? long(d - .5) : long(d + .5);
860 return 1;
861 }
862 break;
863 default:
864 {
865 const LengthSpec *ls = obj->lengthSpec();
866 if (ls)
867 return ls->convert(result);
868 }
869 break;
870 }
871 return 0;
872 }
873
874 bool Interpreter::convertLengthC(ELObj *obj, const Identifier *ident,
875 const Location &loc,
876 FOTBuilder::Length &n)
877 {
878 obj = convertFromString(obj, convertAllowNumber, loc);
879 int dim;
880 double d;
881 switch (obj->quantityValue(n, d, dim)) {
882 case ELObj::longQuantity:
883 if (dim == 1)
884 return 1;
885 break;
886 case ELObj::doubleQuantity:
887 if (dim == 1) {
888 // FIXME catch overflow
889 n = long(d);
890 return 1;
891 }
892 break;
893 default:
894 break;
895 }
896 invalidCharacteristicValue(ident, loc);
897 return 0;
898 }
899
900 bool Interpreter::convertLengthSpecC(ELObj *obj, const Identifier *ident,
901 const Location &loc,
902 FOTBuilder::LengthSpec &result)
903 {
904 obj = convertFromString(obj, convertAllowNumber, loc);
905 if (convertLengthSpec(obj, result))
906 return 1;
907 invalidCharacteristicValue(ident, loc);
908 return 0;
909 }
910
911 bool Interpreter::convertOptLengthSpecC(ELObj *obj, const Identifier *ident,
912 const Location &loc,
913 FOTBuilder::OptLengthSpec &result)
914 {
915 obj = convertFromString(obj, convertAllowBoolean|convertAllowNumber, loc);
916 if (obj == makeFalse()) {
917 result.hasLength = 0;
918 return 1;
919 }
920 if (convertLengthSpecC(obj, ident, loc, result.length)) {
921 result.hasLength = 1;
922 return 1;
923 }
924 return 0;
925 }
926
927 bool Interpreter::convertOptPositiveIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
928 long &result)
929 {
930 obj = convertFromString(obj, convertAllowNumber|convertAllowBoolean, loc);
931 if (obj == makeFalse()) {
932 result = 0;
933 return 1;
934 }
935 if (obj->exactIntegerValue(result) && result > 0)
936 return 1;
937 // FIXME allow inexact value
938 invalidCharacteristicValue(ident, loc);
939 return 0;
940 }
941
942 bool Interpreter::convertIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
943 long &result)
944 {
945 obj = convertFromString(obj, convertAllowNumber, loc);
946 if (obj->exactIntegerValue(result))
947 return 1;
948 // FIXME allow inexact value
949 invalidCharacteristicValue(ident, loc);
950 return 0;
951 }
952
953
954 bool Interpreter::convertLetter2C(ELObj *obj, const Identifier *ident, const Location &loc,
955 FOTBuilder::Letter2 &code)
956 {
957 StringObj *strObj = obj->convertToString();
958 if (strObj) {
959 const StringC &str = *strObj;
960 if (str.size() == 2
961 && str[0] >= 'A' && str[0] <= 'Z'
962 && str[1] >= 'A' && str[1] <= 'Z') {
963 code = SP_LETTER2(str[0], str[1]);
964 return 1;
965 }
966 if (str.size() == 0) {
967 code = 0;
968 return 1;
969 }
970 }
971 else if (obj == makeFalse()) {
972 code = 0;
973 return 1;
974 }
975 invalidCharacteristicValue(ident, loc);
976 return 0;
977 }
978
979 bool Interpreter::convertCharC(ELObj *obj, const Identifier *ident, const Location &loc,
980 Char &result)
981 {
982 if (obj->charValue(result))
983 return 1;
984 const Char *s;
985 size_t n;
986 if (obj->stringData(s, n) && n == 1) {
987 result = s[0];
988 return 1;
989 }
990 invalidCharacteristicValue(ident, loc);
991 return 0;
992 }
993
994 bool Interpreter::convertColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
995 {
996 color = obj->asColor();
997 if (color)
998 return 1;
999 invalidCharacteristicValue(ident, loc);
1000 return 0;
1001 }
1002
1003 bool Interpreter::convertOptColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
1004 {
1005 color = obj->asColor();
1006 if (color)
1007 return 1;
1008 if (obj == makeFalse())
1009 return 1;
1010 invalidCharacteristicValue(ident, loc);
1011 return 0;
1012 }
1013
1014 bool Interpreter::convertRealC(ELObj *obj, const Identifier *ident, const Location &loc,
1015 double &result)
1016 {
1017 obj = convertFromString(obj, convertAllowNumber, loc);
1018 if (obj->realValue(result))
1019 return 1;
1020 invalidCharacteristicValue(ident, loc);
1021 return 0;
1022 }
1023
1024 bool Interpreter::convertEnumC(ELObj *obj, const Identifier *ident, const Location &loc,
1025 FOTBuilder::Symbol &sym)
1026 {
1027 obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
1028 if (obj == makeFalse()) {
1029 sym = FOTBuilder::symbolFalse;
1030 return 1;
1031 }
1032 SymbolObj *symObj = obj->asSymbol();
1033 if (symObj) {
1034 sym = symObj->cValue();
1035 if (sym != FOTBuilder::symbolFalse)
1036 return 1;
1037 }
1038 if (obj == makeTrue()) {
1039 sym = FOTBuilder::symbolTrue;
1040 return 1;
1041 }
1042 invalidCharacteristicValue(ident, loc);
1043 return 0;
1044 }
1045
1046 bool Interpreter::convertEnumC(const FOTBuilder::Symbol *syms, size_t nSyms,
1047 ELObj *obj, const Identifier *ident, const Location &loc,
1048 FOTBuilder::Symbol &result)
1049 {
1050 obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
1051 SymbolObj *symObj = obj->asSymbol();
1052 FOTBuilder::Symbol val;
1053 if (symObj) {
1054 val = symObj->cValue();
1055 if (val == FOTBuilder::symbolFalse) {
1056 invalidCharacteristicValue(ident, loc);
1057 return 0;
1058 }
1059 }
1060 else if (obj == makeFalse())
1061 val = FOTBuilder::symbolFalse;
1062 else if (obj == makeTrue())
1063 val = FOTBuilder::symbolTrue;
1064 else {
1065 invalidCharacteristicValue(ident, loc);
1066 return 0;
1067 }
1068 for (size_t i = 0; i < nSyms; i++)
1069 if (val == syms[i]) {
1070 result = val;
1071 return 1;
1072 }
1073 invalidCharacteristicValue(ident, loc);
1074 return 0;
1075 }
1076
1077 void Interpreter::invalidCharacteristicValue(const Identifier *ident, const Location &loc)
1078 {
1079 setNextLocation(loc);
1080 message(InterpreterMessages::invalidCharacteristicValue,
1081 StringMessageArg(ident->name()));
1082 }
1083
1084 static
1085 bool equal(const Char *s1, const char *s2, size_t n)
1086 {
1087 while (n > 0) {
1088 if (*s1++ != (unsigned char)*s2++)
1089 return 0;
1090 --n;
1091 }
1092 return 1;
1093 }
1094
1095 ELObj *Interpreter::convertFromString(ELObj *obj, unsigned hints, const Location &loc)
1096 {
1097 // FIXME fold to lower case
1098 const Char *s;
1099 size_t n;
1100 if (!dsssl2() || !obj->stringData(s, n))
1101 return obj;
1102 if (hints & convertAllowNumber) {
1103 ELObj *tem = convertNumber(StringC(s, n));
1104 if (tem)
1105 return tem->resolveQuantities(1, *this, loc);
1106 }
1107 if (hints & convertAllowSymbol) {
1108 StringC tem(s, n);
1109 SymbolObj *sym = symbolTable_.lookup(tem);
1110 if (sym && sym->cValue() != FOTBuilder::symbolFalse)
1111 return sym;
1112 }
1113 if (hints & convertAllowBoolean) {
1114 switch (n) {
1115 case 2:
1116 if (equal(s, "no", n))
1117 return makeFalse();
1118 break;
1119 case 3:
1120 if (equal(s, "yes", n))
1121 return makeTrue();
1122 break;
1123 case 4:
1124 if (equal(s, "true", n))
1125 return makeTrue();
1126 break;
1127 case 5:
1128 if (equal(s, "false", n))
1129 return makeFalse();
1130 break;
1131 }
1132 }
1133 return obj;
1134 }
1135
1136 ELObj *Interpreter::convertNumber(const StringC &str, int radix)
1137 {
1138 {
1139 if (str.size() == 0)
1140 return 0;
1141 size_t i = 0;
1142 if (str[0] == '#') {
1143 if (str.size() < 2)
1144 return 0;
1145 switch (str[1]) {
1146 case 'd':
1147 radix = 10;
1148 break;
1149 case 'x':
1150 radix = 16;
1151 break;
1152 case 'o':
1153 radix = 8;
1154 break;
1155 case 'b':
1156 radix = 2;
1157 break;
1158 default:
1159 return 0;
1160 }
1161 i += 2;
1162 }
1163 if (i >= str.size())
1164 return 0;
1165 bool negative;
1166 if (str[i] == '-') {
1167 negative = 1;
1168 i++;
1169 }
1170 else {
1171 negative = 0;
1172 if (str[i] == '+')
1173 i++;
1174 }
1175 bool hadDecimalPoint = 0;
1176 bool hadDigit = 0;
1177 long n = 0;
1178 int exp = 0;
1179 for (; i < str.size(); i++) {
1180 Char c = str[i];
1181 int weight;
1182 switch (c) {
1183 case '0':
1184 weight = 0;
1185 break;
1186 case '1':
1187 weight = 1;
1188 break;
1189 case '2':
1190 weight = 2;
1191 break;
1192 case '3':
1193 weight = 3;
1194 break;
1195 case '4':
1196 weight = 4;
1197 break;
1198 case '5':
1199 weight = 5;
1200 break;
1201 case '6':
1202 weight = 6;
1203 break;
1204 case '7':
1205 weight = 7;
1206 break;
1207 case '8':
1208 weight = 8;
1209 break;
1210 case '9':
1211 weight = 9;
1212 break;
1213 case 'a':
1214 weight = 10;
1215 break;
1216 case 'b':
1217 weight = 11;
1218 break;
1219 case 'c':
1220 weight = 12;
1221 break;
1222 case 'd':
1223 weight = 13;
1224 break;
1225 case 'e':
1226 weight = 14;
1227 break;
1228 case 'f':
1229 weight = 15;
1230 break;
1231 default:
1232 weight = -1;
1233 break;
1234 }
1235 if (weight >= 0 && weight < radix) {
1236 hadDigit = 1;
1237 if (negative) {
1238 if (-(unsigned long)n > (-(unsigned long)LONG_MIN - weight)/radix) {
1239 if (radix != 10)
1240 return 0;
1241 return convertNumberFloat(str);
1242 }
1243 else
1244 n = n*radix - weight;
1245 }
1246 else {
1247 if (n > (LONG_MAX - weight)/radix) {
1248 if (radix != 10)
1249 return 0;
1250 return convertNumberFloat(str);
1251 }
1252 else
1253 n = n*radix + weight;
1254 }
1255 if (hadDecimalPoint)
1256 exp--;
1257 }
1258 else if (c == '.' && radix == 10) {
1259 if (hadDecimalPoint)
1260 return 0;
1261 hadDecimalPoint = 1;
1262 }
1263 else
1264 break;
1265 }
1266 if (!hadDigit || (radix != 10 && i < str.size()))
1267 return 0;
1268 if (i + 1 < str.size() && str[i] == 'e'
1269 && lexCategory(str[i + 1]) != lexLetter) {
1270 hadDecimalPoint = 1;
1271 i++;
1272 int e;
1273 if (!scanSignDigits(str, i, e))
1274 return 0;
1275 exp += e;
1276 }
1277 if (i < str.size()) {
1278 int unitExp;
1279 Unit *unit = scanUnit(str, i, unitExp);
1280 if (!unit)
1281 return 0;
1282 if (unitExp == 1)
1283 return new (*this) UnresolvedLengthObj(n, exp, unit);
1284 else
1285 return convertNumberFloat(str);
1286 }
1287 if (hadDecimalPoint)
1288 return convertNumberFloat(str);
1289 return makeInteger(n);
1290 }
1291 }
1292
1293 bool Interpreter::scanSignDigits(const StringC &str, size_t &i, int &n)
1294 {
1295 bool negative = 0;
1296 if (i < str.size()) {
1297 if (str[i] == '-') {
1298 i++;
1299 negative = 1;
1300 } else if (str[i] == '+')
1301 i++;
1302 }
1303 size_t j = i;
1304 n = 0;
1305 while (i < str.size()
1306 && ('0' <= str[i] && str[i] <= '9')) {
1307 if (negative)
1308 n = n*10 - (str[i] - '0');
1309 else
1310 n = n*10 + (str[i] - '0');
1311 i++;
1312 }
1313 if (i == j)
1314 return 0;
1315 return 1;
1316 }
1317
1318 ELObj *Interpreter::convertNumberFloat(const StringC &str)
1319 {
1320 String<char> buf;
1321 // omit an optional radix prefix
1322 size_t i0 = 0;
1323 if (str.size() > 1 && str[0] == '#' && str[1] == 'd')
1324 i0 = 2;
1325 for (size_t i = i0; i < str.size(); i++) {
1326 if (str[i] > CHAR_MAX || str[i] == '\0')
1327 return 0;
1328 // 'E' is a valid exponent marker for C but not us
1329 if (str[i] == 'E')
1330 break;
1331 buf += char(str[i]);
1332 }
1333 buf += '\0';
1334 const char *endPtr;
1335 double val = strtod((char *)buf.data(), (char **)&endPtr);
1336 if (endPtr - buf.data() == str.size() - i0)
1337 return new (*this) RealObj(val);
1338 if (endPtr == buf.data())
1339 return 0;
1340 int unitExp;
1341 Unit *unit = scanUnit(str, endPtr - buf.data() + i0, unitExp);
1342 if (!unit)
1343 return 0;
1344 return new (*this) UnresolvedQuantityObj(val, unit, unitExp);
1345 }
1346
1347 // Return 0 for error.
1348
1349 Unit *Interpreter::scanUnit(const StringC &str, size_t i, int &unitExp)
1350 {
1351 StringC unitName;
1352 while (i < str.size()) {
1353 if (str[i] == '-' || str[i] == '+' || ('0' <= str[i] && str[i] <= '9'))
1354 break;
1355 unitName += str[i++];
1356 }
1357 if (i >= str.size())
1358 unitExp = 1;
1359 else {
1360 unitExp = 0;
1361 bool neg = 0;
1362 if (str[i] == '-' || str[i] == '+') {
1363 if (str[i] == '-')
1364 neg = 1;
1365 i++;
1366 if (i >= str.size())
1367 return 0;
1368 }
1369 while (i < str.size()) {
1370 if (str[i] < '0' || str[i] > '9')
1371 return 0;
1372 unitExp *= 10;
1373 if (neg)
1374 unitExp -= (str[i] - '0');
1375 else
1376 unitExp += (str[i] - '0');
1377 i++;
1378 }
1379 }
1380 return lookupUnit(unitName);
1381 }
1382
1383 void Interpreter::setNodeLocation(const NodePtr &nd)
1384 {
1385 const LocNode *lnp;
1386 Location nodeLoc;
1387 if ((lnp = LocNode::convert(nd)) != 0
1388 && lnp->getLocation(nodeLoc) == accessOK)
1389 setNextLocation(nodeLoc);
1390 }
1391
1392 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc, Pattern &pattern)
1393 {
1394 IList<Pattern::Element> list;
1395 if (!convertToPattern(obj, loc, 0, list))
1396 return 0;
1397 Pattern tem(list);
1398 tem.swap(pattern);
1399 return 1;
1400 }
1401
1402 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc,
1403 bool isChild,
1404 IList<Pattern::Element> &list)
1405 {
1406 StringObj *str = obj->convertToString();
1407 if (str) {
1408 const Char *s;
1409 size_t n;
1410 str->stringData(s, n);
1411 if (!n) {
1412 setNextLocation(loc);
1413 message(InterpreterMessages::patternEmptyGi);
1414 return 0;
1415 }
1416 list.insert(new Pattern::Element(StringC(s, n)));
1417 return 1;
1418 }
1419 if (obj == makeTrue()) {
1420 list.insert(new Pattern::Element(StringC()));
1421 return 1;
1422 }
1423 Pattern::Element *curElement = 0;
1424 while (!obj->isNil()) {
1425 PairObj *pair = obj->asPair();
1426 if (!pair) {
1427 setNextLocation(loc);
1428 message(InterpreterMessages::patternNotList);
1429 return 0;
1430 }
1431 ELObj *head = pair->car();
1432 obj = pair->cdr();
1433 if (head == makeTrue() && dsssl2()) {
1434 list.insert(curElement = new Pattern::Element(StringC()));
1435 continue;
1436 }
1437 str = head->convertToString();
1438 if (str) {
1439 const Char *s;
1440 size_t n;
1441 str->stringData(s, n);
1442 if (!n) {
1443 setNextLocation(loc);
1444 message(InterpreterMessages::patternEmptyGi);
1445 return 0;
1446 }
1447 list.insert(curElement = new Pattern::Element(StringC(s, n)));
1448 continue;
1449 }
1450 if (!curElement) {
1451 setNextLocation(loc);
1452 message(InterpreterMessages::patternBadGi,
1453 ELObjMessageArg(head, *this));
1454 return 0;
1455 }
1456 if (head->isNil())
1457 continue; // empty attribute list
1458 if (head->asPair()) {
1459 if (!patternAddAttributeQualifiers(head, loc, *curElement)) {
1460 setNextLocation(loc);
1461 message(InterpreterMessages::patternBadAttributeQualifier);
1462 return 0;
1463 }
1464 continue;
1465 }
1466 KeywordObj *key = dsssl2() ? head->asKeyword() : 0;
1467 if (!key) {
1468 setNextLocation(loc);
1469 message(InterpreterMessages::patternBadMember,
1470 ELObjMessageArg(head, *this));
1471 return 0;
1472 }
1473 pair = obj->asPair();
1474 if (!pair) {
1475 setNextLocation(loc);
1476 message(obj->isNil()
1477 ? InterpreterMessages::patternMissingQualifierValue
1478 : InterpreterMessages::patternNotList);
1479 return 0;
1480 }
1481 ELObj *value = pair->car();
1482 obj = pair->cdr();
1483 Identifier::SyntacticKey k;
1484 if (!key->identifier()->syntacticKey(k)) {
1485 setNextLocation(loc);
1486 message(InterpreterMessages::patternUnknownQualifier,
1487 StringMessageArg(key->identifier()->name()));
1488 return 0;
1489 }
1490 switch (k) {
1491 case Identifier::keyAttributes:
1492 if (!patternAddAttributeQualifiers(value, loc, *curElement)) {
1493 setNextLocation(loc);
1494 message(InterpreterMessages::patternBadAttributeQualifier);
1495 return 0;
1496 }
1497 break;
1498 case Identifier::keyChildren:
1499 {
1500 IList<Pattern::Element> children;
1501 if (!convertToPattern(value, loc, 1, children))
1502 return 0;
1503 if (!children.empty())
1504 curElement->addQualifier(new Pattern::ChildrenQualifier(children));
1505 }
1506 break;
1507 case Identifier::keyRepeat:
1508 {
1509 if (isChild) {
1510 setNextLocation(loc);
1511 message(InterpreterMessages::patternChildRepeat);
1512 return 0;
1513 }
1514 SymbolObj *sym = value->asSymbol();
1515 if (sym) {
1516 const StringC &str = *sym->name();
1517 if (str.size() == 1) {
1518 switch (str[0]) {
1519 case '*':
1520 curElement->setRepeat(0, Pattern::Repeat(-1));
1521 value = 0;
1522 break;
1523 case '?':
1524 curElement->setRepeat(0, 1);
1525 value = 0;
1526 break;
1527 case '+':
1528 curElement->setRepeat(1, Pattern::Repeat(-1));
1529 value = 0;
1530 break;
1531 default:
1532 break;
1533 }
1534 }
1535 }
1536 if (value) {
1537 setNextLocation(loc);
1538 message(InterpreterMessages::patternBadQualifierValue,
1539 ELObjMessageArg(value, *this),
1540 StringMessageArg(key->identifier()->name()));
1541 return 0;
1542 }
1543 }
1544 break;
1545 case Identifier::keyPosition:
1546 {
1547 SymbolObj *sym = value->asSymbol();
1548 if (sym) {
1549 Pattern::Qualifier *qual = 0;
1550 const StringC &str = *sym->name();
1551 if (str == "first-of-type")
1552 qual = new Pattern::FirstOfTypeQualifier;
1553 else if (str == "last-of-type")
1554 qual = new Pattern::LastOfTypeQualifier;
1555 else if (str == "first-of-any")
1556 qual = new Pattern::FirstOfAnyQualifier;
1557 else if (str == "last-of-any")
1558 qual = new Pattern::LastOfAnyQualifier;
1559 if (qual) {
1560 curElement->addQualifier(qual);
1561 break;
1562 }
1563 }
1564 setNextLocation(loc);
1565 message(InterpreterMessages::patternBadQualifierValue,
1566 ELObjMessageArg(value, *this),
1567 StringMessageArg(key->identifier()->name()));
1568 return 0;
1569 }
1570 case Identifier::keyOnly:
1571 {
1572 SymbolObj *sym = value->asSymbol();
1573 if (sym) {
1574 Pattern::Qualifier *qual = 0;
1575 const StringC &str = *sym->name();
1576 if (str == "of-type")
1577 qual = new Pattern::OnlyOfTypeQualifier;
1578 else if (str == "of-any")
1579 qual = new Pattern::OnlyOfAnyQualifier;
1580 if (qual) {
1581 curElement->addQualifier(qual);
1582 break;
1583 }
1584 }
1585 setNextLocation(loc);
1586 message(InterpreterMessages::patternBadQualifierValue,
1587 ELObjMessageArg(value, *this),
1588 StringMessageArg(key->identifier()->name()));
1589 return 0;
1590 }
1591 break;
1592 case Identifier::keyId:
1593 {
1594 StringObj *str = value->convertToString();
1595 if (!str) {
1596 setNextLocation(loc);
1597 message(InterpreterMessages::patternBadQualifierValue,
1598 ELObjMessageArg(value, *this),
1599 StringMessageArg(key->identifier()->name()));
1600 return 0;
1601 }
1602 const Char *s;
1603 size_t n;
1604 str->stringData(s, n);
1605 curElement->addQualifier(new Pattern::IdQualifier(StringC(s, n)));
1606 }
1607 break;
1608 case Identifier::keyClass:
1609 {
1610 StringObj *str = value->convertToString();
1611 if (!str) {
1612 setNextLocation(loc);
1613 message(InterpreterMessages::patternBadQualifierValue,
1614 ELObjMessageArg(value, *this),
1615 StringMessageArg(key->identifier()->name()));
1616 return 0;
1617 }
1618 const Char *s;
1619 size_t n;
1620 str->stringData(s, n);
1621 curElement->addQualifier(new Pattern::ClassQualifier(StringC(s, n)));
1622 }
1623 break;
1624 case Identifier::keyImportance:
1625 {
1626 long n;
1627 if (!value->exactIntegerValue(n)) {
1628 setNextLocation(loc);
1629 message(InterpreterMessages::patternBadQualifierValue,
1630 ELObjMessageArg(value, *this),
1631 StringMessageArg(key->identifier()->name()));
1632 return 0;
1633 }
1634 curElement->addQualifier(new Pattern::ImportanceQualifier(n));
1635 }
1636 break;
1637 case Identifier::keyPriority:
1638 {
1639 long n;
1640 if (!value->exactIntegerValue(n)) {
1641 setNextLocation(loc);
1642 message(InterpreterMessages::patternBadQualifierValue,
1643 ELObjMessageArg(value, *this),
1644 StringMessageArg(key->identifier()->name()));
1645 return 0;
1646 }
1647 curElement->addQualifier(new Pattern::PriorityQualifier(n));
1648 }
1649 break;
1650 default:
1651 setNextLocation(loc);
1652 message(InterpreterMessages::patternUnknownQualifier,
1653 StringMessageArg(key->identifier()->name()));
1654 return 0;
1655 }
1656 }
1657 return 1;
1658 }
1659
1660 bool Interpreter::patternAddAttributeQualifiers(ELObj *obj,
1661 const Location &loc,
1662 Pattern::Element &elem)
1663 {
1664 while (!obj->isNil()) {
1665 PairObj *pair = obj->asPair();
1666 if (!pair)
1667 return 0;
1668 StringObj *tem = pair->car()->convertToString();
1669 if (!tem)
1670 return 0;
1671 const Char *s;
1672 size_t n;
1673 tem->stringData(s, n);
1674 if (n == 0)
1675 return 0;
1676 StringC name(s, n);
1677 obj = pair->cdr();
1678 pair = obj->asPair();
1679 if (!pair)
1680 return 0;
1681 obj = pair->cdr();
1682 if (pair->car() == makeFalse() && dsssl2())
1683 elem.addQualifier(new Pattern::AttributeMissingValueQualifier(name));
1684 else if (pair->car() == makeTrue() && dsssl2())
1685 elem.addQualifier(new Pattern::AttributeHasValueQualifier(name));
1686 else {
1687 tem = pair->car()->convertToString();
1688 if (!tem)
1689 return 0;
1690 tem->stringData(s, n);
1691 elem.addQualifier(new Pattern::AttributeQualifier(name, StringC(s, n)));
1692 }
1693 }
1694 return 1;
1695 }
1696
1697 void Interpreter::dispatchMessage(Message &msg)
1698 {
1699 messenger_->dispatchMessage(msg);
1700 }
1701
1702 void Interpreter::dispatchMessage(const Message &msg)
1703 {
1704 messenger_->dispatchMessage(msg);
1705 }
1706
1707 Interpreter::StringSet::StringSet()
1708 {
1709 }
1710
1711 const char *Interpreter::StringSet::store(String<char> &str)
1712 {
1713 str += '\0';
1714 const String<char> *p = table_.lookup(str);
1715 if (!p) {
1716 String<char> *tem = new String<char>;
1717 str.swap(*tem);
1718 table_.insert(tem);
1719 p = tem;
1720 }
1721 return p->data();
1722 }
1723
1724 unsigned long Interpreter::StringSet::hash(const String<char> &str)
1725 {
1726 const char *p = str.data();
1727 unsigned long h = 0;
1728 for (size_t n = str.size(); n > 0; n--)
1729 h = (h << 5) + h + (unsigned char)*p++; // from Chris Torek
1730 return h;
1731 }
1732
1733 bool Identifier::preferBuiltin_ = 0;
1734
1735 Identifier::Identifier(const StringC &name)
1736 : Named(name), value_(0), syntacticKey_(notKey), beingComputed_(0),
1737 flowObj_(0), builtin_(0), defPart_(0), charNIC_(0)
1738 {
1739 }
1740
1741 void Identifier::maybeSaveBuiltin()
1742 {
1743 if (defPart_ == unsigned(-1) && !builtin_) {
1744 builtin_ = new Identifier(name());
1745 if (value_)
1746 builtin_->setValue(value_, defPart_);
1747 else
1748 builtin_->setDefinition(def_, defPart_, defLoc_);
1749 }
1750 }
1751
1752 void Identifier::setDefinition(Owner<Expression> &expr,
1753 unsigned part,
1754 const Location &loc)
1755 {
1756 maybeSaveBuiltin();
1757 def_.swap(expr);
1758 defPart_ = part;
1759 defLoc_ = loc;
1760 value_ = 0;
1761 }
1762
1763 void Identifier::setValue(ELObj *value, unsigned partIndex)
1764 {
1765 maybeSaveBuiltin();
1766 value_ = value;
1767 // Built in functions have lowest priority.
1768 defPart_ = partIndex;
1769 }
1770
1771 bool Identifier::defined(unsigned &part, Location &loc) const
1772 {
1773 if (!def_ && !value_)
1774 return 0;
1775 part = defPart_;
1776 loc = defLoc_;
1777 return 1;
1778 }
1779
1780 ELObj *Identifier::computeValue(bool force, Interpreter &interp) const
1781 {
1782 if (builtin_ && preferBuiltin_)
1783 return builtin_->computeValue(force, interp);
1784 if (value_)
1785 return value_;
1786 bool preferred = 0;
1787 if (defPart_ == unsigned(-1) && !preferBuiltin_) {
1788 preferBuiltin_ = 1;
1789 preferred = 1;
1790 }
1791 ASSERT(def_);
1792 if (beingComputed_) {
1793 if (force) {
1794 interp.setNextLocation(defLoc_);
1795 interp.message(InterpreterMessages::identifierLoop,
1796 StringMessageArg(name()));
1797 ((Identifier *)this)->value_ = interp.makeError();
1798 }
1799 }
1800 else {
1801 ((Identifier *)this)->beingComputed_ = 1;
1802 if (insn_.isNull())
1803 ((Identifier *)this)->insn_
1804 = Expression::optimizeCompile(((Identifier *)this)->def_, interp,
1805 Environment(), 0, InsnPtr());
1806 if (force || def_->canEval(0)) {
1807 VM vm(interp);
1808 ELObj *v = vm.eval(insn_.pointer());
1809 interp.makePermanent(v);
1810 ((Identifier *)this)->value_ = v;
1811 }
1812 ((Identifier *)this)->beingComputed_ = 0;
1813 }
1814 if (preferred)
1815 preferBuiltin_ = 0;
1816 return value_;
1817 }
1818
1819 ELObj *Identifier::computeBuiltinValue(bool force, Interpreter &interp) const
1820 {
1821 preferBuiltin_ = 1;
1822 ELObj *res = computeValue(force, interp);
1823 preferBuiltin_ = 0;
1824 return res;
1825 }
1826
1827 Unit::Unit(const StringC &name)
1828 : Named(name), computed_(notComputed)
1829 {
1830 }
1831
1832 bool Unit::defined(unsigned &part, Location &loc) const
1833 {
1834 if (!def_ && computed_ == notComputed)
1835 return 0;
1836 part = defPart_;
1837 loc = defLoc_;
1838 return 1;
1839 }
1840
1841 void Unit::setDefinition(Owner<Expression> &expr,
1842 unsigned part,
1843 const Location &loc)
1844 {
1845 def_.swap(expr);
1846 defPart_ = part;
1847 defLoc_ = loc;
1848 computed_ = notComputed;
1849 }
1850
1851 void Unit::setValue(long n)
1852 {
1853 computed_ = computedExact;
1854 exact_ = n;
1855 dim_ = 1;
1856 defPart_ = unsigned(-1);
1857 }
1858
1859 void Unit::setValue(double n)
1860 {
1861 computed_ = computedInexact;
1862 inexact_ = n;
1863 dim_ = 1;
1864 defPart_ = unsigned(-1);
1865 }
1866
1867 void Unit::tryCompute(bool force, Interpreter &interp)
1868 {
1869 if (computed_ == notComputed) {
1870 computed_ = beingComputed;
1871 if (insn_.isNull())
1872 insn_ = Expression::optimizeCompile(def_, interp, Environment(), 0, InsnPtr());
1873 if (force || def_->canEval(0)) {
1874 VM vm(interp);
1875 ELObj *v = vm.eval(insn_.pointer());
1876 switch (v->quantityValue(exact_, inexact_, dim_)) {
1877 case ELObj::noQuantity:
1878 if (!interp.isError(v)) {
1879 interp.setNextLocation(defLoc_);
1880 interp.message(InterpreterMessages::badUnitDefinition,
1881 StringMessageArg(name()));
1882 }
1883 computed_ = computedError;
1884 break;
1885 case ELObj::longQuantity:
1886 computed_ = computedExact;
1887 break;
1888 case ELObj::doubleQuantity:
1889 computed_ = computedInexact;
1890 break;
1891 default:
1892 CANNOT_HAPPEN();
1893 }
1894 }
1895 if (computed_ == beingComputed)
1896 computed_ = notComputed;
1897 }
1898 else if (computed_ == beingComputed) {
1899 interp.setNextLocation(defLoc_);
1900 interp.message(InterpreterMessages::unitLoop,
1901 StringMessageArg(name()));
1902 computed_ = computedError;
1903 }
1904 }
1905
1906 // multiply by 10^valExp
1907 // quantity has exponent of 1
1908
1909 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1910 long val, int valExp)
1911 {
1912 tryCompute(force, interp);
1913 long result;
1914 if (computed_ == computedExact && scale(val, valExp, exact_, result))
1915 return new (interp) LengthObj(result);
1916 double x = val;
1917 while (valExp > 0) {
1918 x *= 10.0;
1919 valExp--;
1920 }
1921 while (valExp < 0) {
1922 x /= 10.0;
1923 valExp++;
1924 }
1925 return resolveQuantity(force, interp, x, 1);
1926 }
1927
1928 // val * 10^valExp * factor
1929 // return 0 if it can't be done without overflow
1930
1931 bool Unit::scale(long val, int valExp, long factor, long &result)
1932 {
1933 if (factor <= 0)
1934 return 0; // feeble
1935 while (valExp > 0) {
1936 if (factor > LONG_MAX/10)
1937 return 0;
1938 valExp--;
1939 factor *= 10;
1940 }
1941 if (val >= 0) {
1942 if (val > LONG_MAX/factor)
1943 return 0;
1944 }
1945 else {
1946 if (-(unsigned long)val > -(unsigned long)LONG_MIN/factor)
1947 return 0;
1948 }
1949 result = val*factor;
1950 while (valExp < 0) {
1951 result /= 10;
1952 valExp++;
1953 }
1954 return 1;
1955 }
1956
1957 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1958 double val, int unitExp)
1959 {
1960 tryCompute(force, interp);
1961 double factor;
1962 switch (computed_) {
1963 case computedExact:
1964 factor = exact_;
1965 break;
1966 case computedInexact:
1967 factor = inexact_;
1968 break;
1969 case computedError:
1970 return interp.makeError();
1971 default:
1972 return 0;
1973 }
1974 int resultDim = 0;
1975 double resultVal = val;
1976 while (unitExp > 0) {
1977 resultDim += dim_;
1978 resultVal *= factor;
1979 unitExp--;
1980 }
1981 while (unitExp < 0) {
1982 resultDim -= dim_;
1983 resultVal /= factor;
1984 unitExp++;
1985 }
1986 if (resultDim == 0)
1987 return new (interp) RealObj(resultVal);
1988 return new (interp) QuantityObj(resultVal, resultDim);
1989 }
1990
1991 void ELObjDynamicRoot::trace(Collector &c) const
1992 {
1993 c.trace(obj_);
1994 }
1995
1996 bool operator==(const StringC &s, const char *p)
1997 {
1998 for (size_t i = 0; i < s.size(); i++)
1999 if (p[i] == '\0' || (unsigned char)p[i] != s[i])
2000 return 0;
2001 return p[s.size()] == '\0';
2002 }
2003
2004 void Interpreter::installBuiltins()
2005 {
2006 partIndex_ = unsigned(-1);
2007 StringC sysid(makeStringC(DEFAULT_SCHEME_BUILTINS));
2008 StringC src;
2009 groveManager_->mapSysid(sysid);
2010 if (groveManager_->readEntity(sysid, src)) {
2011 Owner<InputSource> in(new InternalInputSource(src,
2012 InputSourceOrigin::make()));
2013 SchemeParser scm(*this, in);
2014 scm.parse();
2015 }
2016 endPart();
2017 partIndex_ = 0;
2018 }
2019
2020 void Interpreter::setDefaultLanguage(Owner<Expression> &expr,
2021 unsigned part,
2022 const Location &loc)
2023 {
2024 defaultLanguageDef_.swap(expr);
2025 defaultLanguageDefPart_ = part;
2026 defaultLanguageDefLoc_ = loc;
2027 }
2028
2029 ELObj *Interpreter::defaultLanguage() const
2030 {
2031 return defaultLanguage_;
2032 }
2033
2034 bool Interpreter::defaultLanguageSet(unsigned &part,Location &loc) const
2035 {
2036 if(defaultLanguageDef_) {
2037 part = defaultLanguageDefPart_;
2038 loc = defaultLanguageDefLoc_;
2039 return true;
2040 }
2041 return false;
2042 }
2043
2044 void Interpreter::compileDefaultLanguage()
2045 {
2046 if(defaultLanguageDef_) {
2047 InsnPtr insn = Expression::optimizeCompile(defaultLanguageDef_, *this,
2048 Environment(), 0, InsnPtr());
2049 VM vm(*this);
2050 ELObj *obj = vm.eval(insn.pointer());
2051 if(!obj->asLanguage()) {
2052 if(!isError(obj)) {
2053 setNextLocation(defaultLanguageDefLoc_);
2054 message(InterpreterMessages::defLangDeclRequiresLanguage,
2055 ELObjMessageArg(obj, *this));
2056 }
2057 return;
2058 }
2059 makePermanent(obj);
2060 defaultLanguage_ = obj;
2061 }
2062 }
2063
2064 void Interpreter::installCharProperties()
2065 {
2066 //FIXME convert this to tables
2067 // initialize charProperties_;
2068 // if a character doesn't have a value for a property,
2069 // the CharMap contains 0.
2070
2071 CharProp cp;
2072
2073 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2074 cp.loc = Location();
2075 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2076 if (!strictMode_)
2077 for (int i = 0; i < 10; i++) {
2078 ELObjPart num(makeInteger(i), unsigned(-1));
2079 makePermanent(num.obj);
2080 cp.map->setChar(i+'0', num);
2081 }
2082 charProperties_.insert(makeStringC("numeric-equiv"), cp);
2083
2084 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2085 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2086 if (!strictMode_) {
2087 static struct {
2088 Char c;
2089 unsigned num;
2090 } chars[] = {
2091 #define SPACE
2092 #include "charProps.h"
2093 #undef SPACE
2094 };
2095
2096 for (size_t i = 0; i < SIZEOF(chars); i++)
2097 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2098 ELObjPart(makeTrue(), unsigned(-1)));
2099 }
2100 charProperties_.insert(makeStringC("space?"), cp);
2101
2102 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2103 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2104 if (!strictMode_) {
2105 static struct {
2106 Char c;
2107 unsigned num;
2108 } chars[] = {
2109 #define RECORD_END
2110 #include "charProps.h"
2111 #undef RECORD_END
2112 };
2113
2114 for (size_t i = 0; i < SIZEOF(chars); i++)
2115 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2116 ELObjPart(makeTrue(), unsigned(-1)));
2117 }
2118 charProperties_.insert(makeStringC("record-end?"), cp);
2119
2120 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2121 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2122 if (!strictMode_) {
2123 static struct {
2124 Char c;
2125 unsigned num;
2126 } chars[] = {
2127 #define BLANK
2128 #include "charProps.h"
2129 #undef BLANK
2130 };
2131
2132 for (size_t i = 0; i < SIZEOF(chars); i++)
2133 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2134 ELObjPart(makeTrue(), unsigned(-1)));
2135 }
2136 charProperties_.insert(makeStringC("blank?"), cp);
2137
2138 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2139 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2140 if (!strictMode_) {
2141 static struct {
2142 Char c;
2143 unsigned num;
2144 } chars[] = {
2145 #define INPUT_TAB
2146 #include "charProps.h"
2147 #undef INPUT_TAB
2148 };
2149
2150 for (size_t i = 0; i < SIZEOF(chars); i++)
2151 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2152 ELObjPart(makeTrue(), unsigned(-1)));
2153 }
2154 charProperties_.insert(makeStringC("input-tab?"), cp);
2155
2156 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2157 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2158 if (!strictMode_) {
2159 static struct {
2160 Char c;
2161 unsigned num;
2162 } chars[] = {
2163 #define INPUT_WHITESPACE
2164 #include "charProps.h"
2165 #undef INPUT_WHITESPACE
2166 };
2167
2168 for (size_t i = 0; i < SIZEOF(chars); i++)
2169 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2170 ELObjPart(makeTrue(), unsigned(-1)));
2171 }
2172 charProperties_.insert(makeStringC("input-whitespace?"), cp);
2173
2174 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2175 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2176 if (!strictMode_) {
2177 static struct {
2178 Char c;
2179 unsigned num;
2180 } chars[] = {
2181 #define PUNCT
2182 #include "charProps.h"
2183 #undef PUNCT
2184 };
2185
2186 for (size_t i = 0; i < SIZEOF(chars); i++)
2187 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2188 ELObjPart(makeTrue(), unsigned(-1)));
2189 }
2190 charProperties_.insert(makeStringC("punct?"), cp);
2191
2192 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2193 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2194 if (!strictMode_) {
2195 static struct {
2196 Char c1, c2;
2197 char *script;
2198 } chars[] = {
2199 #define SCRIPT
2200 #include "charProps.h"
2201 #undef SCRIPT
2202 };
2203
2204 StringC prefix = makeStringC("ISO/IEC 10179::1996//Script::");
2205 for (size_t i = 0; i < SIZEOF(chars); i++) {
2206 StringC tem(prefix);
2207 tem += makeStringC(chars[i].script);
2208 StringObj *obj = new (*this) StringObj(tem);
2209 makePermanent(obj);
2210 cp.map->setRange(chars[i].c1, chars[i].c2,
2211 ELObjPart(obj, unsigned(-1)));
2212 }
2213 }
2214 charProperties_.insert(makeStringC("script"), cp);
2215
2216 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2217 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2218 charProperties_.insert(makeStringC("glyph-id"), cp);
2219
2220 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2221 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2222 charProperties_.insert(makeStringC("drop-after-line-break?"), cp);
2223
2224 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2225 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2226 charProperties_.insert(makeStringC("drop-unless-before-line-break?"), cp);
2227
2228 cp.def = ELObjPart(makeInteger(0), unsigned(-1));
2229 makePermanent(cp.def.obj);
2230 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2231 CharProp cp2;
2232 cp2.def = ELObjPart(cp.def.obj, unsigned(-1));
2233 cp2.loc = Location();
2234 cp2.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2235 if(!strictMode_) {
2236 static struct {
2237 Char c;
2238 unsigned short num;
2239 unsigned short bbp;
2240 unsigned short bap;
2241 } chars[] ={
2242 #define BREAK_PRIORITIES
2243 #include "charProps.h"
2244 #undef BREAK_PRIORITIES
2245 };
2246 for(size_t i = 0; i<SIZEOF(chars); ++i) {
2247 ELObj *obj = makeInteger(chars[i].bbp);
2248 makePermanent(obj);
2249 cp.map->setRange(chars[i].c, chars[i].c + chars[i].num-1,
2250 ELObjPart(obj, unsigned(-1)));
2251 if(chars[i].bap!=chars[i].bbp) {
2252 obj = makeInteger(chars[i].bap);
2253 makePermanent(obj);
2254 }
2255 cp2.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2256 ELObjPart(obj, unsigned(-1)));
2257 }
2258 }
2259
2260 charProperties_.insert(makeStringC("break-before-priority"), cp);
2261 charProperties_.insert(makeStringC("break-after-priority"), cp2);
2262
2263 cp.def = ELObjPart(makeSymbol(makeStringC("ordinary")), unsigned(-1));
2264 makePermanent(cp.def.obj);
2265 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2266 charProperties_.insert(makeStringC("math-class"), cp);
2267
2268 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2269 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2270 charProperties_.insert(makeStringC("math-font-posture"), cp);
2271 }
2272
2273 // return 1 if the character has the property, return 0 if no such property
2274 // or the character doesn't have the property
2275 // set ret to the value or the default value
2276 ELObj *Interpreter::charProperty(const StringC &prop, Char c, const Location &loc, ELObj *def)
2277 {
2278 const CharProp *cp = charProperties_.lookup(prop);
2279 if (!cp) {
2280 setNextLocation(loc);
2281 message(InterpreterMessages::unknownCharProperty,
2282 StringMessageArg(prop));
2283 return makeError();
2284 }
2285
2286 if ((*cp->map)[c].obj)
2287 return (*cp->map)[c].obj;
2288 else if (def)
2289 return def;
2290 else
2291 return cp->def.obj;
2292 }
2293
2294 void Interpreter::addCharProperty(const Identifier *prop, Owner<Expression> &defval)
2295 {
2296 // FIXME: what about variable default values ?
2297 defval->optimize(*this, Environment(), defval);
2298 if(!defval->constantValue()) {
2299 setNextLocation(defval->location());
2300 message(InterpreterMessages::varCharPropertyExprUnsupported);
2301 return;
2302 }
2303 // FIXME: this is a kind of memory leak
2304 makePermanent(defval->constantValue());
2305 ELObjPart val(defval->constantValue(), partIndex_);
2306 const CharProp *cp = charProperties_.lookup(prop->name());
2307 if (cp) {
2308 if (partIndex_ < cp->def.defPart)
2309 ((CharProp *)cp)->def = val;
2310 else if (partIndex_ == cp->def.defPart &&
2311 !ELObj::eqv(*val.obj, *cp->def.obj)) {
2312 // FIXME: report previous location
2313 setNextLocation(defval->location());
2314 message(InterpreterMessages::duplicateCharPropertyDecl,
2315 StringMessageArg(prop->name()), cp->loc);
2316 }
2317 }
2318 else {
2319 CharProp ncp;
2320 ncp.map = new CharMap<ELObjPart>(ELObjPart(0,0));
2321 ncp.def = val;
2322 ncp.loc = defval->location();
2323 charProperties_.insert(prop->name(), ncp);
2324 }
2325 }
2326
2327 void Interpreter::setCharProperty(const Identifier *prop, Char c, Owner<Expression> &val)
2328 {
2329 // FIXME: what about variable default values ?
2330 val->optimize(*this, Environment(), val);
2331 if(!val->constantValue()) {
2332 setNextLocation(val->location());
2333 message(InterpreterMessages::varCharPropertyExprUnsupported);
2334 return;
2335 }
2336 makePermanent(val->constantValue());
2337 const CharProp *cp = charProperties_.lookup(prop->name());
2338 if (!cp) {
2339 CharProp ncp;
2340 ncp.map = new CharMap<ELObjPart>(ELObjPart(0,0));
2341 ncp.def = ELObjPart(0, unsigned(-1));
2342 ncp.loc = val->location();
2343 charProperties_.insert(prop->name(), ncp);
2344 cp = charProperties_.lookup(prop->name());
2345 }
2346 ELObjPart obj = ELObjPart(val->constantValue(), partIndex_);
2347
2348 ELObjPart def = (*cp->map)[c];
2349 if (def.obj) {
2350 if (partIndex_ < def.defPart)
2351 cp->map->setChar(c, obj);
2352 else if (partIndex_ == def.defPart && !ELObj::eqv(*obj.obj, *def.obj)) {
2353 setNextLocation(val->location());
2354 // FIXME: report previous location
2355 message(InterpreterMessages::duplicateAddCharProperty,
2356 StringMessageArg(prop->name()),
2357 StringMessageArg(StringC(&c, 1)));
2358 }
2359 }
2360 else
2361 cp->map->setChar(c, obj);
2362 }
2363
2364 void
2365 Interpreter::compileCharProperties()
2366 {
2367 HashTableIter<StringC, CharProp> iter(charProperties_);
2368 const StringC *key;
2369 const CharProp *val;
2370 while (iter.next(key, val))
2371 if (!val->def.obj) {
2372 // FIXME location
2373 setNextLocation(val->loc);
2374 message(InterpreterMessages::unknownCharProperty,
2375 StringMessageArg(*key));
2376 ((CharProp *)val)->def = ELObjPart(makeError(), 0);
2377 }
2378 }
2379
2380
2381 void Interpreter::installExtensionCharNIC(Identifier *ident,
2382 const StringC &pubid,
2383 const Location &loc)
2384 {
2385 ident->setCharNIC(currentPartIndex(), loc);
2386 }
2387
2388 #ifdef DSSSL_NAMESPACE
2389 }
2390 #endif
2391