1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
5 #include "Interpreter.h"
7 #include "InterpreterMessages.h"
10 #include "MacroFlowObj.h"
11 #include "ELObjMessageArg.h"
14 #include "SchemeParser.h"
16 #include "InternalInputSource.h"
20 #ifdef DSSSL_NAMESPACE
21 namespace DSSSL_NAMESPACE {
24 const Char defaultChar = 0xfffd;
29 static size_t sz[] = {
30 sizeof(UnresolvedQuantityObj),
32 sizeof(OverriddenStyleObj),
33 sizeof(MergeStyleObj),
34 sizeof(DeviceRGBColorObj),
35 sizeof(ColorSpaceObj),
39 sizeof(NamedNodeListPtrNodeListObj),
40 sizeof(ProcessNodeSosofoObj),
41 sizeof(AppendSosofoObj),
42 sizeof(SetNonInheritedCsSosofoObj),
43 sizeof(LabelSosofoObj),
45 sizeof(FlowObj) + sizeof(StringC), // for FormattingInstructionFlowObj
54 for (size_t i = 1; i < SIZEOF(sz); i++)
60 Interpreter::Interpreter(GroveManager *groveManager,
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
73 lexCategory_(lexOther),
74 unitsPerInch_(unitsPerInch),
76 initialProcessingMode_(StringC()),
77 currentPartFirstInitialValue_(0),
79 nextGlyphSubstTableUniqueId_(0),
80 debugMode_(debugMode),
82 strictMode_(strictMode)
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();
104 installInheritedCs();
105 installNodeProperties();
107 static const char *lexCategories[] = {
108 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
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);
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
128 for (Char i = 127; i < charMax; i++)
129 lexCategory_.setChar(i, lexAddNameStart);
131 initialProcessingMode_.setDefined();
132 // can't be done before initializing lexCategory_
134 installCharProperties();
137 void Interpreter::compile()
139 // FIXME compile all definitions
140 compileInitialValues();
141 initialProcessingMode_.compile(*this);
142 NamedTableIter<ProcessingMode> iter(processingModeTable_);
144 ProcessingMode *mode = iter.next();
147 mode->compile(*this);
149 compileCharProperties();
150 compileDefaultLanguage();
153 void Interpreter::compileInitialValues()
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();
163 ConstPtr<InheritedC> tem(ic->make(val, expr->location(), *this));
168 ics.push_back(new VarInheritedC(ic,
169 expr->compile(*this, Environment(), 0, InsnPtr()),
173 Vector<ConstPtr<InheritedC> > forceIcs;
174 initialStyle_ = new (*this) VarStyleObj(new StyleSpec(forceIcs, ics), 0, 0, NodePtr());
175 makePermanent(initialStyle_);
179 void Interpreter::installInitialValue(Identifier *ident, Owner<Expression> &expr)
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());
192 initialValueValues_.resize(initialValueValues_.size() + 1);
193 expr.swap(initialValueValues_.back());
194 initialValueNames_.push_back(ident);
197 void Interpreter::installUnits()
211 { "pc", 1, 6 } // a DSSSL2 addition
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));
220 unit->setValue(double(n)/units[i].denom);
224 void Interpreter::installSyntacticKeys()
228 Identifier::SyntacticKey key;
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 },
372 { "declare-class-attribute", Identifier::keyDeclareClassAttribute },
373 { "declare-id-attribute", Identifier::keyDeclareIdAttribute },
374 { "declare-flow-object-macro", Identifier::keyDeclareFlowObjectMacro },
375 { "or-element", Identifier::keyOrElement },
376 { "set!", Identifier::keySet },
377 { "begin", Identifier::keyBegin },
379 for (size_t i = 0; i < SIZEOF(keys); i++) {
380 StringC tem(makeStringC(keys[i].name));
381 lookup(tem)->setSyntacticKey(keys[i].key);
382 if (dsssl2() && tem[tem.size() - 1] == '?') {
383 tem.resize(tem.size() - 1);
384 lookup(tem)->setSyntacticKey(keys[i].key);
388 for (size_t i = 0; i < SIZEOF(keys2); i++)
389 lookup(makeStringC(keys2[i].name))->setSyntacticKey(keys2[i].key);
393 void Interpreter::installCValueSymbols()
395 cValueSymbols_[0] = makeFalse();
396 cValueSymbols_[1] = makeTrue();
397 for (size_t i = 2; i < FOTBuilder::nSymbols; i++) {
398 SymbolObj *sym = makeSymbol(makeStringC(FOTBuilder::symbolName(FOTBuilder::Symbol(i))));
399 sym->setCValue(FOTBuilder::Symbol(i));
400 cValueSymbols_[i] = sym;
404 void Interpreter::installPortNames()
406 // These must match the order in SymbolObj.
407 static const char *names[] = {
427 ASSERT(SIZEOF(names) == nPortNames);
428 for (size_t i = 0; i < SIZEOF(names); i++)
429 portNames_[i] = makeSymbol(makeStringC(names[i]));
432 void Interpreter::installCharNames()
438 #include "charNames.h"
440 for (size_t i = 0; i < SIZEOF(chars); i++) {
443 ch.defPart = unsigned(-1);
444 namedCharTable_.insert(makeStringC(chars[i].name), ch, 1);
448 void Interpreter::installSdata()
450 // This comes from uni2sgml.txt on ftp://unicode.org.
451 // It is marked there as obsolete, so it probably ought to be checked.
452 // The definitions of apos and quot have been fixed for consistency with XML.
459 for (size_t i = 0; i < SIZEOF(entities); i++) {
461 ch.c = entities[i].c;
462 ch.defPart = unsigned(-1);
463 sdataEntityNameTable_.insert(makeStringC(entities[i].name), ch, 1);
467 void Interpreter::installNodeProperties()
469 for (int i = 0; i < ComponentName::nIds; i++) {
470 ComponentName::Id id = ComponentName::Id(i);
471 nodePropertyTable_.insert(makeStringC(ComponentName::rcsName(id)), i);
472 nodePropertyTable_.insert(makeStringC(ComponentName::sdqlName(id)), i);
476 void Interpreter::setCharRepertoire(const StringC &pubid)
478 if (pubid == "UNREGISTERED::OpenJade//Character Repertoire::OpenJade") {
482 // This assumes that we process char-repertoire
483 // declaration before any declarations which change
484 // lexical categories.
485 for (Char i = 127; i < charMax; i++)
486 lexCategory_.setChar(i, lexAddNameStart);
490 message(InterpreterMessages::unsupportedCharRepertoire,
491 StringMessageArg(pubid));
494 void Interpreter::addStandardChar(const StringC &name, const StringC &num)
498 if (!scanSignDigits(num, i, n)) {
499 message(InterpreterMessages::invalidCharNumber, StringMessageArg(num));
503 const CharPart *def = namedCharTable_.lookup(name);
506 ch.defPart = dPartIndex_;
508 if (dPartIndex_ < def->defPart)
509 namedCharTable_.insert(name, ch, 1);
510 else if (def->defPart == dPartIndex_ && def->c != ch.c)
511 message(InterpreterMessages::duplicateCharName,
512 StringMessageArg(name));
515 namedCharTable_.insert(name, ch, 1);
518 void Interpreter::addNameChar(const StringC &name)
520 const CharPart *cp = namedCharTable_.lookup(name);
522 message(InterpreterMessages::badCharName,
523 StringMessageArg(name));
524 else if (lexCategory_[cp->c] != lexOther)
525 // FIXME give a more specific error
526 message(InterpreterMessages::badDeclaration);
528 lexCategory_.setChar(cp->c, lexAddNameStart);
531 void Interpreter::addSeparatorChar(const StringC &name)
533 const CharPart *cp = namedCharTable_.lookup(name);
535 message(InterpreterMessages::badCharName,
536 StringMessageArg(name));
537 else if (lexCategory_[cp->c] != lexOther)
538 // FIXME give a more specific error
539 message(InterpreterMessages::badDeclaration);
541 lexCategory_.setChar(cp->c, lexAddWhiteSpace);
544 void Interpreter::addSdataEntity(const StringC &ename, const StringC &etext, const StringC &name)
546 const CharPart *cp = namedCharTable_.lookup(name);
548 message(InterpreterMessages::badCharName,
549 StringMessageArg(name));
555 ch.defPart = dPartIndex_;
557 if (ename.size() > 0) {
558 const CharPart *def = sdataEntityNameTable_.lookup(ename);
560 if (dPartIndex_ < def->defPart)
561 sdataEntityNameTable_.insert(ename, ch);
562 else if (def->defPart == dPartIndex_ && def->c != cp->c)
563 message(InterpreterMessages::duplicateSdataEntityName,
564 StringMessageArg(ename));
567 sdataEntityNameTable_.insert(ename, ch);
570 if (etext.size() > 0) {
571 const CharPart *def = sdataEntityTextTable_.lookup(etext);
573 if (dPartIndex_ < def->defPart)
574 sdataEntityTextTable_.insert(etext, ch);
575 else if (def->defPart == dPartIndex_ && def->c != cp->c)
576 message(InterpreterMessages::duplicateSdataEntityText,
577 StringMessageArg(etext));
580 sdataEntityTextTable_.insert(etext, ch);
584 bool Interpreter::sdataMap(GroveString name, GroveString text, GroveChar &c) const
586 StringC tem(name.data(), name.size());
587 StringC tem2(text.data(), text.size());
589 const CharPart *cp = sdataEntityNameTable_.lookup(tem);
595 cp = sdataEntityTextTable_.lookup(tem2);
601 if (convertUnicodeCharName(tem, c))
603 // I think this is the best thing to do.
604 // At least it makes preserve-sdata work with unknown SDATA entities.
609 ELObj *Interpreter::convertGlyphId(const Char *str, size_t len, const Location &loc)
612 const char *publicId = 0;
613 for (size_t i = len; i > 1; --i) {
614 if (str[i - 1] == ':' && str[i - 2] == ':' && i < len && str[i] != '0') {
615 for (size_t j = i; j < len; j++)
616 n = n*10 + (str[j] - '0');
617 publicId = storePublicId(str, i - 2, loc);
620 if (str[i - 1] < '0' || str[i - 1] > '9')
624 publicId = storePublicId(str, len, loc);
625 return new (*this) GlyphIdObj(FOTBuilder::GlyphId(publicId, n));
628 bool Interpreter::convertCharName(const StringC &str, Char &c) const
630 const CharPart *cp = namedCharTable_.lookup(str);
635 return convertUnicodeCharName(str, c);
638 bool Interpreter::convertUnicodeCharName(const StringC &str, Char &c)
640 if (str.size() != 6 || str[0] != 'U' || str[1] != '-')
643 for (int i = 2; i < 6; i++) {
656 value |= str[i] - '0';
664 value |= 10 + (str[i] - 'A');
674 SymbolObj *Interpreter::makeSymbol(const StringC &str)
676 SymbolObj *sym = symbolTable_.lookup(str);
678 StringObj *strObj = new (*this) StringObj(str);
679 makePermanent(strObj);
680 sym = new (*this) SymbolObj(strObj);
682 symbolTable_.insert(sym);
687 Identifier *Interpreter::lookup(const StringC &str)
689 Identifier *ident = identTable_.lookup(str);
691 ident = new Identifier(str);
692 identTable_.insert(ident);
697 bool Interpreter::lookupNodeProperty(const StringC &str, ComponentName::Id &id)
699 const int *val = nodePropertyTable_.lookup(str);
702 for (size_t i = 0; i < tem.size(); i++) {
703 if (tem[i] >= 'A' && tem[i] <= 'Z')
704 tem[i] = 'a' + (tem[i] - 'A');
706 val = nodePropertyTable_.lookup(tem);
710 id = ComponentName::Id(*val);
714 Unit *Interpreter::lookupUnit(const StringC &str)
716 Unit *unit = unitTable_.lookup(str);
718 unit = new Unit(str);
719 unitTable_.insert(unit);
724 ProcessingMode *Interpreter::lookupProcessingMode(const StringC &str)
726 ProcessingMode *mode = processingModeTable_.lookup(str);
728 mode = new ProcessingMode(str, &initialProcessingMode_);
729 processingModeTable_.insert(mode);
734 StringC Interpreter::makeStringC(const char *s)
739 tem += (unsigned char)*s++;
743 void Interpreter::endPart()
745 currentPartFirstInitialValue_ = initialValueNames_.size();
749 void Interpreter::dEndPart()
754 void Interpreter::normalizeGeneralName(const NodePtr &nd, StringC &str)
756 NamedNodeListPtr nnl;
758 if (nd->getGroveRoot(root) == accessOK
759 && root->getElements(nnl) == accessOK)
760 str.resize(nnl->normalize(str.begin(), str.size()));
763 ELObj *Interpreter::makeLengthSpec(const FOTBuilder::LengthSpec &ls)
765 if (ls.displaySizeFactor != 0.0) {
766 LengthSpec result(LengthSpec::displaySize, ls.displaySizeFactor);
767 result += double(ls.length);
768 return new (*this) LengthSpecObj(result);
771 return new (*this) LengthObj(ls.length);
774 bool Interpreter::convertBooleanC(ELObj *obj, const Identifier *ident, const Location &loc,
777 obj = convertFromString(obj, convertAllowBoolean, loc);
778 if (obj == makeFalse()) {
782 if (obj == makeTrue()) {
786 invalidCharacteristicValue(ident, loc);
790 bool Interpreter::convertPublicIdC(ELObj *obj, const Identifier *ident,
792 FOTBuilder::PublicId &pubid)
794 if (obj == makeFalse()) {
800 if (obj->stringData(s, n)) {
804 pubid = storePublicId(s, n, loc);
807 invalidCharacteristicValue(ident, loc);
811 const char *Interpreter::storePublicId(const Char *s, size_t n, const Location &loc)
814 for (; n > 0; s++, n--) {
816 setNextLocation(loc);
817 message(InterpreterMessages::invalidPublicIdChar,
818 StringMessageArg(StringC(s, 1)));
824 return publicIds_.store(buf);
827 bool Interpreter::convertStringC(ELObj *obj, const Identifier *ident, const Location &loc,
832 if (obj->stringData(s, n)) {
836 invalidCharacteristicValue(ident, loc);
840 bool Interpreter::convertLengthSpec(ELObj *obj,
841 FOTBuilder::LengthSpec &result)
845 switch (obj->quantityValue(result.length, d, dim)) {
846 case ELObj::longQuantity:
850 case ELObj::doubleQuantity:
852 // FIXME catch overflow
853 result.length = d < 0.0 ? long(d - .5) : long(d + .5);
859 const LengthSpec *ls = obj->lengthSpec();
861 return ls->convert(result);
868 bool Interpreter::convertLengthC(ELObj *obj, const Identifier *ident,
870 FOTBuilder::Length &n)
872 obj = convertFromString(obj, convertAllowNumber, loc);
875 switch (obj->quantityValue(n, d, dim)) {
876 case ELObj::longQuantity:
880 case ELObj::doubleQuantity:
882 // FIXME catch overflow
890 invalidCharacteristicValue(ident, loc);
894 bool Interpreter::convertLengthSpecC(ELObj *obj, const Identifier *ident,
896 FOTBuilder::LengthSpec &result)
898 obj = convertFromString(obj, convertAllowNumber, loc);
899 if (convertLengthSpec(obj, result))
901 invalidCharacteristicValue(ident, loc);
905 bool Interpreter::convertOptLengthSpecC(ELObj *obj, const Identifier *ident,
907 FOTBuilder::OptLengthSpec &result)
909 obj = convertFromString(obj, convertAllowBoolean|convertAllowNumber, loc);
910 if (obj == makeFalse()) {
911 result.hasLength = 0;
914 if (convertLengthSpecC(obj, ident, loc, result.length)) {
915 result.hasLength = 1;
921 bool Interpreter::convertOptPositiveIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
924 obj = convertFromString(obj, convertAllowNumber|convertAllowBoolean, loc);
925 if (obj == makeFalse()) {
929 if (obj->exactIntegerValue(result) && result > 0)
931 // FIXME allow inexact value
932 invalidCharacteristicValue(ident, loc);
936 bool Interpreter::convertIntegerC(ELObj *obj, const Identifier *ident, const Location &loc,
939 obj = convertFromString(obj, convertAllowNumber, loc);
940 if (obj->exactIntegerValue(result))
942 // FIXME allow inexact value
943 invalidCharacteristicValue(ident, loc);
948 bool Interpreter::convertLetter2C(ELObj *obj, const Identifier *ident, const Location &loc,
949 FOTBuilder::Letter2 &code)
951 StringObj *strObj = obj->convertToString();
953 const StringC &str = *strObj;
955 && str[0] >= 'A' && str[0] <= 'Z'
956 && str[1] >= 'A' && str[1] <= 'Z') {
957 code = SP_LETTER2(str[0], str[1]);
960 if (str.size() == 0) {
965 else if (obj == makeFalse()) {
969 invalidCharacteristicValue(ident, loc);
973 bool Interpreter::convertCharC(ELObj *obj, const Identifier *ident, const Location &loc,
976 if (obj->charValue(result))
980 if (obj->stringData(s, n) && n == 1) {
984 invalidCharacteristicValue(ident, loc);
988 bool Interpreter::convertColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
990 color = obj->asColor();
993 invalidCharacteristicValue(ident, loc);
997 bool Interpreter::convertOptColorC(ELObj *obj, const Identifier *ident, const Location &loc, ColorObj *&color)
999 color = obj->asColor();
1002 if (obj == makeFalse())
1004 invalidCharacteristicValue(ident, loc);
1008 bool Interpreter::convertRealC(ELObj *obj, const Identifier *ident, const Location &loc,
1011 obj = convertFromString(obj, convertAllowNumber, loc);
1012 if (obj->realValue(result))
1014 invalidCharacteristicValue(ident, loc);
1018 bool Interpreter::convertEnumC(ELObj *obj, const Identifier *ident, const Location &loc,
1019 FOTBuilder::Symbol &sym)
1021 obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
1022 if (obj == makeFalse()) {
1023 sym = FOTBuilder::symbolFalse;
1026 SymbolObj *symObj = obj->asSymbol();
1028 sym = symObj->cValue();
1029 if (sym != FOTBuilder::symbolFalse)
1032 if (obj == makeTrue()) {
1033 sym = FOTBuilder::symbolTrue;
1036 invalidCharacteristicValue(ident, loc);
1040 bool Interpreter::convertEnumC(const FOTBuilder::Symbol *syms, size_t nSyms,
1041 ELObj *obj, const Identifier *ident, const Location &loc,
1042 FOTBuilder::Symbol &result)
1044 obj = convertFromString(obj, convertAllowSymbol|convertAllowBoolean, loc);
1045 SymbolObj *symObj = obj->asSymbol();
1046 FOTBuilder::Symbol val;
1048 val = symObj->cValue();
1049 if (val == FOTBuilder::symbolFalse) {
1050 invalidCharacteristicValue(ident, loc);
1054 else if (obj == makeFalse())
1055 val = FOTBuilder::symbolFalse;
1056 else if (obj == makeTrue())
1057 val = FOTBuilder::symbolTrue;
1059 invalidCharacteristicValue(ident, loc);
1062 for (size_t i = 0; i < nSyms; i++)
1063 if (val == syms[i]) {
1067 invalidCharacteristicValue(ident, loc);
1071 void Interpreter::invalidCharacteristicValue(const Identifier *ident, const Location &loc)
1073 setNextLocation(loc);
1074 message(InterpreterMessages::invalidCharacteristicValue,
1075 StringMessageArg(ident->name()));
1079 bool equal(const Char *s1, const char *s2, size_t n)
1082 if (*s1++ != (unsigned char)*s2++)
1089 ELObj *Interpreter::convertFromString(ELObj *obj, unsigned hints, const Location &loc)
1091 // FIXME fold to lower case
1094 if (!dsssl2() || !obj->stringData(s, n))
1096 if (hints & convertAllowNumber) {
1097 ELObj *tem = convertNumber(StringC(s, n));
1099 return tem->resolveQuantities(1, *this, loc);
1101 if (hints & convertAllowSymbol) {
1103 SymbolObj *sym = symbolTable_.lookup(tem);
1104 if (sym && sym->cValue() != FOTBuilder::symbolFalse)
1107 if (hints & convertAllowBoolean) {
1110 if (equal(s, "no", n))
1114 if (equal(s, "yes", n))
1118 if (equal(s, "true", n))
1122 if (equal(s, "false", n))
1130 ELObj *Interpreter::convertNumber(const StringC &str, int radix)
1133 if (str.size() == 0)
1136 if (str[0] == '#') {
1157 if (i >= str.size())
1160 if (str[i] == '-') {
1169 bool hadDecimalPoint = 0;
1173 for (; i < str.size(); i++) {
1229 if (weight >= 0 && weight < radix) {
1232 if (-(unsigned long)n > (-(unsigned long)LONG_MIN - weight)/radix) {
1235 return convertNumberFloat(str);
1238 n = n*radix - weight;
1241 if (n > (LONG_MAX - weight)/radix) {
1244 return convertNumberFloat(str);
1247 n = n*radix + weight;
1249 if (hadDecimalPoint)
1252 else if (c == '.' && radix == 10) {
1253 if (hadDecimalPoint)
1255 hadDecimalPoint = 1;
1260 if (!hadDigit || (radix != 10 && i < str.size()))
1262 if (i + 1 < str.size() && str[i] == 'e'
1263 && lexCategory(str[i + 1]) != lexLetter) {
1264 hadDecimalPoint = 1;
1267 if (!scanSignDigits(str, i, e))
1271 if (i < str.size()) {
1273 Unit *unit = scanUnit(str, i, unitExp);
1277 return new (*this) UnresolvedLengthObj(n, exp, unit);
1279 return convertNumberFloat(str);
1281 if (hadDecimalPoint)
1282 return convertNumberFloat(str);
1283 return makeInteger(n);
1287 bool Interpreter::scanSignDigits(const StringC &str, size_t &i, int &n)
1290 if (i < str.size()) {
1291 if (str[i] == '-') {
1294 } else if (str[i] == '+')
1299 while (i < str.size()
1300 && ('0' <= str[i] && str[i] <= '9')) {
1302 n = n*10 - (str[i] - '0');
1304 n = n*10 + (str[i] - '0');
1312 ELObj *Interpreter::convertNumberFloat(const StringC &str)
1315 // omit an optional radix prefix
1317 if (str.size() > 1 && str[0] == '#' && str[1] == 'd')
1319 for (size_t i = i0; i < str.size(); i++) {
1320 if (str[i] > CHAR_MAX || str[i] == '\0')
1322 // 'E' is a valid exponent marker for C but not us
1325 buf += char(str[i]);
1329 double val = strtod((char *)buf.data(), (char **)&endPtr);
1330 if (endPtr - buf.data() == str.size() - i0)
1331 return new (*this) RealObj(val);
1332 if (endPtr == buf.data())
1335 Unit *unit = scanUnit(str, endPtr - buf.data() + i0, unitExp);
1338 return new (*this) UnresolvedQuantityObj(val, unit, unitExp);
1341 // Return 0 for error.
1343 Unit *Interpreter::scanUnit(const StringC &str, size_t i, int &unitExp)
1346 while (i < str.size()) {
1347 if (str[i] == '-' || str[i] == '+' || ('0' <= str[i] && str[i] <= '9'))
1349 unitName += str[i++];
1351 if (i >= str.size())
1356 if (str[i] == '-' || str[i] == '+') {
1360 if (i >= str.size())
1363 while (i < str.size()) {
1364 if (str[i] < '0' || str[i] > '9')
1368 unitExp -= (str[i] - '0');
1370 unitExp += (str[i] - '0');
1374 return lookupUnit(unitName);
1377 void Interpreter::setNodeLocation(const NodePtr &nd)
1381 if ((lnp = LocNode::convert(nd)) != 0
1382 && lnp->getLocation(nodeLoc) == accessOK)
1383 setNextLocation(nodeLoc);
1386 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc, Pattern &pattern)
1388 IList<Pattern::Element> list;
1389 if (!convertToPattern(obj, loc, 0, list))
1396 bool Interpreter::convertToPattern(ELObj *obj, const Location &loc,
1398 IList<Pattern::Element> &list)
1400 StringObj *str = obj->convertToString();
1404 str->stringData(s, n);
1406 setNextLocation(loc);
1407 message(InterpreterMessages::patternEmptyGi);
1410 list.insert(new Pattern::Element(StringC(s, n)));
1413 if (obj == makeTrue()) {
1414 list.insert(new Pattern::Element(StringC()));
1417 Pattern::Element *curElement = 0;
1418 while (!obj->isNil()) {
1419 PairObj *pair = obj->asPair();
1421 setNextLocation(loc);
1422 message(InterpreterMessages::patternNotList);
1425 ELObj *head = pair->car();
1427 if (head == makeTrue() && dsssl2()) {
1428 list.insert(curElement = new Pattern::Element(StringC()));
1431 str = head->convertToString();
1435 str->stringData(s, n);
1437 setNextLocation(loc);
1438 message(InterpreterMessages::patternEmptyGi);
1441 list.insert(curElement = new Pattern::Element(StringC(s, n)));
1445 setNextLocation(loc);
1446 message(InterpreterMessages::patternBadGi,
1447 ELObjMessageArg(head, *this));
1451 continue; // empty attribute list
1452 if (head->asPair()) {
1453 if (!patternAddAttributeQualifiers(head, loc, *curElement)) {
1454 setNextLocation(loc);
1455 message(InterpreterMessages::patternBadAttributeQualifier);
1460 KeywordObj *key = dsssl2() ? head->asKeyword() : 0;
1462 setNextLocation(loc);
1463 message(InterpreterMessages::patternBadMember,
1464 ELObjMessageArg(head, *this));
1467 pair = obj->asPair();
1469 setNextLocation(loc);
1470 message(obj->isNil()
1471 ? InterpreterMessages::patternMissingQualifierValue
1472 : InterpreterMessages::patternNotList);
1475 ELObj *value = pair->car();
1477 Identifier::SyntacticKey k;
1478 if (!key->identifier()->syntacticKey(k)) {
1479 setNextLocation(loc);
1480 message(InterpreterMessages::patternUnknownQualifier,
1481 StringMessageArg(key->identifier()->name()));
1485 case Identifier::keyAttributes:
1486 if (!patternAddAttributeQualifiers(value, loc, *curElement)) {
1487 setNextLocation(loc);
1488 message(InterpreterMessages::patternBadAttributeQualifier);
1492 case Identifier::keyChildren:
1494 IList<Pattern::Element> children;
1495 if (!convertToPattern(value, loc, 1, children))
1497 if (!children.empty())
1498 curElement->addQualifier(new Pattern::ChildrenQualifier(children));
1501 case Identifier::keyRepeat:
1504 setNextLocation(loc);
1505 message(InterpreterMessages::patternChildRepeat);
1508 SymbolObj *sym = value->asSymbol();
1510 const StringC &str = *sym->name();
1511 if (str.size() == 1) {
1514 curElement->setRepeat(0, Pattern::Repeat(-1));
1518 curElement->setRepeat(0, 1);
1522 curElement->setRepeat(1, Pattern::Repeat(-1));
1531 setNextLocation(loc);
1532 message(InterpreterMessages::patternBadQualifierValue,
1533 ELObjMessageArg(value, *this),
1534 StringMessageArg(key->identifier()->name()));
1539 case Identifier::keyPosition:
1541 SymbolObj *sym = value->asSymbol();
1543 Pattern::Qualifier *qual = 0;
1544 const StringC &str = *sym->name();
1545 if (str == "first-of-type")
1546 qual = new Pattern::FirstOfTypeQualifier;
1547 else if (str == "last-of-type")
1548 qual = new Pattern::LastOfTypeQualifier;
1549 else if (str == "first-of-any")
1550 qual = new Pattern::FirstOfAnyQualifier;
1551 else if (str == "last-of-any")
1552 qual = new Pattern::LastOfAnyQualifier;
1554 curElement->addQualifier(qual);
1558 setNextLocation(loc);
1559 message(InterpreterMessages::patternBadQualifierValue,
1560 ELObjMessageArg(value, *this),
1561 StringMessageArg(key->identifier()->name()));
1564 case Identifier::keyOnly:
1566 SymbolObj *sym = value->asSymbol();
1568 Pattern::Qualifier *qual = 0;
1569 const StringC &str = *sym->name();
1570 if (str == "of-type")
1571 qual = new Pattern::OnlyOfTypeQualifier;
1572 else if (str == "of-any")
1573 qual = new Pattern::OnlyOfAnyQualifier;
1575 curElement->addQualifier(qual);
1579 setNextLocation(loc);
1580 message(InterpreterMessages::patternBadQualifierValue,
1581 ELObjMessageArg(value, *this),
1582 StringMessageArg(key->identifier()->name()));
1586 case Identifier::keyId:
1588 StringObj *str = value->convertToString();
1590 setNextLocation(loc);
1591 message(InterpreterMessages::patternBadQualifierValue,
1592 ELObjMessageArg(value, *this),
1593 StringMessageArg(key->identifier()->name()));
1598 str->stringData(s, n);
1599 curElement->addQualifier(new Pattern::IdQualifier(StringC(s, n)));
1602 case Identifier::keyClass:
1604 StringObj *str = value->convertToString();
1606 setNextLocation(loc);
1607 message(InterpreterMessages::patternBadQualifierValue,
1608 ELObjMessageArg(value, *this),
1609 StringMessageArg(key->identifier()->name()));
1614 str->stringData(s, n);
1615 curElement->addQualifier(new Pattern::ClassQualifier(StringC(s, n)));
1618 case Identifier::keyImportance:
1621 if (!value->exactIntegerValue(n)) {
1622 setNextLocation(loc);
1623 message(InterpreterMessages::patternBadQualifierValue,
1624 ELObjMessageArg(value, *this),
1625 StringMessageArg(key->identifier()->name()));
1628 curElement->addQualifier(new Pattern::ImportanceQualifier(n));
1631 case Identifier::keyPriority:
1634 if (!value->exactIntegerValue(n)) {
1635 setNextLocation(loc);
1636 message(InterpreterMessages::patternBadQualifierValue,
1637 ELObjMessageArg(value, *this),
1638 StringMessageArg(key->identifier()->name()));
1641 curElement->addQualifier(new Pattern::PriorityQualifier(n));
1645 setNextLocation(loc);
1646 message(InterpreterMessages::patternUnknownQualifier,
1647 StringMessageArg(key->identifier()->name()));
1654 bool Interpreter::patternAddAttributeQualifiers(ELObj *obj,
1655 const Location &loc,
1656 Pattern::Element &elem)
1658 while (!obj->isNil()) {
1659 PairObj *pair = obj->asPair();
1662 StringObj *tem = pair->car()->convertToString();
1667 tem->stringData(s, n);
1672 pair = obj->asPair();
1676 if (pair->car() == makeFalse() && dsssl2())
1677 elem.addQualifier(new Pattern::AttributeMissingValueQualifier(name));
1678 else if (pair->car() == makeTrue() && dsssl2())
1679 elem.addQualifier(new Pattern::AttributeHasValueQualifier(name));
1681 tem = pair->car()->convertToString();
1684 tem->stringData(s, n);
1685 elem.addQualifier(new Pattern::AttributeQualifier(name, StringC(s, n)));
1691 void Interpreter::dispatchMessage(Message &msg)
1693 messenger_->dispatchMessage(msg);
1696 void Interpreter::dispatchMessage(const Message &msg)
1698 messenger_->dispatchMessage(msg);
1701 Interpreter::StringSet::StringSet()
1705 const char *Interpreter::StringSet::store(String<char> &str)
1708 const String<char> *p = table_.lookup(str);
1710 String<char> *tem = new String<char>;
1718 unsigned long Interpreter::StringSet::hash(const String<char> &str)
1720 const char *p = str.data();
1721 unsigned long h = 0;
1722 for (size_t n = str.size(); n > 0; n--)
1723 h = (h << 5) + h + (unsigned char)*p++; // from Chris Torek
1727 bool Identifier::preferBuiltin_ = 0;
1729 Identifier::Identifier(const StringC &name)
1730 : Named(name), value_(0), syntacticKey_(notKey), beingComputed_(0),
1731 flowObj_(0), builtin_(0), defPart_(0), charNIC_(0)
1735 void Identifier::maybeSaveBuiltin()
1737 if (defPart_ == unsigned(-1) && !builtin_) {
1738 builtin_ = new Identifier(name());
1740 builtin_->setValue(value_, defPart_);
1742 builtin_->setDefinition(def_, defPart_, defLoc_);
1746 void Identifier::setDefinition(Owner<Expression> &expr,
1748 const Location &loc)
1757 void Identifier::setValue(ELObj *value, unsigned partIndex)
1761 // Built in functions have lowest priority.
1762 defPart_ = partIndex;
1765 bool Identifier::defined(unsigned &part, Location &loc) const
1767 if (!def_ && !value_)
1774 ELObj *Identifier::computeValue(bool force, Interpreter &interp) const
1776 if (builtin_ && preferBuiltin_)
1777 return builtin_->computeValue(force, interp);
1781 if (defPart_ == unsigned(-1) && !preferBuiltin_) {
1786 if (beingComputed_) {
1788 interp.setNextLocation(defLoc_);
1789 interp.message(InterpreterMessages::identifierLoop,
1790 StringMessageArg(name()));
1791 ((Identifier *)this)->value_ = interp.makeError();
1795 ((Identifier *)this)->beingComputed_ = 1;
1797 ((Identifier *)this)->insn_
1798 = Expression::optimizeCompile(((Identifier *)this)->def_, interp,
1799 Environment(), 0, InsnPtr());
1800 if (force || def_->canEval(0)) {
1802 ELObj *v = vm.eval(insn_.pointer());
1803 interp.makePermanent(v);
1804 ((Identifier *)this)->value_ = v;
1806 ((Identifier *)this)->beingComputed_ = 0;
1813 ELObj *Identifier::computeBuiltinValue(bool force, Interpreter &interp) const
1816 ELObj *res = computeValue(force, interp);
1821 Unit::Unit(const StringC &name)
1822 : Named(name), computed_(notComputed)
1826 bool Unit::defined(unsigned &part, Location &loc) const
1828 if (!def_ && computed_ == notComputed)
1835 void Unit::setDefinition(Owner<Expression> &expr,
1837 const Location &loc)
1842 computed_ = notComputed;
1845 void Unit::setValue(long n)
1847 computed_ = computedExact;
1850 defPart_ = unsigned(-1);
1853 void Unit::setValue(double n)
1855 computed_ = computedInexact;
1858 defPart_ = unsigned(-1);
1861 void Unit::tryCompute(bool force, Interpreter &interp)
1863 if (computed_ == notComputed) {
1864 computed_ = beingComputed;
1866 insn_ = Expression::optimizeCompile(def_, interp, Environment(), 0, InsnPtr());
1867 if (force || def_->canEval(0)) {
1869 ELObj *v = vm.eval(insn_.pointer());
1870 switch (v->quantityValue(exact_, inexact_, dim_)) {
1871 case ELObj::noQuantity:
1872 if (!interp.isError(v)) {
1873 interp.setNextLocation(defLoc_);
1874 interp.message(InterpreterMessages::badUnitDefinition,
1875 StringMessageArg(name()));
1877 computed_ = computedError;
1879 case ELObj::longQuantity:
1880 computed_ = computedExact;
1882 case ELObj::doubleQuantity:
1883 computed_ = computedInexact;
1889 if (computed_ == beingComputed)
1890 computed_ = notComputed;
1892 else if (computed_ == beingComputed) {
1893 interp.setNextLocation(defLoc_);
1894 interp.message(InterpreterMessages::unitLoop,
1895 StringMessageArg(name()));
1896 computed_ = computedError;
1900 // multiply by 10^valExp
1901 // quantity has exponent of 1
1903 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1904 long val, int valExp)
1906 tryCompute(force, interp);
1908 if (computed_ == computedExact && scale(val, valExp, exact_, result))
1909 return new (interp) LengthObj(result);
1911 while (valExp > 0) {
1915 while (valExp < 0) {
1919 return resolveQuantity(force, interp, x, 1);
1922 // val * 10^valExp * factor
1923 // return 0 if it can't be done without overflow
1925 bool Unit::scale(long val, int valExp, long factor, long &result)
1929 while (valExp > 0) {
1930 if (factor > LONG_MAX/10)
1936 if (val > LONG_MAX/factor)
1940 if (-(unsigned long)val > -(unsigned long)LONG_MIN/factor)
1943 result = val*factor;
1944 while (valExp < 0) {
1951 ELObj *Unit::resolveQuantity(bool force, Interpreter &interp,
1952 double val, int unitExp)
1954 tryCompute(force, interp);
1956 switch (computed_) {
1960 case computedInexact:
1964 return interp.makeError();
1969 double resultVal = val;
1970 while (unitExp > 0) {
1972 resultVal *= factor;
1975 while (unitExp < 0) {
1977 resultVal /= factor;
1981 return new (interp) RealObj(resultVal);
1982 return new (interp) QuantityObj(resultVal, resultDim);
1985 void ELObjDynamicRoot::trace(Collector &c) const
1990 bool operator==(const StringC &s, const char *p)
1992 for (size_t i = 0; i < s.size(); i++)
1993 if (p[i] == '\0' || (unsigned char)p[i] != s[i])
1995 return p[s.size()] == '\0';
1998 void Interpreter::installBuiltins()
2000 partIndex_ = unsigned(-1);
2001 StringC sysid(makeStringC(DEFAULT_SCHEME_BUILTINS));
2003 groveManager_->mapSysid(sysid);
2004 if (groveManager_->readEntity(sysid, src)) {
2005 Owner<InputSource> in(new InternalInputSource(src,
2006 InputSourceOrigin::make()));
2007 SchemeParser scm(*this, in);
2014 void Interpreter::setDefaultLanguage(Owner<Expression> &expr,
2016 const Location &loc)
2018 defaultLanguageDef_.swap(expr);
2019 defaultLanguageDefPart_ = part;
2020 defaultLanguageDefLoc_ = loc;
2023 ELObj *Interpreter::defaultLanguage() const
2025 return defaultLanguage_;
2028 bool Interpreter::defaultLanguageSet(unsigned &part,Location &loc) const
2030 if(defaultLanguageDef_) {
2031 part = defaultLanguageDefPart_;
2032 loc = defaultLanguageDefLoc_;
2038 void Interpreter::compileDefaultLanguage()
2040 if(defaultLanguageDef_) {
2041 InsnPtr insn = Expression::optimizeCompile(defaultLanguageDef_, *this,
2042 Environment(), 0, InsnPtr());
2044 ELObj *obj = vm.eval(insn.pointer());
2045 if(!obj->asLanguage()) {
2047 setNextLocation(defaultLanguageDefLoc_);
2048 message(InterpreterMessages::defLangDeclRequiresLanguage,
2049 ELObjMessageArg(obj, *this));
2054 defaultLanguage_ = obj;
2058 void Interpreter::installCharProperties()
2060 //FIXME convert this to tables
2061 // initialize charProperties_;
2062 // if a character doesn't have a value for a property,
2063 // the CharMap contains 0.
2067 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2068 cp.loc = Location();
2069 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2071 for (int i = 0; i < 10; i++) {
2072 ELObjPart num(makeInteger(i), unsigned(-1));
2073 makePermanent(num.obj);
2074 cp.map->setChar(i+'0', num);
2076 charProperties_.insert(makeStringC("numeric-equiv"), cp);
2078 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2079 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2086 #include "charProps.h"
2090 for (size_t i = 0; i < SIZEOF(chars); i++)
2091 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2092 ELObjPart(makeTrue(), unsigned(-1)));
2094 charProperties_.insert(makeStringC("space?"), cp);
2096 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2097 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2104 #include "charProps.h"
2108 for (size_t i = 0; i < SIZEOF(chars); i++)
2109 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2110 ELObjPart(makeTrue(), unsigned(-1)));
2112 charProperties_.insert(makeStringC("record-end?"), cp);
2114 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2115 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2122 #include "charProps.h"
2126 for (size_t i = 0; i < SIZEOF(chars); i++)
2127 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2128 ELObjPart(makeTrue(), unsigned(-1)));
2130 charProperties_.insert(makeStringC("blank?"), cp);
2132 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2133 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2140 #include "charProps.h"
2144 for (size_t i = 0; i < SIZEOF(chars); i++)
2145 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2146 ELObjPart(makeTrue(), unsigned(-1)));
2148 charProperties_.insert(makeStringC("input-tab?"), cp);
2150 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2151 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2157 #define INPUT_WHITESPACE
2158 #include "charProps.h"
2159 #undef INPUT_WHITESPACE
2162 for (size_t i = 0; i < SIZEOF(chars); i++)
2163 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2164 ELObjPart(makeTrue(), unsigned(-1)));
2166 charProperties_.insert(makeStringC("input-whitespace?"), cp);
2168 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2169 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2176 #include "charProps.h"
2180 for (size_t i = 0; i < SIZEOF(chars); i++)
2181 cp.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2182 ELObjPart(makeTrue(), unsigned(-1)));
2184 charProperties_.insert(makeStringC("punct?"), cp);
2186 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2187 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2194 #include "charProps.h"
2198 StringC prefix = makeStringC("ISO/IEC 10179::1996//Script::");
2199 for (size_t i = 0; i < SIZEOF(chars); i++) {
2200 StringC tem(prefix);
2201 tem += makeStringC(chars[i].script);
2202 StringObj *obj = new (*this) StringObj(tem);
2204 cp.map->setRange(chars[i].c1, chars[i].c2,
2205 ELObjPart(obj, unsigned(-1)));
2208 charProperties_.insert(makeStringC("script"), cp);
2210 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2211 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2212 charProperties_.insert(makeStringC("glyph-id"), cp);
2214 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2215 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2216 charProperties_.insert(makeStringC("drop-after-line-break?"), cp);
2218 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2219 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2220 charProperties_.insert(makeStringC("drop-unless-before-line-break?"), cp);
2222 cp.def = ELObjPart(makeInteger(0), unsigned(-1));
2223 makePermanent(cp.def.obj);
2224 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2226 cp2.def = ELObjPart(cp.def.obj, unsigned(-1));
2227 cp2.loc = Location();
2228 cp2.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2236 #define BREAK_PRIORITIES
2237 #include "charProps.h"
2238 #undef BREAK_PRIORITIES
2240 for(size_t i = 0; i<SIZEOF(chars); ++i) {
2241 ELObj *obj = makeInteger(chars[i].bbp);
2243 cp.map->setRange(chars[i].c, chars[i].c + chars[i].num-1,
2244 ELObjPart(obj, unsigned(-1)));
2245 if(chars[i].bap!=chars[i].bbp) {
2246 obj = makeInteger(chars[i].bap);
2249 cp2.map->setRange(chars[i].c, chars[i].c+chars[i].num-1,
2250 ELObjPart(obj, unsigned(-1)));
2254 charProperties_.insert(makeStringC("break-before-priority"), cp);
2255 charProperties_.insert(makeStringC("break-after-priority"), cp2);
2257 cp.def = ELObjPart(makeSymbol(makeStringC("ordinary")), unsigned(-1));
2258 makePermanent(cp.def.obj);
2259 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2260 charProperties_.insert(makeStringC("math-class"), cp);
2262 cp.def = ELObjPart(makeFalse(), unsigned(-1));
2263 cp.map = new CharMap<ELObjPart>(ELObjPart(0, 0));
2264 charProperties_.insert(makeStringC("math-font-posture"), cp);
2267 // return 1 if the character has the property, return 0 if no such property
2268 // or the character doesn't have the property
2269 // set ret to the value or the default value
2270 ELObj *Interpreter::charProperty(const StringC &prop, Char c, const Location &loc, ELObj *def)
2272 const CharProp *cp = charProperties_.lookup(prop);
2274 setNextLocation(loc);
2275 message(InterpreterMessages::unknownCharProperty,
2276 StringMessageArg(prop));
2280 if ((*cp->map)[c].obj)
2281 return (*cp->map)[c].obj;
2288 void Interpreter::addCharProperty(const Identifier *prop, Owner<Expression> &defval)
2290 // FIXME: what about variable default values ?
2291 defval->optimize(*this, Environment(), defval);
2292 if(!defval->constantValue()) {
2293 setNextLocation(defval->location());
2294 message(InterpreterMessages::varCharPropertyExprUnsupported);
2297 // FIXME: this is a kind of memory leak
2298 makePermanent(defval->constantValue());
2299 ELObjPart val(defval->constantValue(), partIndex_);
2300 const CharProp *cp = charProperties_.lookup(prop->name());
2302 if (partIndex_ < cp->def.defPart)
2303 ((CharProp *)cp)->def = val;
2304 else if (partIndex_ == cp->def.defPart &&
2305 !ELObj::eqv(*val.obj, *cp->def.obj)) {
2306 // FIXME: report previous location
2307 setNextLocation(defval->location());
2308 message(InterpreterMessages::duplicateCharPropertyDecl,
2309 StringMessageArg(prop->name()), cp->loc);
2314 ncp.map = new CharMap<ELObjPart>(ELObjPart(0,0));
2316 ncp.loc = defval->location();
2317 charProperties_.insert(prop->name(), ncp);
2321 void Interpreter::setCharProperty(const Identifier *prop, Char c, Owner<Expression> &val)
2323 // FIXME: what about variable default values ?
2324 val->optimize(*this, Environment(), val);
2325 if(!val->constantValue()) {
2326 setNextLocation(val->location());
2327 message(InterpreterMessages::varCharPropertyExprUnsupported);
2330 makePermanent(val->constantValue());
2331 const CharProp *cp = charProperties_.lookup(prop->name());
2334 ncp.map = new CharMap<ELObjPart>(ELObjPart(0,0));
2335 ncp.def = ELObjPart(0, unsigned(-1));
2336 ncp.loc = val->location();
2337 charProperties_.insert(prop->name(), ncp);
2338 cp = charProperties_.lookup(prop->name());
2340 ELObjPart obj = ELObjPart(val->constantValue(), partIndex_);
2342 ELObjPart def = (*cp->map)[c];
2344 if (partIndex_ < def.defPart)
2345 cp->map->setChar(c, obj);
2346 else if (partIndex_ == def.defPart && !ELObj::eqv(*obj.obj, *def.obj)) {
2347 setNextLocation(val->location());
2348 // FIXME: report previous location
2349 message(InterpreterMessages::duplicateAddCharProperty,
2350 StringMessageArg(prop->name()),
2351 StringMessageArg(StringC(&c, 1)));
2355 cp->map->setChar(c, obj);
2359 Interpreter::compileCharProperties()
2361 HashTableIter<StringC, CharProp> iter(charProperties_);
2363 const CharProp *val;
2364 while (iter.next(key, val))
2365 if (!val->def.obj) {
2367 setNextLocation(val->loc);
2368 message(InterpreterMessages::unknownCharProperty,
2369 StringMessageArg(*key));
2370 ((CharProp *)val)->def = ELObjPart(makeError(), 0);
2375 void Interpreter::installExtensionCharNIC(Identifier *ident,
2376 const StringC &pubid,
2377 const Location &loc)
2379 ident->setCharNIC(currentPartIndex(), loc);
2382 #ifdef DSSSL_NAMESPACE